From 23f5178d88e4975e99d859afd71077ce96f506d9 Mon Sep 17 00:00:00 2001 From: Martin Date: Fri, 1 Mar 2024 17:44:35 +0100 Subject: [PATCH 01/15] changes added for feature/97-MatchmakingAgentApi --- .github/workflows/build.yml | 40 + .github/workflows/helm-chart-lint.yml | 11 + .github/workflows/trivy.yml | 1 + .github/workflows/veracode.yml | 3 +- charts/README.md | 1 + charts/matchmaking-agent/.helmignore | 45 ++ charts/matchmaking-agent/Chart.yaml | 34 + charts/matchmaking-agent/LICENSE | 202 +++++ charts/matchmaking-agent/README.md | 120 +++ charts/matchmaking-agent/README.md.gotmpl | 44 ++ charts/matchmaking-agent/templates/NOTES.txt | 65 ++ .../matchmaking-agent/templates/_helpers.tpl | 88 +++ .../templates/configmap-env.yaml | 26 + .../templates/configmap.yaml | 32 + .../templates/deployment.yaml | 166 +++++ charts/matchmaking-agent/templates/hpa.yaml | 46 ++ .../matchmaking-agent/templates/ingress.yaml | 95 +++ .../matchmaking-agent/templates/service.yaml | 33 + .../templates/serviceaccount.yaml | 34 + charts/matchmaking-agent/values.yaml | 247 +++++++ matchmaking/README.md | 148 +++- .../docs/MatchmakingAgentDiagram.drawio.svg | 4 + matchmaking/pom.xml | 428 +++++++++++ matchmaking/resources/dataplane.properties | 82 +++ .../agents/conforming/api/AgentApi.java | 147 ++++ .../agents/conforming/api/ApiException.java | 27 + .../conforming/api/ApiOriginFilter.java | 46 ++ .../agents/conforming/api/JsonProvider.java | 58 ++ .../conforming/api/NotFoundException.java | 27 + .../conforming/api/Rfc3339DateFormat.java | 35 + .../agents/conforming/api/SparqlProvider.java | 64 ++ .../agents/conforming/api/StringUtil.java | 58 ++ .../agents/conforming/api/XmlProvider.java | 85 +++ .../agents/conforming/model/CxWarning.java | 214 ++++++ .../conforming/model/JsonResultset.java | 117 +++ .../conforming/model/JsonResultsetHead.java | 99 +++ .../model/JsonResultsetResults.java | 99 +++ .../agents/conforming/model/XmlResultset.java | 117 +++ .../conforming/model/XmlResultsetHead.java | 84 +++ .../model/XmlResultsetHeadVariable.java | 89 +++ .../conforming/model/XmlResultsetResults.java | 84 +++ .../model/XmlResultsetResultsResult.java | 84 +++ .../XmlResultsetResultsResultBinding.java | 139 ++++ ...lResultsetResultsResultBindingLiteral.java | 142 ++++ matchmaking/src/main/docker/Dockerfile | 52 ++ .../agents/conforming/BindingAgent.java | 66 ++ .../conforming/BindingProfileChecker.java | 38 + .../tractusx/agents/conforming/Bootstrap.java | 173 +++++ .../agents/conforming/ConformingAgent.java | 295 ++++++++ .../agents/conforming/MatchmakingAgent.java | 57 ++ .../conforming/SharedObjectManager.java | 199 +++++ .../agents/conforming/TransferAgent.java | 109 +++ .../tractusx/agents/edc/AgentConfig.java | 405 ++++++++++ .../tractusx/agents/edc/AgentExtension.java | 195 +++++ .../tractusx/agents/edc/AgentProtocol.java | 36 + .../agents/edc/AgreementController.java | 44 ++ .../agents/edc/AgreementControllerImpl.java | 437 +++++++++++ .../tractusx/agents/edc/MonitorWrapper.java | 106 +++ .../agents/edc/SkillDistribution.java | 73 ++ .../tractusx/agents/edc/SkillStore.java | 76 ++ .../eclipse/tractusx/agents/edc/Tuple.java | 108 +++ .../eclipse/tractusx/agents/edc/TupleSet.java | 138 ++++ .../agents/edc/http/AgentController.java | 487 ++++++++++++ .../agents/edc/http/AgentHttpAction.java | 170 +++++ .../agents/edc/http/DelegationResponse.java | 73 ++ .../agents/edc/http/DelegationService.java | 43 ++ .../edc/http/DelegationServiceImpl.java | 367 ++++++++++ .../agents/edc/http/GraphController.java | 158 ++++ .../agents/edc/http/HttpClientAdapter.java | 177 +++++ .../agents/edc/http/HttpClientFactory.java | 134 ++++ .../agents/edc/http/HttpResponseAdapter.java | 89 +++ .../edc/http/HttpServletContextAdapter.java | 347 +++++++++ .../edc/http/HttpServletRequestAdapter.java | 433 +++++++++++ .../edc/http/HttpServletResponseAdapter.java | 238 ++++++ .../tractusx/agents/edc/http/HttpUtils.java | 160 ++++ .../agents/edc/http/JakartaAdapter.java | 92 +++ .../agents/edc/http/JakartaAdapterImpl.java | 62 ++ .../JakartaServletInputStreamAdapter.java | 80 ++ .../JakartaServletOutputStreamAdapter.java | 75 ++ .../edc/http/ServletInputStreamDelegator.java | 88 +++ .../http/ServletOutputStreamDelegator.java | 59 ++ .../http/transfer/AgentSourceController.java | 149 ++++ .../AgentSourceHttpParamsDecorator.java | 230 ++++++ .../AgentSourceRequestParamsSupplier.java | 98 +++ .../edc/http/transfer/AgentSourceServlet.java | 140 ++++ .../tractusx/agents/edc/jsonld/JsonLd.java | 146 ++++ .../agents/edc/jsonld/JsonLdObject.java | 43 ++ .../tractusx/agents/edc/model/Asset.java | 47 ++ .../agents/edc/model/ContractAgreement.java | 35 + .../agents/edc/model/ContractNegotiation.java | 42 ++ .../edc/model/ContractNegotiationRequest.java | 103 +++ .../edc/model/ContractOfferDescription.java | 43 ++ .../agents/edc/model/DcatCatalog.java | 54 ++ .../agents/edc/model/DcatDataset.java | 62 ++ .../tractusx/agents/edc/model/IdResponse.java | 31 + .../tractusx/agents/edc/model/OdrlPolicy.java | 31 + .../agents/edc/model/TransferProcess.java | 31 + .../agents/edc/model/TransferRequest.java | 175 +++++ .../agents/edc/rdf/ExternalFormat.java | 66 ++ .../tractusx/agents/edc/rdf/RdfStore.java | 270 +++++++ .../agents/edc/service/DataManagement.java | 156 ++++ .../edc/service/DataManagementImpl.java | 683 +++++++++++++++++ .../edc/service/DataspaceSynchronizer.java | 337 +++++++++ .../agents/edc/service/EdcSkillStore.java | 114 +++ .../edc/service/InMemorySkillStore.java | 64 ++ .../agents/edc/sparql/CatenaxWarning.java | 247 +++++++ .../edc/sparql/DataspaceServiceExecutor.java | 652 ++++++++++++++++ .../agents/edc/sparql/GraphRewrite.java | 125 ++++ .../edc/sparql/GraphRewriteVisitor.java | 33 + ...ervletRequestToOkHttpRequestConverter.java | 94 +++ .../edc/sparql/OptimizeJoinStrategy.java | 64 ++ .../tractusx/agents/edc/sparql/Optimizer.java | 48 ++ .../agents/edc/sparql/OptimizerFactory.java | 31 + .../agents/edc/sparql/QueryExecutor.java | 693 ++++++++++++++++++ .../edc/sparql/QueryExecutorBuilder.java | 93 +++ .../agents/edc/sparql/QueryIterFutures.java | 177 +++++ .../agents/edc/sparql/QueryIterJoin.java | 100 +++ .../edc/sparql/SkillVariableDetector.java | 68 ++ .../edc/sparql/SparqlQueryProcessor.java | 498 +++++++++++++ .../edc/sparql/SparqlQuerySerializer.java | 415 +++++++++++ .../sparql/SparqlQuerySerializerFactory.java | 53 ++ .../sparql/StratifiedFormatterElement.java | 120 +++ .../agents/edc/sparql/VariableDetector.java | 63 ++ .../DataPlaneTokenValidationApi.java | 26 + ...hingDataPlaneTokenValidatorController.java | 98 +++ .../conforming/ConformingAgentTest.java | 158 ++++ .../conforming/MatchmakingAgentTest.java | 94 +++ .../agents/conforming/TransferAgentTest.java | 48 ++ pom.xml | 6 + 129 files changed, 16880 insertions(+), 23 deletions(-) create mode 100644 charts/matchmaking-agent/.helmignore create mode 100644 charts/matchmaking-agent/Chart.yaml create mode 100644 charts/matchmaking-agent/LICENSE create mode 100644 charts/matchmaking-agent/README.md create mode 100644 charts/matchmaking-agent/README.md.gotmpl create mode 100644 charts/matchmaking-agent/templates/NOTES.txt create mode 100644 charts/matchmaking-agent/templates/_helpers.tpl create mode 100644 charts/matchmaking-agent/templates/configmap-env.yaml create mode 100644 charts/matchmaking-agent/templates/configmap.yaml create mode 100644 charts/matchmaking-agent/templates/deployment.yaml create mode 100644 charts/matchmaking-agent/templates/hpa.yaml create mode 100644 charts/matchmaking-agent/templates/ingress.yaml create mode 100644 charts/matchmaking-agent/templates/service.yaml create mode 100644 charts/matchmaking-agent/templates/serviceaccount.yaml create mode 100644 charts/matchmaking-agent/values.yaml create mode 100644 matchmaking/docs/MatchmakingAgentDiagram.drawio.svg create mode 100644 matchmaking/pom.xml create mode 100644 matchmaking/resources/dataplane.properties create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/AgentApi.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/ApiException.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/ApiOriginFilter.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/JsonProvider.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/NotFoundException.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/Rfc3339DateFormat.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/SparqlProvider.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/StringUtil.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/XmlProvider.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/CxWarning.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultset.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultsetHead.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultsetResults.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultset.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetHead.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetHeadVariable.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResults.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResult.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResultBinding.java create mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResultBindingLiteral.java create mode 100644 matchmaking/src/main/docker/Dockerfile create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/BindingAgent.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/BindingProfileChecker.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/Bootstrap.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/ConformingAgent.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/MatchmakingAgent.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/SharedObjectManager.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/TransferAgent.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentConfig.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentExtension.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentProtocol.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgreementController.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgreementControllerImpl.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/MonitorWrapper.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/SkillDistribution.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/SkillStore.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/Tuple.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/TupleSet.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentController.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentHttpAction.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationResponse.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationService.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationServiceImpl.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/GraphController.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientAdapter.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientFactory.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpResponseAdapter.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletContextAdapter.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletRequestAdapter.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletResponseAdapter.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpUtils.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapter.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapterImpl.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletInputStreamAdapter.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletOutputStreamAdapter.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletInputStreamDelegator.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletOutputStreamDelegator.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceController.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceHttpParamsDecorator.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceRequestParamsSupplier.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceServlet.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLd.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLdObject.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/Asset.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractAgreement.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiation.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiationRequest.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractOfferDescription.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatCatalog.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatDataset.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/IdResponse.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/OdrlPolicy.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/TransferProcess.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/TransferRequest.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/rdf/ExternalFormat.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/rdf/RdfStore.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagementImpl.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataspaceSynchronizer.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/EdcSkillStore.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/InMemorySkillStore.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/CatenaxWarning.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/DataspaceServiceExecutor.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewrite.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewriteVisitor.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/HttpServletRequestToOkHttpRequestConverter.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/OptimizeJoinStrategy.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/Optimizer.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/OptimizerFactory.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutor.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutorBuilder.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterFutures.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterJoin.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SkillVariableDetector.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQueryProcessor.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializer.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializerFactory.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/StratifiedFormatterElement.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/VariableDetector.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/validation/DataPlaneTokenValidationApi.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/validation/SwitchingDataPlaneTokenValidatorController.java create mode 100644 matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/ConformingAgentTest.java create mode 100644 matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/MatchmakingAgentTest.java create mode 100644 matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/TransferAgentTest.java diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 31a2e7ea..5a614997 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -238,3 +238,43 @@ jobs: username: ${{ secrets.DOCKER_HUB_USER || github.actor }} password: ${{ secrets.DOCKER_HUB_TOKEN || secrets.GITHUB_TOKEN }} repository: ${{ steps.set-docker-repo.outputs.REPO }}/provisioning-agent + + # build in any case, but push only main and version tag settings + - name: Matchmaking Container Build and Push + uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 + with: + context: matchmaking/. + file: matchmaking/src/main/docker/Dockerfile + # Build image for verification purposes on every trigger event. Only push if event is not a PR + push: ${{ ( github.event.inputs.deploy_docker == 'true' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') ) }} + tags: ${{ steps.meta-remote.outputs.tags }} + labels: ${{ steps.meta-remote.outputs.labels }} + + # Important step to push image description to DockerHub - since this is version independent, we always take it from main + - name: Update Docker Hub description for Matchmaking Agent + if: ${{ steps.set-docker-repo.outputs.REPO == 'docker.io' && github.ref == 'refs/heads/main' }} + uses: peter-evans/dockerhub-description@dc67fad7001ef9e8e3c124cb7a64e16d0a63d864 # v3.4.2 + with: + readme-filepath: matchmaking/README.md + username: ${{ secrets.DOCKER_HUB_USER || github.actor }} + password: ${{ secrets.DOCKER_HUB_TOKEN || secrets.GITHUB_TOKEN }} + repository: ${{ steps.set-docker-repo.outputs.REPO }}/matchmaking-agent + + # Create SemVer or ref tags dependent of trigger event + - name: Docker Meta Matchmaking + id: meta-match + uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0 + with: + images: | + ${{ steps.set-docker-repo.outputs.REPO }}/provisioning-agent + # Automatically prepare image tags; See action docs for more examples. + # semver patter will generate tags like these for example :1 :1.2 :1.2.3 + tags: | + type=sha,event=branch + type=sha,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=1.10.15-SNAPSHOT,enable=${{ github.event.inputs.deploy_docker == 'true' || github.ref == format('refs/heads/{0}', 'main') }} + type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }} + diff --git a/.github/workflows/helm-chart-lint.yml b/.github/workflows/helm-chart-lint.yml index de844851..1cfae4e3 100644 --- a/.github/workflows/helm-chart-lint.yml +++ b/.github/workflows/helm-chart-lint.yml @@ -136,3 +136,14 @@ jobs: helm dependency update charts/remoting-agent helm upgrade remoting charts/remoting-agent if: (github.event_name != 'pull_request' || env.CHART_CHANGED == 'true') && github.event.inputs.upgrade_from != '' && github.event.inputs.upgrade_from != 'x.x.x' + + # Upgrade the released chart version with the locally available chart + # default value for event_name != workflow_dispatch + - name: Run helm upgrade on matchmaking agent + run: | + helm repo add tractusx-dev https://eclipse-tractusx.github.io/charts/dev + helm install matchmaking tractusx-dev/matchmaking-agent --version ${{ github.event.inputs.upgrade_from }} --set=image.registry=kind-registry:5000/ + helm dependency update charts/matchmaking-agent + helm upgrade remoting charts/matchmaking-agent + if: (github.event_name != 'pull_request' || env.CHART_CHANGED == 'true') && github.event.inputs.upgrade_from != '' && github.event.inputs.upgrade_from != 'x.x.x' + diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml index 420a8a40..aadb2187 100644 --- a/.github/workflows/trivy.yml +++ b/.github/workflows/trivy.yml @@ -85,6 +85,7 @@ jobs: - provisioning-agent - remoting-agent - conforming-agent + - matchmaking-agent steps: # Determine the right target docker repo diff --git a/.github/workflows/veracode.yml b/.github/workflows/veracode.yml index 84ab1c10..8598258c 100644 --- a/.github/workflows/veracode.yml +++ b/.github/workflows/veracode.yml @@ -61,7 +61,8 @@ jobs: fail-fast: false matrix: variant: [{dir: remoting, name: remoting-agent}, - {dir: conforming, name: conforming-agent}] + {dir: conforming, name: conforming-agent}, + {dir: matchmaking, name: matchmaking-agent}] steps: # Set-Up - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 diff --git a/charts/README.md b/charts/README.md index 46ace907..834b9561 100644 --- a/charts/README.md +++ b/charts/README.md @@ -27,6 +27,7 @@ This folder contains ready-made charts for the following optional features/refer - [Conforming Agent](conforming-agent) - [Provisioning Agent](provisioning-agent) - [Remoting Agent](remoting-agent) +- [Matchmaking Agent](matchmaking-agent) ## Chart Linting diff --git a/charts/matchmaking-agent/.helmignore b/charts/matchmaking-agent/.helmignore new file mode 100644 index 00000000..9a12504f --- /dev/null +++ b/charts/matchmaking-agent/.helmignore @@ -0,0 +1,45 @@ +# Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ +# Doc Templates +README.md.gotmpl +# Accept only values.yaml +values?*.yaml +values?*.yml \ No newline at end of file diff --git a/charts/matchmaking-agent/Chart.yaml b/charts/matchmaking-agent/Chart.yaml new file mode 100644 index 00000000..1c192caa --- /dev/null +++ b/charts/matchmaking-agent/Chart.yaml @@ -0,0 +1,34 @@ +--- +# Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Matchmaking Agent Chat Header +# This is a YAML-formatted file. +apiVersion: v2 +name: matchmaking-agent +description: | + A Helm chart for the Tractus-X Matchmaking Agent which is a container encompassing data storage capabilities accessible from the dataplane by a REST API + + This chart has no prerequisites. +home: https://github.com/eclipse-tractusx/knowledge-agents/ +sources: + - https://github.com/eclipse-tractusx/knowledge-agents/tree/main/matchmaking +type: application +appVersion: "1.10.15-SNAPSHOT" +version: 1.10.15-SNAPSHOT +maintainers: + - name: 'Tractus-X Knowledge Agents Team' diff --git a/charts/matchmaking-agent/LICENSE b/charts/matchmaking-agent/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/charts/matchmaking-agent/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) 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. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/charts/matchmaking-agent/README.md b/charts/matchmaking-agent/README.md new file mode 100644 index 00000000..3198024d --- /dev/null +++ b/charts/matchmaking-agent/README.md @@ -0,0 +1,120 @@ + +# matchmaking-agent + +![Version: 1.10.15-SNAPSHOT](https://img.shields.io/badge/Version-1.10.2--SNAPSHOT-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.10.15-SNAPSHOT](https://img.shields.io/badge/AppVersion-1.10.2--SNAPSHOT-informational?style=flat-square) + +A Helm chart for the Tractus-X Matchmaking Agent which is a container to Bridge Agent-Enabled Connector and REST APIs. + +This chart has no prerequisites. + +**Homepage:** + +## TL;DR +```shell +$ helm repo add eclipse-tractusx https://eclipse-tractusx.github.io/charts/dev +$ helm install my-release eclipse-tractusx/matchmaking-agent --version 1.10.15-SNAPSHOT +``` + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| Tractus-X Knowledge Agents Team | | | + +## Source Code + +* + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | [Affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) constrains which nodes the Pod can be scheduled on based on node labels. | +| agent.endpoints.default.auth | object | `{}` | An auth object for default security | +| agent.endpoints.default.path | string | `""` | The path mapping the "default" api is going to be exposed by | +| agent.endpoints.default.port | string | `"8081"` | The network port, which the "default" api is going to be exposed by the container, pod and service | +| agent.endpoints.default.regex | string | `"/(.*)"` | An optional regex path match (whose match groups could be used in an nginx-annotation of the ingress) | +| automountServiceAccountToken | bool | `false` | Whether to [automount kubernetes API credentials](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server) into the pod | +| autoscaling.enabled | bool | `false` | Enables [horizontal pod autoscaling](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) | +| autoscaling.maxReplicas | int | `100` | Maximum replicas if resource consumption exceeds resource threshholds | +| autoscaling.minReplicas | int | `1` | Minimal replicas if resource consumption falls below resource threshholds | +| autoscaling.targetCPUUtilizationPercentage | int | `80` | targetAverageUtilization of cpu provided to a pod | +| autoscaling.targetMemoryUtilizationPercentage | int | `80` | targetAverageUtilization of memory provided to a pod | +| customLabels | object | `{}` | Additional custom Labels to add | +| env | object | `{}` | Container environment variables e.g. for configuring [JAVA_TOOL_OPTIONS](https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/envvars002.html) Ex.: JAVA_TOOL_OPTIONS: > -Dhttp.proxyHost=proxy -Dhttp.proxyPort=80 -Dhttp.nonProxyHosts="localhost|127.*|[::1]" -Dhttps.proxyHost=proxy -Dhttps.proxyPort=443 | +| envSecretName | string | `nil` | [Kubernetes Secret Resource](https://kubernetes.io/docs/concepts/configuration/secret/) name to load environment variables from | +| fullnameOverride | string | `""` | Overrides the releases full name | +| image.digest | string | `""` | Overrides the image digest | +| image.pullPolicy | string | `"IfNotPresent"` | | +| image.pullSecrets | list | `[]` | | +| image.registry | string | `"docker.io/"` | target registry | +| image.repository | string | `"tractusx/matchmaking-agent"` | Which derivate of agent to use | +| image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion | +| ingresses[0].annotations | string | `nil` | Additional ingress annotations to add, for example when implementing more complex routings you may set { nginx.ingress.kubernetes.io/rewrite-target: /$1, nginx.ingress.kubernetes.io/use-regex: "true" } | +| ingresses[0].certManager.clusterIssuer | string | `""` | If preset enables certificate generation via cert-manager cluster-wide issuer | +| ingresses[0].certManager.issuer | string | `""` | If preset enables certificate generation via cert-manager namespace scoped issuer | +| ingresses[0].className | string | `""` | Defines the [ingress class](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class) to use | +| ingresses[0].enabled | bool | `false` | | +| ingresses[0].endpoints | list | `["default"]` | Agent endpoints exposed by this ingress resource | +| ingresses[0].hostname | string | `"matchmaking-agent.local"` | The hostname to be used to precisely map incoming traffic onto the underlying network service | +| ingresses[0].prefix | string | `""` | Optional prefix that will be prepended to the paths of the endpoints | +| ingresses[0].tls | object | `{"enabled":false,"secretName":""}` | TLS [tls class](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls) applied to the ingress resource | +| ingresses[0].tls.enabled | bool | `false` | Enables TLS on the ingress resource | +| ingresses[0].tls.secretName | string | `""` | If present overwrites the default secret name | +| livenessProbe.enabled | bool | `true` | Whether to enable kubernetes [liveness-probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) | +| livenessProbe.failureThreshold | int | `3` | Minimum consecutive failures for the probe to be considered failed after having succeeded | +| livenessProbe.periodSeconds | int | `60` | Number of seconds each period lasts. | +| livenessProbe.timeoutSeconds | int | `5` | number of seconds until a timeout is assumed | +| logging.configuration | string | `"\n\n \n \n %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n\n \n \n \n \n \n \n"` | Logback Xml | +| nameOverride | string | `""` | Overrides the charts name | +| nodeSelector | object | `{}` | [Node-Selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) to constrain the Pod to nodes with specific labels. | +| podAnnotations | object | `{}` | [Annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) added to deployed [pods](https://kubernetes.io/docs/concepts/workloads/pods/) | +| podSecurityContext.fsGroup | int | `30000` | The owner for volumes and any files created within volumes will belong to this guid | +| podSecurityContext.runAsGroup | int | `30000` | Processes within a pod will belong to this guid | +| podSecurityContext.runAsUser | int | `10001` | Runs all processes within a pod with a special uid | +| podSecurityContext.seccompProfile.type | string | `"RuntimeDefault"` | Restrict a Container's Syscalls with seccomp | +| readinessProbe.enabled | bool | `true` | Whether to enable kubernetes readiness-probes | +| readinessProbe.failureThreshold | int | `3` | Minimum consecutive failures for the probe to be considered failed after having succeeded | +| readinessProbe.periodSeconds | int | `300` | Number of seconds each period lasts. | +| readinessProbe.timeoutSeconds | int | `5` | number of seconds until a timeout is assumed | +| replicaCount | int | `1` | Specifies how many replicas of a deployed pod shall be created during the deployment Note: If horizontal pod autoscaling is enabled this setting has no effect | +| repositories | object | `{}` | A map of repository names to configuration ttl files | +| resources | object | `{"limits":{"cpu":"250m","memory":"768Mi"},"requests":{"cpu":"250m","memory":"768Mi"}}` | [Resource management](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) applied to the deployed pod We recommend 25% of a cpu, 512MB per server and 256MB per endpoint | +| securityContext.allowPrivilegeEscalation | bool | `false` | Controls [Privilege Escalation](https://kubernetes.io/docs/concepts/security/pod-security-policy/#privilege-escalation) enabling setuid binaries changing the effective user ID | +| securityContext.capabilities.add | list | `["NET_BIND_SERVICE"]` | Specifies which capabilities to add to issue specialized syscalls | +| securityContext.capabilities.drop | list | `["ALL"]` | Specifies which capabilities to drop to reduce syscall attack surface | +| securityContext.readOnlyRootFilesystem | bool | `true` | Whether the root filesystem is mounted in read-only mode | +| securityContext.runAsGroup | int | `30000` | Processes within a pod will belong to this guid | +| securityContext.runAsNonRoot | bool | `true` | Requires the container to run without root privileges | +| securityContext.runAsUser | int | `10001` | The container's process will run with the specified uid | +| service.type | string | `"ClusterIP"` | [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) to expose the running application on a set of Pods as a network service. | +| serviceAccount.annotations | object | `{}` | [Annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) to add to the service account | +| serviceAccount.create | bool | `true` | Specifies whether a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) should be created per release | +| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the release's fullname template | +| startupProbe.enabled | bool | `true` | Whether to enable kubernetes startup-probes | +| startupProbe.failureThreshold | int | `18` | Minimum consecutive failures for the probe to be considered failed after having succeeded | +| startupProbe.initialDelaySeconds | int | `60` | Number of seconds after the container has started before liveness probes are initiated. | +| startupProbe.periodSeconds | int | `30` | Number of seconds each period lasts. | +| startupProbe.timeoutSeconds | int | `5` | number of seconds until a timeout is assumed | +| tolerations | list | `[]` | [Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) are applied to Pods to schedule onto nodes with matching taints. | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/charts/matchmaking-agent/README.md.gotmpl b/charts/matchmaking-agent/README.md.gotmpl new file mode 100644 index 00000000..585e8fb7 --- /dev/null +++ b/charts/matchmaking-agent/README.md.gotmpl @@ -0,0 +1,44 @@ + +{{ template "chart.header" . }} + +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.badgesSection" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +## TL;DR +```shell +$ helm repo add eclipse-tractusx https://eclipse-tractusx.github.io/charts/dev +$ helm install my-release eclipse-tractusx/matchmaking-agent --version {{ .Version }} +``` + +{{ template "chart.maintainersSection" . }} + +{{ template "chart.sourcesSection" . }} + +{{ template "chart.requirementsSection" . }} + +{{ template "chart.valuesSection" . }} + +{{ template "helm-docs.versionFooter" . }} diff --git a/charts/matchmaking-agent/templates/NOTES.txt b/charts/matchmaking-agent/templates/NOTES.txt new file mode 100644 index 00000000..41d26814 --- /dev/null +++ b/charts/matchmaking-agent/templates/NOTES.txt @@ -0,0 +1,65 @@ +# Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +CHART NAME: {{ .Chart.Name }} +CHART VERSION: {{ .Chart.Version }} +APP VERSION: {{ .Chart.AppVersion }} + +Logs can be accessed by running this command: + + kubectl logs --tail 100 -f \ + --namespace {{ .Release.Namespace }} \ + -l "app.kubernetes.io/name={{ include "agent.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" + +{{- if .Values.ingresses }} + +Following ingress URLS are available: + {{- $endpoints := .Values.agent.endpoints }} + {{- range $ingress := .Values.ingresses }} + {{- if .enabled }} + {{- $ingressEndpoints := .endpoints }} + {{- $hostname := .hostname }} + {{- $tls := .tls }} + {{- range $name, $mapping := $endpoints }} + {{- if (has $name $ingressEndpoints) }} + Visit http{{ if $tls }}s{{ end }}://{{ $hostname }}{{default $ingress.prefix ""}}{{ $mapping.path }} to access the {{ $name }} api + {{- end }} + {{- end }} + {{- end }} + {{- end }} + +{{- else if contains "NodePort" .Values.service.type }} +Get the application URLs by running these commands: + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + + export NODE_PORT_DEFAULT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "agent.fullname" . }}}") + + echo "Visit http://$NODE_IP:$NODE_PORT_DEFAULT to access the default api" + +{{- else if contains "ClusterIP" .Values.service.type }} +Get the application URL by running these commands: + + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "agent.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + + export CONTAINER_PORT_DEFAULT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + + echo "Visit http://127.0.0.1:8080 to access the default api" + + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME \ + 8080:$CONTAINER_PORT_DEFAULT + +{{- end }} diff --git a/charts/matchmaking-agent/templates/_helpers.tpl b/charts/matchmaking-agent/templates/_helpers.tpl new file mode 100644 index 00000000..50de48fa --- /dev/null +++ b/charts/matchmaking-agent/templates/_helpers.tpl @@ -0,0 +1,88 @@ +# Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +{{/* +Expand the name of the chart. +*/}} +{{- define "agent.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "agent.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "agent.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "agent.labels" -}} +helm.sh/chart: {{ include "agent.chart" . }} +{{ include "agent.selectorLabels" . }} +{{ include "agent.customLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "agent.selectorLabels" -}} +app.kubernetes.io/name: {{ include "agent.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Custom labels +*/}} +{{- define "agent.customLabels" -}} +{{- with .Values.customLabels }} +{{ toYaml . }} +{{- end }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "agent.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "agent.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/matchmaking-agent/templates/configmap-env.yaml b/charts/matchmaking-agent/templates/configmap-env.yaml new file mode 100644 index 00000000..51008dd2 --- /dev/null +++ b/charts/matchmaking-agent/templates/configmap-env.yaml @@ -0,0 +1,26 @@ +--- +# Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "agent.fullname" . }}-env + namespace: {{ .Release.Namespace | default "default" | quote }} + labels: + {{- include "agent.labels" . | nindent 4 }} +data: + {{- toYaml .Values.env | nindent 2 }} diff --git a/charts/matchmaking-agent/templates/configmap.yaml b/charts/matchmaking-agent/templates/configmap.yaml new file mode 100644 index 00000000..72b9110f --- /dev/null +++ b/charts/matchmaking-agent/templates/configmap.yaml @@ -0,0 +1,32 @@ +--- +# Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "agent.fullname" . }}-configmap + namespace: {{ .Release.Namespace | default "default" | quote }} + labels: + {{- include "agent.labels" . | nindent 4 }} +data: + logback.xml: |- + {{- .Values.logging.configuration | nindent 4 }} + {{ $scope := . }} + {{- range $asset, $content := .Values.repositories }} + {{ $asset }}.ttl: {{ $content | toYaml | indent 2 }} + {{- end }} + diff --git a/charts/matchmaking-agent/templates/deployment.yaml b/charts/matchmaking-agent/templates/deployment.yaml new file mode 100644 index 00000000..26323483 --- /dev/null +++ b/charts/matchmaking-agent/templates/deployment.yaml @@ -0,0 +1,166 @@ +--- +# Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "agent.fullname" . }} + namespace: {{ .Release.Namespace | default "default" | quote }} + labels: + {{- include "agent.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "agent.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + checksum/env-config: {{ include (print $.Template.BasePath "/configmap-env.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "agent.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.image.pullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "agent.serviceAccountName" . }} + automountServiceAccountToken: {{ if .Values.automountServiceAccountToken }}true{{ else }}false{{ end }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.registry }}{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: default + containerPort: {{ .Values.agent.endpoints.default.port }} + protocol: TCP + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: {{ .Values.agent.endpoints.default.path }}/rdf4j-server/protocol + port: default + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: {{ .Values.agent.endpoints.default.path }}/rdf4j-server/protocol + port: default + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + {{- end }} + {{- if .Values.startupProbe.enabled }} + startupProbe: + httpGet: + path: {{ .Values.agent.endpoints.default.path }}/rdf4j-server/protocol + port: default + failureThreshold: {{ .Values.startupProbe.failureThreshold }} + periodSeconds: {{ .Values.startupProbe.periodSeconds }} + timeoutSeconds: {{ .Values.startupProbe.timeoutSeconds }} + initialDelaySeconds: {{ .Values.startupProbe.initialDelaySeconds }} + {{- end }} + envFrom: + - configMapRef: + name: {{ include "agent.fullname" . }}-env + {{- if .Values.envSecretName }} + - secretRef: + name: {{ .Values.envSecretName | quote }} + {{- end }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: configuration + mountPath: /var/rdf4j/server/conf/logback.xml + subPath: logback.xml + readOnly: true + - name: logs + mountPath: /usr/local/tomcat/logs + readOnly: false + - name: work + mountPath: /usr/local/tomcat/work/Catalina/localhost + readOnly: false + - name: conf + mountPath: /usr/local/tomcat/conf/Catalina/localhost + readOnly: false + - name: tmp + mountPath: /usr/local/tomcat/temp + readOnly: false + - name: rdf4jlogs + mountPath: /var/rdf4j/server/logs + readOnly: false + - name: rdf4jconf + mountPath: /var/rdf4j/server/conf + readOnly: false + - name: rdf4jrepositories + mountPath: /var/rdf4j/server/repositories + readOnly: false + {{- range $asset, $_ := .Values.repositories }} + - name: configuration + mountPath: /var/rdf4j/server/repositories/{{ $asset }}/config.ttl + subPath: {{ $asset }}.ttl + readOnly: true + {{- end }} + volumes: + - name: configuration + configMap: + name: {{ include "agent.fullname" . }}-configmap + items: + - key: logback.xml + path: logback.xml + {{- range $asset, $_ := .Values.repositories }} + - key: {{ $asset }}.ttl + path: {{ $asset }}.ttl + {{- end }} + - name: tmp + emptyDir: {} + - name: logs + emptyDir: {} + - name: work + emptyDir: {} + - name: conf + emptyDir: {} + - name: rdf4jconf + emptyDir: {} + - name: rdf4jlogs + emptyDir: {} + - name: rdf4jrepositories + emptyDir: {} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/matchmaking-agent/templates/hpa.yaml b/charts/matchmaking-agent/templates/hpa.yaml new file mode 100644 index 00000000..4e2babfa --- /dev/null +++ b/charts/matchmaking-agent/templates/hpa.yaml @@ -0,0 +1,46 @@ +{{- if .Values.autoscaling.enabled }} +--- +# Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "agent.fullname" . }} + namespace: {{ .Release.Namespace | default "default" | quote }} + labels: + {{- include "agent.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "agent.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/charts/matchmaking-agent/templates/ingress.yaml b/charts/matchmaking-agent/templates/ingress.yaml new file mode 100644 index 00000000..570615dc --- /dev/null +++ b/charts/matchmaking-agent/templates/ingress.yaml @@ -0,0 +1,95 @@ +{{- $fullName := include "agent.fullname" . }} +{{- $labels := include "agent.labels" . | nindent 4 }} +{{- $gitVersion := .Capabilities.KubeVersion.GitVersion }} +{{- $endpoints := .Values.agent.endpoints }} +{{- $namespace := .Release.Namespace }} +{{- range .Values.ingresses }} +{{- if and .enabled .endpoints }} +{{- $ingressName := printf "%s-%s" $fullName .hostname }} +--- +# Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +{{- if semverCompare ">=1.19-0" $gitVersion }} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" $gitVersion }} +apiVersion: networking.k8s.io/v1beta1 +{{- else }} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $ingressName }} + namespace: {{ $namespace | default "default" | quote }} + labels: + {{- $labels | nindent 2 }} + annotations: + {{- if and .className (not (semverCompare ">=1.18-0" $gitVersion)) }} + {{- if not (hasKey .annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .annotations "kubernetes.io/ingress.class" .className}} + {{- end }} + {{- end }} + {{- if .certManager }} + {{- if .certManager.issuer }} + {{- $_ := set .annotations "cert-manager.io/issuer" .certManager.issuer}} + {{- end }} + {{- if .certManager.clusterIssuer }} + {{- $_ := set .annotations "cert-manager.io/cluster-issuer" .certManager.clusterIssuer}} + {{- end }} + {{- end }} + {{- with .annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .className (semverCompare ">=1.18-0" $gitVersion) }} + ingressClassName: {{ .className }} + {{- end }} + {{- if .hostname }} + {{- if .tls.enabled }} + tls: + - hosts: + - {{ .hostname }} + {{- if .tls.secretName }} + secretName: {{ .tls.secretName }} + {{- else }} + secretName: {{ $ingressName }}-tls + {{- end }} + {{- end }} + rules: + - host: {{ .hostname }} + http: + paths: + {{- $ingressEndpoints := .endpoints }} + {{- $prefix := .prefix }} + {{- range $name, $mapping := $endpoints }} + {{- if (has $name $ingressEndpoints) }} + - path: {{ $prefix}}{{ $mapping.regex | default $mapping.path }} + pathType: Prefix + backend: + {{- if semverCompare ">=1.19-0" $gitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $mapping.port }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $mapping.port }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} +{{- end }}{{- /* end: if .enabled */}} +{{- end }}{{- /* end: range .Values.ingresses */}} diff --git a/charts/matchmaking-agent/templates/service.yaml b/charts/matchmaking-agent/templates/service.yaml new file mode 100644 index 00000000..0f2a6008 --- /dev/null +++ b/charts/matchmaking-agent/templates/service.yaml @@ -0,0 +1,33 @@ +--- +# Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +apiVersion: v1 +kind: Service +metadata: + name: {{ include "agent.fullname" . }} + namespace: {{ .Release.Namespace | default "default" | quote }} + labels: + {{- include "agent.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.agent.endpoints.default.port }} + targetPort: default + protocol: TCP + name: default + selector: + {{- include "agent.selectorLabels" . | nindent 4 }} diff --git a/charts/matchmaking-agent/templates/serviceaccount.yaml b/charts/matchmaking-agent/templates/serviceaccount.yaml new file mode 100644 index 00000000..fbace363 --- /dev/null +++ b/charts/matchmaking-agent/templates/serviceaccount.yaml @@ -0,0 +1,34 @@ +{{- if .Values.serviceAccount.create -}} +--- +# Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "agent.serviceAccountName" . }} + namespace: {{ .Release.Namespace | default "default" | quote }} + labels: + {{- include "agent.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- with .Values.serviceAccount.imagePullSecrets }} +imagePullSecrets: + {{- toYaml . | nindent 2 }} +{{- end }} +{{- end }} diff --git a/charts/matchmaking-agent/values.yaml b/charts/matchmaking-agent/values.yaml new file mode 100644 index 00000000..bc2d314e --- /dev/null +++ b/charts/matchmaking-agent/values.yaml @@ -0,0 +1,247 @@ +--- +# Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Matchmaking Agent Deployment Values +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# -- Specifies how many replicas of a deployed pod shall be created during the deployment +# Note: If horizontal pod autoscaling is enabled this setting has no effect +replicaCount: 1 + +image: + # -- target registry + registry: docker.io/ + # -- Which derivate of agent to use + repository: tractusx/matchmaking-agent + # -- Overrides the image tag whose default is the chart appVersion + tag: "" + # -- Overrides the image digest + digest: "" + ## Specify an imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: https://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## Example: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## Set to true if you would like to see extra information on logs + ## + +# -- Overrides the charts name +nameOverride: "" + +# -- Overrides the releases full name +fullnameOverride: "" + +# -- Additional custom Labels to add +customLabels: {} + +serviceAccount: + # -- Specifies whether a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) should be created per release + create: true + # -- [Annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) to add to the service account + annotations: {} + # -- The name of the service account to use. If not set and create is true, a name is generated using the release's fullname template + name: "" + +# -- Whether to [automount kubernetes API credentials](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server) into the pod +automountServiceAccountToken: false + +# -- [Annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) added to deployed [pods](https://kubernetes.io/docs/concepts/workloads/pods/) +podAnnotations: {} +# Uncomment this and remove parenthesis if you want to enable apparmor +# container.apparmor.security.beta.kubernetes.io/matchmaking-agent: runtime/default + +# The [pod security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) defines privilege and access control settings for a Pod within the deployment +podSecurityContext: + seccompProfile: + # -- Restrict a Container's Syscalls with seccomp + type: RuntimeDefault + # -- Runs all processes within a pod with a special uid + runAsUser: 10001 + # -- Processes within a pod will belong to this guid + runAsGroup: 30000 + # -- The owner for volumes and any files created within volumes will belong to this guid + fsGroup: 30000 + +# The [container security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) defines privilege and access control settings for a Container within a pod +securityContext: + capabilities: + # -- Specifies which capabilities to drop to reduce syscall attack surface + drop: + - ALL + # -- Specifies which capabilities to add to issue specialized syscalls + add: + - NET_BIND_SERVICE + # -- Whether the root filesystem is mounted in read-only mode + readOnlyRootFilesystem: true + # -- Controls [Privilege Escalation](https://kubernetes.io/docs/concepts/security/pod-security-policy/#privilege-escalation) enabling setuid binaries changing the effective user ID + allowPrivilegeEscalation: false + # -- Requires the container to run without root privileges + runAsNonRoot: true + # -- The container's process will run with the specified uid + runAsUser: 10001 + # -- Processes within a pod will belong to this guid + runAsGroup: 30000 + +livenessProbe: + # -- Whether to enable kubernetes [liveness-probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) + enabled: true + # -- Minimum consecutive failures for the probe to be considered failed after having succeeded + failureThreshold: 3 + # -- Number of seconds each period lasts. + periodSeconds: 60 + # -- number of seconds until a timeout is assumed + timeoutSeconds: 5 + +readinessProbe: + # -- Whether to enable kubernetes readiness-probes + enabled: true + # -- Minimum consecutive failures for the probe to be considered failed after having succeeded + failureThreshold: 3 + # -- Number of seconds each period lasts. + periodSeconds: 300 + # -- number of seconds until a timeout is assumed + timeoutSeconds: 5 + +startupProbe: + # -- Whether to enable kubernetes startup-probes + enabled: true + # -- Minimum consecutive failures for the probe to be considered failed after having succeeded + failureThreshold: 18 + # -- Number of seconds after the container has started before liveness probes are initiated. + initialDelaySeconds: 60 + # -- Number of seconds each period lasts. + periodSeconds: 30 + # -- number of seconds until a timeout is assumed + timeoutSeconds: 5 + +## Endpoints exposed by the matchmaking agent +agent: + endpoints: + ## Default api exposing health checks etc + default: + # -- The network port, which the "default" api is going to be exposed by the container, pod and service + port: "8280" + # -- An auth object for default security + auth: {} + # -- The path mapping the "default" api is going to be exposed by + path: "" + # -- An optional regex path match (whose match groups could be used in an nginx-annotation of the ingress) + regex: /(.*) + +service: + # -- [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) to expose the running application on a set of Pods as a network service. + type: ClusterIP + +## Ingress declaration to expose the network service. +ingresses: + ## Agent-Plane Facing Ingress + - enabled: false + # -- The hostname to be used to precisely map incoming traffic onto the underlying network service + hostname: "matchmaking-agent.local" + # -- Additional ingress annotations to add, for example when implementing more complex routings you may set { nginx.ingress.kubernetes.io/rewrite-target: /$1, nginx.ingress.kubernetes.io/use-regex: "true" } + annotations: + # Example if you want more complex routings in interplay with the endpoints regex property + # nginx.ingress.kubernetes.io/rewrite-target: /$1 + # nginx.ingress.kubernetes.io/use-regex: "true" + # -- Optional prefix that will be prepended to the paths of the endpoints + prefix: "" + # -- Agent endpoints exposed by this ingress resource + endpoints: + - default + # -- Defines the [ingress class](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class) to use + className: "" + # -- TLS [tls class](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls) applied to the ingress resource + tls: + # -- Enables TLS on the ingress resource + enabled: false + # -- If present overwrites the default secret name + secretName: "" + ## Adds [cert-manager](https://cert-manager.io/docs/) annotations to the ingress resource + certManager: + # -- If preset enables certificate generation via cert-manager namespace scoped issuer + issuer: "" + # -- If preset enables certificate generation via cert-manager cluster-wide issuer + clusterIssuer: "" + +# -- [Resource management](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) applied to the deployed pod +# We recommend 25% of a cpu, 512MB per server and 256MB per endpoint +resources: + requests: + cpu: 250m + memory: 768Mi + limits: + cpu: 250m + memory: 768Mi + +autoscaling: + # -- Enables [horizontal pod autoscaling](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) + enabled: false + # -- Minimal replicas if resource consumption falls below resource threshholds + minReplicas: 1 + # -- Maximum replicas if resource consumption exceeds resource threshholds + maxReplicas: 100 + # -- targetAverageUtilization of cpu provided to a pod + targetCPUUtilizationPercentage: 80 + # -- targetAverageUtilization of memory provided to a pod + targetMemoryUtilizationPercentage: 80 + +# -- [Node-Selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) to constrain the Pod to nodes with specific labels. +nodeSelector: {} + +# -- [Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) are applied to Pods to schedule onto nodes with matching taints. +tolerations: [] + +# -- [Affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) constrains which nodes the Pod can be scheduled on based on node labels. +affinity: {} + +# -- Container environment variables e.g. for configuring [JAVA_TOOL_OPTIONS](https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/envvars002.html) +# Ex.: +# JAVA_TOOL_OPTIONS: > +# -Dhttp.proxyHost=proxy -Dhttp.proxyPort=80 -Dhttp.nonProxyHosts="localhost|127.*|[::1]" -Dhttps.proxyHost=proxy -Dhttps.proxyPort=443 +env: {} + +# -- [Kubernetes Secret Resource](https://kubernetes.io/docs/concepts/configuration/secret/) name to load environment variables from +envSecretName: + +logging: + # -- Logback Xml + configuration: |- + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + +# -- A map of repository names to configuration ttl files +repositories: {} diff --git a/matchmaking/README.md b/matchmaking/README.md index 53ec01a8..264593e9 100644 --- a/matchmaking/README.md +++ b/matchmaking/README.md @@ -15,45 +15,149 @@ * under the License. * * SPDX-License-Identifier: Apache-2.0 - --> -# Tractus-X Matchmaking and Inference Agent (Upcoming) +# Tractus-X Matchmaking Agent + +The Matchmaking Agent is a module of the [Tractus-X Knowledge Agents Reference Implementations](../README.md). + +## About this Module + +Up to now the Matchmaking Agent's functionality was integrated into the Agent Plane Container. +This container separates the Matchmaking Agent's functionality from the Agent Plane Container. +As a result, the RDF Store is disjoined from the public-facing Agent Plane container. +It caters for the need of small and medium sized companies who want to directly upload/provide use case data as well as for +security-aware companies who want to separate data storage from public API even for meta-data. +This container also has the ability to be used by the Simple Graph Exchanger Feature, adding the ability to host business data from the RDF Store over the Matchmaking Agent +Communication between the Agent Plane Container and the Matchmaking Agent by a REST API on the docker (internal) network. + +## Architecture + +The FOSS Matchmaking Agent is built using [Jersey](https://github.com/eclipse-ee4j/jersey) (for the REST endpoints) and [RDF4J](https://rdf4j.org/) (for SPARQL parsing). It exposes three endpoints which are to be certified/tested in the KA architecture: +* With the '/api/agent' endpoint the EDC tenant can issue queries and execute skills in interaction with local resources and the complete Dataspace (the so-called Matchmaking Agent that is also hit by incoming Agent transfers). +* With the '/api/graph' endpoint the EDC tenant can manage graph content which can be published as assets. +* With the '/agentsource' endpoint communication with the EDC Dataplane is carried out. However, this is a docker internal endpoint and can not be accessed by a user from the internet + +The Matchmaking Agent does not perform any logic but just returns pre-rendered results depending on the input parameters. + +![Source Code](docs/MatchmakingAgentDiagram.drawio.svg) + + +Architecture is similar to the one shown in Tractus-X Knowledge Agents EDC Extensions (KA-EDC). However the AgentSource Object within the Dataplane accesses the AgentSourceController of the MatchmakingAgent by a REST API. + +### Security + +The conforming agent will be configurable to support the following http/s based security mechanisms: +- Basic Authentication +- Oauth2 + +## Deployment + +### Compile, Test, Package and Containerization + +```console +mvn -Pwith-docker-image +``` + +This will generate + +- a jar file in the respective target folder +- a docker image within the local docker repository which can be started with + +### Run Locally + +The [standalone jar](target/matchmaking-agent-1.10.15-SNAPSHOT.jar) may be started as follows + +```console +java -Dproperty.file.location="dataplane.properties" -cp ../matchmaking-agent-1.10.15-SNAPSHOT.jar org.eclipse.tractusx.agents.conforming.Bootstrap +``` +Make sure that jar file, properties file and dataspace.ttl are in the same directory +Then you should be able to reach the /graph endpoint + +Afterwards, you should be able to access the [local endpoint](http://localhost:8281/api/agent) by directly invoking a query + +```console +curl --location --globoff 'localhost:8280/api/agent?query=SELECT%20%3Fsubject%20%3Fpredicate%20%3Fobject%20WHERE%20{%20%3Fsubject%20%3Fpredicate%20%3Fobject.}' +``` + +### Run in Docker + +```console + docker run -i -p 8280:8280 -t +``` + +Afterwards, you should be able to access the [local endpoint](http://localhost:8281/api/agent) by directly invoking a query + +```console +curl --location --globoff 'localhost:8280/api/agent?query=SELECT%20%3Fsubject%20%3Fpredicate%20%3Fobject%20WHERE%20{%20%3Fsubject%20%3Fpredicate%20%3Fobject.}' +``` -This is a folder providing a FOSS implementations of a Matchmaking Agent. +Nevertheless it is intended that the Matchmaking Agent does not run on its own but rather in a combination of a EDC Data Plane and a Control plane as depicted in the diagram above -The Matchmaking Agent is needed by any Agent-Enabled dataspace participant. +### Notice for Docker Image -The Matchmaking Agent is able to interact with and reason about the Dataspace/EDC (and hence: other Matchmaking Agents) -using a Federated Data Catalogue. +DockerHub: https://hub.docker.com/r/tractusx/matchmaking-agent -It is also able to delegate work on sub-graphs/asset to tenant-internal agents (Binding Agents) providing actual data and functions. +Eclipse Tractus-X product(s) installed within the image: -For Agent-Enabled dataspace consumers, deploying the Matchmaking Agent alongside an Agent-Enabled EDC is sufficient. +- GitHub: https://github.com/eclipse-tractusx/knowledge-agents/tree/main/matchmaking +- Project home: https://projects.eclipse.org/projects/automotive.tractusx +- Dockerfile: https://github.com/eclipse-tractusx/knowledge-agents/blob/main/matchmaking/src/main/docker/Dockerfile +- Project license: Apache License, Version 2.0 -Currently, the Matchmaking Agent (based on Apache Jena Fuseki) is baked into the [EDC data plane (Agent Plane)](https://github.com/eclipse-tractusx/knowledge-agents-edc/tree/main/agent-plane/agent-plane-protocol/src/main/java/org/eclipse/tractusx/agents/edc/sparql). +**Used base image** -This will be refactored in the near future. +- [eclipse-temurin:17-jre-alpine](https://github.com/adoptium/containers) +- Official Eclipse Temurin DockerHub page: https://hub.docker.com/_/eclipse-temurin +- Eclipse Temurin Project: https://projects.eclipse.org/projects/adoptium.temurin +- Additional information about the Eclipse Temurin images: https://github.com/docker-library/repo-info/tree/master/repos/eclipse-temurin -## What is Matchmaking +As with all Docker images, these likely also contain other software which may be under other licenses (such as Bash, etc from the base distribution, along with any direct or indirect dependencies of the primary software being contained). -A query/computation engine is federating if parts of the query maybe (recursively) dumped off to separate query/computation engines collocated in the same environment/dataspace. +As for any pre-built image usage, it is the image user's responsibility to ensure that any use of this image complies with any relevant licenses for all software contained within. -Usually, there will be an explicit construct in the query language which determines (or even: infers) the required computation target. This is useful when the targets of the computations are unique in the sense that they can be listed/lookedup in advance. +### Helm Chart -But there maybe cases in which -* the query designed has no full overview over the dataspace -* the dataspace is rapidly changing -* there are several computation engines providing similar assets, but with a slightly differently profile (contract conditions, intersecting content, performance, ...) -* the integration (union, join) of individual federated computations is costly by itself. +A helm chart for deploying the matchmaking agent can be found under [this folder](../charts/matchmaking-agent). -In these cases, so-called Matchmaking agents come into play. They introduce several measures to improve the behaviour of more complex dataspaces: -* Federation decisions in the query (hence a so-called query rewrite) will be made using advanced meta-data and optimization algorithms. This means that the user of such a matchmaking agent will be able to pose a technically simple (but not necessarily business-wise) query which is then elaborated by the dataspace in an optimal fashion. -* the matchmaking agent comes with its additional computing power. -* the matchmaking agent may negotiate with the most common and critical provider agents to migrate a part of their data/functions to the matchmaking agent in order to be able to do most optimal data integration strategies (local union/join, predicate-push, ...) +It can be added to your umbrella chart.yaml by the following snippet +```console +dependencies: + - name: matchmaking-agent + repository: https://eclipse-tractusx.github.io/charts/dev + version: 1.10.15-SNAPSHOT + alias: my-matchmmaking-agent +``` +and then installed using +```console +helm dependency update +``` +In your values.yml, you configure your specific instance of the matchmaking agent like this +```console +############################################################################################## +# Matchmaking Agent +############################################################################################## +my-matchmaking-agent: + securityContext: *securityContext + nameOverride: my-matchmaking-agent + fullnameOverride: my-matchmaking-agent + ingresses: + - enabled: true + # -- The hostname to be used to precisely map incoming traffic onto the underlying network service + hostname: "my-matchmaking-agent.public-ip" + annotations: + nginx.ingress.kubernetes.io/rewrite-target: /$1 + nginx.ingress.kubernetes.io/use-regex: "true" + # -- Agent endpoints exposed by this ingress resource + endpoints: + - default + tls: + enabled: true + secretName: my-conforming-tls +``` diff --git a/matchmaking/docs/MatchmakingAgentDiagram.drawio.svg b/matchmaking/docs/MatchmakingAgentDiagram.drawio.svg new file mode 100644 index 00000000..ddfa12dd --- /dev/null +++ b/matchmaking/docs/MatchmakingAgentDiagram.drawio.svg @@ -0,0 +1,4 @@ + + + +
EDC Control Plane
EDC Control Plane
Matchmaking Agent
AgentSource
AgentSourceController
SparqlProcessor
GraphController
AgentController
AgreementController
DataManagementImpl
DataspaceSynchronizer
Actor
RdfStore
Matchmaking functionality 
isolating REST interface
EDR Callback
Management API
\ No newline at end of file diff --git a/matchmaking/pom.xml b/matchmaking/pom.xml new file mode 100644 index 00000000..b1bcce99 --- /dev/null +++ b/matchmaking/pom.xml @@ -0,0 +1,428 @@ + + + + + + + org.eclipse.tractusx + agents + 1.10.15-SNAPSHOT + ../pom.xml + + + 4.0.0 + + org.eclipse.tractusx.agents + matchmaking-agent + jar + + Tractus-X Knowledge Agents Matchmaking + This container/application separates the edc part from the matchmaking part for security reasons. + http://catena-x.net/ + + + org.eclipse.tractusx.agents.matchmaking-agent + ${symbolic.name}-${project.version} + true + false + 2.2.12 + 3.1.3 + 4.13.1 + 1.4.8 + 4.8.0 + 3.4.0 + 2.5 + 2.0.1.Final + + + + + + com.google.code.gson + gson + 2.8.8 + + + io.swagger.core.v3 + swagger-jaxrs2 + compile + ${swagger-core-version} + + + ch.qos.logback + logback-classic + ${logback-version} + compile + + + ch.qos.logback + logback-core + ${logback-version} + compile + + + javax.servlet + javax.servlet-api + ${javax.servlet-api.version} + + + org.glassfish.jersey.test-framework.providers + jersey-test-framework-provider-simple + ${jersey3-version} + test + + + org.glassfish.jersey.containers + jersey-container-simple-http + ${jersey3-version} + + + org.glassfish.jersey.media + jersey-media-multipart + ${jersey3-version} + + + + org.glassfish.jersey.media + jersey-media-json-jackson + ${jersey3-version} + runtime + + + + org.glassfish.jersey.containers + jersey-container-servlet + ${jersey3-version} + + + org.glassfish.jersey.inject + jersey-hk2 + ${jersey3-version} + + + org.glassfish.jersey.containers + jersey-container-jetty-http + ${jersey3-version} + + + org.glassfish.jersey.containers + jersey-container-servlet-core + ${jersey3-version} + + + com.fasterxml.jackson.datatype + jackson-datatype-joda + ${jackson.version} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + ${jackson.version} + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-json-provider + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + + javax.xml.bind + jaxb-api + ${jaxb.version} + + + jakarta.ws.rs + jakarta.ws.rs-api + ${jakarta.ws.rs-api.version} + + + org.eclipse.jetty + jetty-servlet + 11.0.20 + + + org.eclipse.jetty.toolchain + jetty-jakarta-servlet-api + ${jetty-jakarta-servlet-api.version} + + + org.apache.jena + jena-fuseki-core + ${org.apache.jena.version} + + + + + org.eclipse.edc + boot + 0.4.1 + + + + org.eclipse.edc + web-spi + ${edc.version} + + + + org.eclipse.edc + data-plane-http + ${edc.version} + + + dev.failsafe + failsafe-okhttp + + + + + org.eclipse.edc + http-spi + ${edc.version} + + + + org.eclipse.edc + core-spi + 0.2.1 + + + + + com.squareup.okio + okio + ${okio.version} + + + + + javax.validation + validation-api + ${beanvalidation-version} + provided + + + + com.nimbusds + nimbus-jose-jwt + ${com.nimbusds.version} + + + + com.squareup.okhttp3 + okhttp + ${okhttp.version} + + + + + com.google.guava + guava + ${guava.version} + + + + + org.eclipse.edc + jersey-core + ${edc.version} + test-fixtures + test + + + + + org.eclipse.rdf4j + rdf4j-queryparser-sparql + ${rdf4j.version} + + + com.fasterxml.jackson.core + jackson-annotations + + + + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + + + + + + src/main/resources + + **/* + + + + .. + + LICENSE + DEPENDENCIES + SECURITY.md + NOTICE.md + + META-INF + + + . + + README.md + + META-INF + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + org.codehaus.mojo + build-helper-maven-plugin + 1.9.1 + + + add-source + generate-sources + + add-source + + + + src/gen/java + + + + + + + + org.apache.maven.plugins + maven-shade-plugin + + + package + + shade + + + + + + io.catenax.knowledge.agents.conforming.Application + 0.5.1 + + + + + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + + + + + + with-docker-image + + + + org.codehaus.mojo + exec-maven-plugin + + + + + + + diff --git a/matchmaking/resources/dataplane.properties b/matchmaking/resources/dataplane.properties new file mode 100644 index 00000000..d51362b4 --- /dev/null +++ b/matchmaking/resources/dataplane.properties @@ -0,0 +1,82 @@ +# Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +# Sample Configuration for Agent Data Plane + +### +# Chapter General Settings +### + +edc.participant.id=BPNL0000000DUMMY + +### +# Chapter Web Server / Ports +### + +web.http.default.port=8082 +web.http.default.path=/api +web.http.public.port=8185 +web.http.public.path=/api/v1/public +web.http.callback.port=8187 +web.http.callback.path=/callback +web.http.control.port=9999 +web.http.control.path=/api/dataplane/control +edc.web.rest.cors.enabled=true +edc.web.rest.cors.headers=origin, content-type, accept, authorization, x-api-key +edc.web.rest.cors.methods=GET, PUT, POST, DELETE, OPTIONS +edc.web.rest.cors.origins=* + +### +# Chapter Security +### + +edc.api.auth.key=foo + +# depends on your chosen vault implementation + +### +# Chapter Trust & Dataspace +### + +# Single Control Plane setup +edc.dataplane.token.validation.endpoint=http://provider-control-plane:9999/control/token + +# Provider and Consumer Control Plane Setup +#edc.dataplane.token.validation.endpoint=http://agent-plane:8082/api/validation/ +edc.dataplane.token.validation.endpoints.provider=http://provider-control-plane:9999/control/token +edc.dataplane.token.validation.endpoints.consumer=http://consumer-control-plane:9999/control/token + +cx.agent.controlplane.protocol=http://consumer-control-plane:8282 +cx.agent.controlplane.management=http://oem-control-plane2:8181/management +cx.agent.controlplane.management.provider=http://oem-control-plane2:8181/management +cx.agent.callback=http://agent-plane:8187/callback/endpoint-data-reference +cx.agent.skill.contract.default=Contract?partner=Skill +cx.agent.edc.version=0.5.1 + +cx.agent.service.allow=(edcs?://.*)|(https://query\\.wikidata\\.org/sparql)|(http://[^\\.]+:\\d+.*) +cx.agent.service.asset.allow=(edcs?://.*)|(https://query\\.wikidata\\.org/sparql)|(http://[^\\.]+:\\d+.*) +cx.agent.service.deny=^$ +cx.agent.service.asset.deny=^$ + +### +# Chapter Agent Catalogue +### + +cx.agent.asset.file=dataspace.ttl +cx.agent.dataspace.synchronization=60000 +cx.agent.dataspace.remotes=http://oem-control-plane:8282,http://consumer-control-plane:8282 +cx.agent.matchmaking.internal.api=8080 diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/AgentApi.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/AgentApi.java new file mode 100644 index 00000000..8d6e70e0 --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/AgentApi.java @@ -0,0 +1,147 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.api; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Request; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +import jakarta.ws.rs.core.UriInfo; +import org.eclipse.tractusx.agents.conforming.model.CxWarning; +import org.eclipse.tractusx.agents.conforming.model.JsonResultset; +import org.eclipse.tractusx.agents.conforming.model.XmlResultset; + +import java.util.List; + + +@Path("/") +@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") +public abstract class AgentApi { + + @Context + public SecurityContext securityContext; + @Context + public Application application; + @Context + public HttpHeaders headers; + @Context + public Request request; + @Context + public Response response; + @Context + public UriInfo uri; + + @GET + @Produces({ "application/sparql-results+json", + "application/sparql-results+xml" + }) + @Operation(summary = "Invoke a Skill or Query (Simple)", description = "", tags = { "agent" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "The SparQL query has been processed successfully.", + content = { + @Content(mediaType = "application/sparql-results+json", schema = @Schema(implementation = JsonResultset.class)), + @Content(mediaType = "application/sparql-results+xml", schema = @Schema(implementation = XmlResultset.class)) + }), + @ApiResponse(responseCode = "203", description = "The SparQL query has been processed successfully but warnings did occur.", + headers = { @Header(name = "cx_warnings", schema = @Schema(type = "array", implementation = CxWarning.class)) }, + content = { + @Content(mediaType = "application/sparql-results+json", schema = @Schema(implementation = JsonResultset.class)), + @Content(mediaType = "application/sparql-results+xml", schema = @Schema(implementation = XmlResultset.class)) + }), + @ApiResponse(responseCode = "400", description = "Bad request or malformed SPARQL"), + @ApiResponse(responseCode = "500", description = "Fatal error") + }) + public abstract Response getAgent( + @Parameter(in = ParameterIn.QUERY, description = "The Target Asset of the Query (targets the complete dataspace if empty)") + @QueryParam("asset") String asset, + @Parameter(in = ParameterIn.QUERY, description = "The Query language (fixed: SPARQL)") + @QueryParam("queryLn") String queryLn, + @Parameter(in = ParameterIn.QUERY, description = "The SPARQL query") + @QueryParam("query") String query, + @Parameter(in = ParameterIn.QUERY, description = "A sample bound parameter 'vin' which opens a new input tuple") + @QueryParam("(vin") String vin, + @Parameter(in = ParameterIn.QUERY, description = "A sample multi-bound parameter 'troubleCode' which closes the tuple") + @QueryParam("troubleCode") List troubleCode) + throws org.eclipse.tractusx.agents.conforming.api.NotFoundException; + + @POST + @Consumes({ "application/sparql-results+json", "application/sparql-results+xml", "application/sparql-query" }) + @Produces({ "application/sparql-results+json", "application/sparql-results+xml" }) + @Operation(summary = "Invoke a Skill or Query (Flexible)", description = "", tags = { "agent" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "The SparQL query has been processed successfully.", + content = { + @Content(mediaType = "application/sparql-results+json", schema = @Schema(implementation = JsonResultset.class)), + @Content(mediaType = "application/sparql-results+xml", schema = @Schema(implementation = XmlResultset.class)) + }), + @ApiResponse(responseCode = "203", description = "The SparQL query has been processed successfully but warnings did occur.", + headers = { @Header(name = "cx_warnings", schema = @Schema(type = "array", implementation = CxWarning.class)) }, + content = { + @Content(mediaType = "application/sparql-results+json", schema = @Schema(implementation = JsonResultset.class)), + @Content(mediaType = "application/sparql-results+xml", schema = @Schema(implementation = XmlResultset.class)) + }), + @ApiResponse(responseCode = "400", description = "Bad request or malformed SPARQL"), + @ApiResponse(responseCode = "500", description = "Fatal error") + }) + public abstract Response postAgent( + @Parameter(in = ParameterIn.DEFAULT, description = "The body either contains the query or a binding data set when a skill is invoked", required = true) + Object body, + @Parameter(in = ParameterIn.QUERY, description = "The Target Asset of the Query (targets the complete dataspace if empty)") + @QueryParam("asset") String asset, + @Parameter(in = ParameterIn.QUERY, description = "The Query language (fixed: SPARQL)") + @QueryParam("queryLn") String queryLn, + @Parameter(in = ParameterIn.QUERY, description = "The SPARQL query") + @QueryParam("query") String query, + @Parameter(in = ParameterIn.QUERY, description = "A sample bound parameter 'vin' which opens a new input tuple") + @QueryParam("(vin") String vin, + @Parameter(in = ParameterIn.QUERY, description = "A sample multi-bound parameter 'troubleCode' which closes the tuple") + @QueryParam("troubleCode") List troubleCode) + throws org.eclipse.tractusx.agents.conforming.api.NotFoundException; + + @POST + @Path("/skill") + @Consumes({ "application/sparql-query" }) + @Operation(summary = "Register a Skill", description = "", tags = { "agent" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Skill has been registered"), + @ApiResponse(responseCode = "204", description = "Skill has been updated"), + @ApiResponse(responseCode = "400", description = "Bad request or malformed SPARQL"), + @ApiResponse(responseCode = "500", description = "Fatal error") }) + public abstract Response postSkill( + @Parameter(in = ParameterIn.DEFAULT, description = "The body either contains the parameterized query", required = true) + String body, + @Parameter(in = ParameterIn.QUERY, description = "The Target Asset of the Query (targets the complete dataspace if empty)", required = true) + @QueryParam("asset") String asset) + throws org.eclipse.tractusx.agents.conforming.api.NotFoundException; + +} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/ApiException.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/ApiException.java new file mode 100644 index 00000000..03887970 --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/ApiException.java @@ -0,0 +1,27 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.api; + +@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") +public class ApiException extends Exception { + private int code; + + public ApiException(int code, String msg) { + super(msg); + this.code = code; + } +} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/ApiOriginFilter.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/ApiOriginFilter.java new file mode 100644 index 00000000..a012627f --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/ApiOriginFilter.java @@ -0,0 +1,46 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.api; + +import java.io.IOException; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") +public class ApiOriginFilter implements javax.servlet.Filter { + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + HttpServletResponse res = (HttpServletResponse) response; + res.addHeader("Access-Control-Allow-Origin", "*"); + res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT"); + res.addHeader("Access-Control-Allow-Headers", "Content-Type"); + chain.doFilter(request, response); + } + + @Override + public void destroy() { + } +} \ No newline at end of file diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/JsonProvider.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/JsonProvider.java new file mode 100644 index 00000000..2540c5a3 --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/JsonProvider.java @@ -0,0 +1,58 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.ext.MessageBodyReader; +import jakarta.ws.rs.ext.MessageBodyWriter; +import jakarta.ws.rs.ext.Provider; +import org.eclipse.tractusx.agents.conforming.ConformingAgent; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +@Provider +public class JsonProvider implements MessageBodyReader, MessageBodyWriter { + + ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public boolean isReadable(Class aclass, Type type, Annotation[] annotations, MediaType mediaType) { + return mediaType.isCompatible(ConformingAgent.srj); + } + + @Override + public Object readFrom(Class aclass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap multivaluedMap, InputStream inputStream) throws IOException, WebApplicationException { + return objectMapper.readTree(inputStream); + } + + @Override + public boolean isWriteable(Class aclass, Type type, Annotation[] annotations, MediaType mediaType) { + return mediaType.isCompatible(ConformingAgent.srj); + } + + @Override + public void writeTo(Object o, Class aclass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap multivaluedMap, OutputStream outputStream) throws IOException, WebApplicationException { + objectMapper.writeValue(outputStream, o); + } +} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/NotFoundException.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/NotFoundException.java new file mode 100644 index 00000000..84b02191 --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/NotFoundException.java @@ -0,0 +1,27 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.api; + +@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") +public class NotFoundException extends ApiException { + private int code; + + public NotFoundException(int code, String msg) { + super(code, msg); + this.code = code; + } +} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/Rfc3339DateFormat.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/Rfc3339DateFormat.java new file mode 100644 index 00000000..8ee61c98 --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/Rfc3339DateFormat.java @@ -0,0 +1,35 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.api; + +import com.fasterxml.jackson.databind.util.ISO8601DateFormat; +import com.fasterxml.jackson.databind.util.ISO8601Utils; + +import java.text.FieldPosition; +import java.util.Date; + +public class Rfc3339DateFormat extends ISO8601DateFormat { + + // Same as ISO8601DateFormat but serializing milliseconds. + @Override + public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { + String value = ISO8601Utils.format(date, true); + toAppendTo.append(value); + return toAppendTo; + } + +} \ No newline at end of file diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/SparqlProvider.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/SparqlProvider.java new file mode 100644 index 00000000..85397577 --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/SparqlProvider.java @@ -0,0 +1,64 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.ext.MessageBodyReader; +import jakarta.ws.rs.ext.MessageBodyWriter; +import jakarta.ws.rs.ext.Provider; +import org.eclipse.tractusx.agents.conforming.ConformingAgent; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.stream.Collectors; + +@Provider +public class SparqlProvider implements MessageBodyReader, MessageBodyWriter { + + ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public boolean isReadable(Class aclass, Type type, Annotation[] annotations, MediaType mediaType) { + return mediaType.isCompatible(ConformingAgent.sq); + } + + @Override + public Object readFrom(Class aclass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap multivaluedMap, InputStream inputStream) throws IOException, WebApplicationException { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + return reader.lines().collect(Collectors.joining("\n")); + } + } + + @Override + public boolean isWriteable(Class aclass, Type type, Annotation[] annotations, MediaType mediaType) { + return mediaType.isCompatible(ConformingAgent.sq); + } + + @Override + public void writeTo(Object o, Class aclass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap multivaluedMap, OutputStream outputStream) throws IOException, WebApplicationException { + new OutputStreamWriter(outputStream).append(String.valueOf(o)); + } +} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/StringUtil.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/StringUtil.java new file mode 100644 index 00000000..691a2e47 --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/StringUtil.java @@ -0,0 +1,58 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.api; + +@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") +public class StringUtil { + /** + * Check if the given array contains the given value (with case-insensitive comparison). + * + * @param array The array + * @param value The value to search + * @return true if the array contains the value + */ + public static boolean containsIgnoreCase(String[] array, String value) { + for (String str : array) { + if (value == null && str == null) return true; + if (value != null && value.equalsIgnoreCase(str)) return true; + } + return false; + } + + /** + * Join an array of strings with the given separator. + *

+ * Note: This might be replaced by utility method from commons-lang or guava someday + * if one of those libraries is added as dependency. + *

+ * + * @param array The array of strings + * @param separator The separator + * @return the resulting string + */ + public static String join(String[] array, String separator) { + int len = array.length; + if (len == 0) return ""; + + StringBuilder out = new StringBuilder(); + out.append(array[0]); + for (int i = 1; i < len; i++) { + out.append(separator).append(array[i]); + } + return out.toString(); + } +} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/XmlProvider.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/XmlProvider.java new file mode 100644 index 00000000..9c79b801 --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/XmlProvider.java @@ -0,0 +1,85 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.api; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.ext.MessageBodyReader; +import jakarta.ws.rs.ext.MessageBodyWriter; +import jakarta.ws.rs.ext.Provider; +import org.eclipse.tractusx.agents.conforming.ConformingAgent; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +/** + * This class provides a MessageBodyReader and MessageBodyWriter for XML content type. + * It prevents access to external DTDs and stylesheets while reading and writing XML. + */ +@Provider +public class XmlProvider implements MessageBodyReader, MessageBodyWriter { + + @Override + public boolean isReadable(Class aclass, Type type, Annotation[] annotations, MediaType mediaType) { + return mediaType.isCompatible(ConformingAgent.srx); + } + + @Override + public Object readFrom(Class aclass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap multivaluedMap, InputStream inputStream) throws IOException, WebApplicationException { + try { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + DocumentBuilder parser = factory.newDocumentBuilder(); + return parser.parse(new InputSource(inputStream)); + } catch (ParserConfigurationException | SAXException e) { + throw new IOException("Could not xml parse message body", e); + } + } + + @Override + public boolean isWriteable(Class aclass, Type type, Annotation[] annotations, MediaType mediaType) { + return mediaType.isCompatible(ConformingAgent.srx); + } + + @Override + public void writeTo(Object o, Class aclass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap multivaluedMap, OutputStream outputStream) throws IOException, WebApplicationException { + try { + TransformerFactory factory = TransformerFactory.newInstance(); + factory.setAttribute("http://javax.xml.XMLConstants/property/accessExternalDTD", ""); + factory.setAttribute("http://javax.xml.XMLConstants/property/accessExternalStylesheet", ""); + Transformer transformer = factory.newTransformer(); + transformer.transform(new DOMSource((Document) o), new StreamResult(outputStream)); + } catch (TransformerException e) { + throw new IOException("Cannot render xml body", e); + } + } +} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/CxWarning.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/CxWarning.java new file mode 100644 index 00000000..c36d1612 --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/CxWarning.java @@ -0,0 +1,214 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; + +import java.util.Objects; + +/** + * CxWarning + */ +@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") +public class CxWarning { + @JsonProperty("source-tenant") + private String sourceTenant = null; + + @JsonProperty("source-asset") + private String sourceAsset = null; + + @JsonProperty("target-tenant") + private String targetTenant = null; + + @JsonProperty("target-asset") + private String targetAsset = null; + + @JsonProperty("problem") + private String problem = null; + + @JsonProperty("context") + private String context = null; + + public CxWarning sourceTenant(String sourceTenant) { + this.sourceTenant = sourceTenant; + return this; + } + + /** + * Get sourceTenant + * + * @return sourceTenant + **/ + @JsonProperty("source-tenant") + @Schema(description = "") + public String getSourceTenant() { + return sourceTenant; + } + + public void setSourceTenant(String sourceTenant) { + this.sourceTenant = sourceTenant; + } + + public CxWarning sourceAsset(String sourceAsset) { + this.sourceAsset = sourceAsset; + return this; + } + + /** + * Get sourceAsset + * + * @return sourceAsset + **/ + @JsonProperty("source-asset") + @Schema(description = "") + public String getSourceAsset() { + return sourceAsset; + } + + public void setSourceAsset(String sourceAsset) { + this.sourceAsset = sourceAsset; + } + + public CxWarning targetTenant(String targetTenant) { + this.targetTenant = targetTenant; + return this; + } + + /** + * Get targetTenant + * + * @return targetTenant + **/ + @JsonProperty("target-tenant") + @Schema(description = "") + public String getTargetTenant() { + return targetTenant; + } + + public void setTargetTenant(String targetTenant) { + this.targetTenant = targetTenant; + } + + public CxWarning targetAsset(String targetAsset) { + this.targetAsset = targetAsset; + return this; + } + + /** + * Get targetAsset + * + * @return targetAsset + **/ + @JsonProperty("target-asset") + @Schema(description = "") + public String getTargetAsset() { + return targetAsset; + } + + public void setTargetAsset(String targetAsset) { + this.targetAsset = targetAsset; + } + + public CxWarning problem(String problem) { + this.problem = problem; + return this; + } + + /** + * Get problem + * + * @return problem + **/ + @JsonProperty("problem") + @Schema(description = "") + public String getProblem() { + return problem; + } + + public void setProblem(String problem) { + this.problem = problem; + } + + public CxWarning context(String context) { + this.context = context; + return this; + } + + /** + * Get context + * + * @return context + **/ + @JsonProperty("context") + @Schema(description = "") + public String getContext() { + return context; + } + + public void setContext(String context) { + this.context = context; + } + + @Override + public int hashCode() { + return Objects.hash(sourceTenant, sourceAsset, targetTenant, targetAsset, problem, context); + } + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CxWarning cxWarning = (CxWarning) o; + return Objects.equals(this.sourceTenant, cxWarning.sourceTenant) && + Objects.equals(this.sourceAsset, cxWarning.sourceAsset) && + Objects.equals(this.targetTenant, cxWarning.targetTenant) && + Objects.equals(this.targetAsset, cxWarning.targetAsset) && + Objects.equals(this.problem, cxWarning.problem) && + Objects.equals(this.context, cxWarning.context); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class CxWarning {\n"); + + sb.append(" sourceTenant: ").append(toIndentedString(sourceTenant)).append("\n"); + sb.append(" sourceAsset: ").append(toIndentedString(sourceAsset)).append("\n"); + sb.append(" targetTenant: ").append(toIndentedString(targetTenant)).append("\n"); + sb.append(" targetAsset: ").append(toIndentedString(targetAsset)).append("\n"); + sb.append(" problem: ").append(toIndentedString(problem)).append("\n"); + sb.append(" context: ").append(toIndentedString(context)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultset.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultset.java new file mode 100644 index 00000000..8c888026 --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultset.java @@ -0,0 +1,117 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; + +import java.util.Objects; +import javax.validation.Valid; + +/** + * JsonResultset + */ +@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") +public class JsonResultset { + @JsonProperty("head") + private JsonResultsetHead head = null; + + @JsonProperty("results") + private JsonResultsetResults results = null; + + public JsonResultset head(JsonResultsetHead head) { + this.head = head; + return this; + } + + /** + * Get head + * + * @return head + **/ + @JsonProperty("head") + @Schema(description = "") + @Valid + public JsonResultsetHead getHead() { + return head; + } + + public void setHead(JsonResultsetHead head) { + this.head = head; + } + + public JsonResultset results(JsonResultsetResults results) { + this.results = results; + return this; + } + + /** + * Get results + * + * @return results + **/ + @JsonProperty("results") + @Schema(description = "") + @Valid + public JsonResultsetResults getResults() { + return results; + } + + public void setResults(JsonResultsetResults results) { + this.results = results; + } + + @Override + public int hashCode() { + return Objects.hash(head, results); + } + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + JsonResultset jsonResultset = (JsonResultset) o; + return Objects.equals(this.head, jsonResultset.head) && + Objects.equals(this.results, jsonResultset.results); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class JsonResultset {\n"); + + sb.append(" head: ").append(toIndentedString(head)).append("\n"); + sb.append(" results: ").append(toIndentedString(results)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultsetHead.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultsetHead.java new file mode 100644 index 00000000..7de6ed5d --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultsetHead.java @@ -0,0 +1,99 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * JsonResultsetHead + */ +@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") +public class JsonResultsetHead { + @JsonProperty("vars") + private List vars = null; + + public JsonResultsetHead vars(List vars) { + this.vars = vars; + return this; + } + + public JsonResultsetHead addVarsItem(String varsItem) { + if (this.vars == null) { + this.vars = new ArrayList(); + } + this.vars.add(varsItem); + return this; + } + + /** + * Get vars + * + * @return vars + **/ + @JsonProperty("vars") + @Schema(description = "") + public List getVars() { + return vars; + } + + public void setVars(List vars) { + this.vars = vars; + } + + @Override + public int hashCode() { + return Objects.hash(vars); + } + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + JsonResultsetHead jsonResultsetHead = (JsonResultsetHead) o; + return Objects.equals(this.vars, jsonResultsetHead.vars); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class JsonResultsetHead {\n"); + + sb.append(" vars: ").append(toIndentedString(vars)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultsetResults.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultsetResults.java new file mode 100644 index 00000000..20de1434 --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultsetResults.java @@ -0,0 +1,99 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * JsonResultsetResults + */ +@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") +public class JsonResultsetResults { + @JsonProperty("bindings") + private List bindings = null; + + public JsonResultsetResults bindings(List bindings) { + this.bindings = bindings; + return this; + } + + public JsonResultsetResults addBindingsItem(Object bindingsItem) { + if (this.bindings == null) { + this.bindings = new ArrayList(); + } + this.bindings.add(bindingsItem); + return this; + } + + /** + * Get bindings + * + * @return bindings + **/ + @JsonProperty("bindings") + @Schema(description = "") + public List getBindings() { + return bindings; + } + + public void setBindings(List bindings) { + this.bindings = bindings; + } + + @Override + public int hashCode() { + return Objects.hash(bindings); + } + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + JsonResultsetResults jsonResultsetResults = (JsonResultsetResults) o; + return Objects.equals(this.bindings, jsonResultsetResults.bindings); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class JsonResultsetResults {\n"); + + sb.append(" bindings: ").append(toIndentedString(bindings)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultset.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultset.java new file mode 100644 index 00000000..1755388a --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultset.java @@ -0,0 +1,117 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; + +import java.util.Objects; +import javax.validation.Valid; + +/** + * XmlResultset + */ +@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") +public class XmlResultset { + @JsonProperty("head") + private XmlResultsetHead head = null; + + @JsonProperty("results") + private XmlResultsetResults results = null; + + public XmlResultset head(XmlResultsetHead head) { + this.head = head; + return this; + } + + /** + * Get head + * + * @return head + **/ + @JsonProperty("head") + @Schema(description = "") + @Valid + public XmlResultsetHead getHead() { + return head; + } + + public void setHead(XmlResultsetHead head) { + this.head = head; + } + + public XmlResultset results(XmlResultsetResults results) { + this.results = results; + return this; + } + + /** + * Get results + * + * @return results + **/ + @JsonProperty("results") + @Schema(description = "") + @Valid + public XmlResultsetResults getResults() { + return results; + } + + public void setResults(XmlResultsetResults results) { + this.results = results; + } + + @Override + public int hashCode() { + return Objects.hash(head, results); + } + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + XmlResultset xmlResultset = (XmlResultset) o; + return Objects.equals(this.head, xmlResultset.head) && + Objects.equals(this.results, xmlResultset.results); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class XmlResultset {\n"); + + sb.append(" head: ").append(toIndentedString(head)).append("\n"); + sb.append(" results: ").append(toIndentedString(results)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetHead.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetHead.java new file mode 100644 index 00000000..e6c16b01 --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetHead.java @@ -0,0 +1,84 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * XmlResultsetHead + */ +@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") +public class XmlResultsetHead { + @JsonProperty("variable") + private List variables = new ArrayList<>(); + + public XmlResultsetHead addVariable(XmlResultsetHeadVariable variable) { + this.variables.add(variable); + return this; + } + + /** + * Get variables + * + * @return variables + **/ + public List getVariables() { + return variables; + } + + @Override + public int hashCode() { + return Objects.hash(variables); + } + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + XmlResultsetHead xmlResultsetHead = (XmlResultsetHead) o; + return Objects.equals(this.variables, xmlResultsetHead.variables); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class XmlResultsetHead {\n"); + + sb.append(" variable: ").append(toIndentedString(variables)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetHeadVariable.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetHeadVariable.java new file mode 100644 index 00000000..0bb8ddb1 --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetHeadVariable.java @@ -0,0 +1,89 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; + +import java.util.Objects; + +/** + * XmlResultsetHeadVariable + */ +@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") +public class XmlResultsetHeadVariable { + @JsonProperty("name") + private String name = null; + + public XmlResultsetHeadVariable name(String name) { + this.name = name; + return this; + } + + /** + * Get name + * + * @return name + **/ + @JsonProperty("name") + @Schema(description = "") + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + XmlResultsetHeadVariable xmlResultsetHeadVariable = (XmlResultsetHeadVariable) o; + return Objects.equals(this.name, xmlResultsetHeadVariable.name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class XmlResultsetHeadVariable {\n"); + + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResults.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResults.java new file mode 100644 index 00000000..3049250f --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResults.java @@ -0,0 +1,84 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * XmlResultsetResults + */ +@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") +public class XmlResultsetResults { + @JsonProperty("result") + private List results = new ArrayList<>(); + + public XmlResultsetResults addResult(XmlResultsetResultsResult result) { + this.results.add(result); + return this; + } + + /** + * Get result + * + * @return result + **/ + public List getResults() { + return results; + } + + @Override + public int hashCode() { + return Objects.hash(results); + } + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + XmlResultsetResults xmlResultsetResults = (XmlResultsetResults) o; + return Objects.equals(this.results, xmlResultsetResults.results); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class XmlResultsetResults {\n"); + + sb.append(" result: ").append(toIndentedString(results)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResult.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResult.java new file mode 100644 index 00000000..9107a207 --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResult.java @@ -0,0 +1,84 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * XmlResultsetResultsResult + */ +@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") +public class XmlResultsetResultsResult { + @JsonProperty("binding") + private List bindings = new ArrayList<>(); + + public XmlResultsetResultsResult addBinding(XmlResultsetResultsResultBinding binding) { + this.bindings.add(binding); + return this; + } + + /** + * Get binding + * + * @return binding + **/ + public List getBindings() { + return bindings; + } + + @Override + public int hashCode() { + return Objects.hash(bindings); + } + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + XmlResultsetResultsResult xmlResultsetResultsResult = (XmlResultsetResultsResult) o; + return Objects.equals(this.bindings, xmlResultsetResultsResult.bindings); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class XmlResultsetResultsResult {\n"); + + sb.append(" binding: ").append(toIndentedString(bindings)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResultBinding.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResultBinding.java new file mode 100644 index 00000000..136ed872 --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResultBinding.java @@ -0,0 +1,139 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; + +import java.util.Objects; + +/** + * XmlResultsetResultsResultBinding + */ +@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") +public class XmlResultsetResultsResultBinding { + @JsonProperty("name") + private String name = null; + + @JsonProperty("literal") + private XmlResultsetResultsResultBindingLiteral literal = null; + + @JsonProperty("uri") + private String uri = null; + + public XmlResultsetResultsResultBinding name(String name) { + this.name = name; + return this; + } + + /** + * Get name + * + * @return name + **/ + @JsonProperty("name") + @Schema(description = "") + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public XmlResultsetResultsResultBinding literal(XmlResultsetResultsResultBindingLiteral literal) { + this.literal = literal; + return this; + } + + /** + * Get literal + * + * @return literal + **/ + @JsonProperty("literal") + @Schema(description = "") + public XmlResultsetResultsResultBindingLiteral getLiteral() { + return literal; + } + + public void setLiteral(XmlResultsetResultsResultBindingLiteral literal) { + this.literal = literal; + } + + public XmlResultsetResultsResultBinding uri(String uri) { + this.uri = uri; + return this; + } + + /** + * Get uri + * + * @return uri + **/ + @JsonProperty("uri") + @Schema(description = "") + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + @Override + public int hashCode() { + return Objects.hash(name, literal, uri); + } + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + XmlResultsetResultsResultBinding xmlResultsetResultsResultBinding = (XmlResultsetResultsResultBinding) o; + return Objects.equals(this.name, xmlResultsetResultsResultBinding.name) && + Objects.equals(this.literal, xmlResultsetResultsResultBinding.literal) && + Objects.equals(this.uri, xmlResultsetResultsResultBinding.uri); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class XmlResultsetResultsResultBinding {\n"); + + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" literal: ").append(toIndentedString(literal)).append("\n"); + sb.append(" uri: ").append(toIndentedString(uri)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResultBindingLiteral.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResultBindingLiteral.java new file mode 100644 index 00000000..56eec6c3 --- /dev/null +++ b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResultBindingLiteral.java @@ -0,0 +1,142 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText; +import io.swagger.v3.oas.annotations.media.Schema; + +import java.util.Objects; + +/** + * XmlResultsetResultsResultBindingLiteral + */ +@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-24T17:09:51.803733265Z[GMT]") +public class XmlResultsetResultsResultBindingLiteral { + @JsonProperty("xml:lang") + private String xmllang = null; + + @JsonProperty("datatype") + private String datatype = null; + + @JsonProperty("value") + @JacksonXmlText + private String value = null; + + public XmlResultsetResultsResultBindingLiteral xmllang(String xmllang) { + this.xmllang = xmllang; + return this; + } + + /** + * Get xmllang + * + * @return xmllang + **/ + @JsonProperty("xml:lang") + @Schema(description = "") + public String getXmllang() { + return xmllang; + } + + public void setXmllang(String xmllang) { + this.xmllang = xmllang; + } + + public XmlResultsetResultsResultBindingLiteral datatype(String datatype) { + this.datatype = datatype; + return this; + } + + /** + * Get datatype + * + * @return datatype + **/ + @JsonProperty("datatype") + @Schema(description = "") + public String getDatatype() { + return datatype; + } + + public void setDatatype(String datatype) { + this.datatype = datatype; + } + + public XmlResultsetResultsResultBindingLiteral value(String value) { + this.value = value; + return this; + } + + /** + * Get value + * + * @return value + **/ + @JsonProperty("value") + @Schema(description = "") + @JacksonXmlText() + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @Override + public int hashCode() { + return Objects.hash(xmllang, datatype, value); + } + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + XmlResultsetResultsResultBindingLiteral xmlResultsetResultsResultBindingLiteral = (XmlResultsetResultsResultBindingLiteral) o; + return Objects.equals(this.xmllang, xmlResultsetResultsResultBindingLiteral.xmllang) && + Objects.equals(this.datatype, xmlResultsetResultsResultBindingLiteral.datatype) && + Objects.equals(this.value, xmlResultsetResultsResultBindingLiteral.value); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class XmlResultsetResultsResultBindingLiteral {\n"); + + sb.append(" xmllang: ").append(toIndentedString(xmllang)).append("\n"); + sb.append(" datatype: ").append(toIndentedString(datatype)).append("\n"); + sb.append(" value: ").append(toIndentedString(value)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/matchmaking/src/main/docker/Dockerfile b/matchmaking/src/main/docker/Dockerfile new file mode 100644 index 00000000..f4cc5f5e --- /dev/null +++ b/matchmaking/src/main/docker/Dockerfile @@ -0,0 +1,52 @@ +# Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +FROM eclipse-temurin:17-jre-alpine +ARG JAR +ARG LIB + +ARG APP_USER=agent +ARG APP_UID=10100 +ARG APP_GID=30000 + +RUN addgroup --gid "$APP_GID" --system "$APP_USER" + +RUN apk add --update curl + +RUN adduser \ + --shell /sbin/nologin \ + --disabled-password \ + --gecos "" \ + --ingroup "$APP_USER" \ + --no-create-home \ + --uid "$APP_UID" \ + "$APP_USER" + +USER "$APP_USER" +WORKDIR /app +VOLUME /tmp + +COPY target/matchmaking-agent-*.jar /app/lib/ +COPY resources/dataplane.properties /app/configuration.properties +COPY resources/dataspace.ttl /app/dataspace.ttl + +# TODO implement wget or curl-based health check +HEALTHCHECK NONE + +EXPOSE 8080 + +ENTRYPOINT ["java","-cp","/app/lib/*", "org.eclipse.tractusx.agents.conforming.Bootstrap"] \ No newline at end of file diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/BindingAgent.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/BindingAgent.java new file mode 100644 index 00000000..25843819 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/BindingAgent.java @@ -0,0 +1,66 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming; + +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Response; +import org.eclipse.rdf4j.query.parser.ParsedQuery; +import org.eclipse.rdf4j.query.parser.sparql.SPARQLParser; +import org.eclipse.tractusx.agents.conforming.api.NotFoundException; + +import java.util.List; +import javax.validation.constraints.NotNull; + +/** + * Implements a standard binding agent + */ +@Path("/bind") +public class BindingAgent extends ConformingAgent { + + public BindingAgent() { + + } + + @Override + public Response getAgent(String asset, String queryLn, String query, String vin, List troubleCode) throws NotFoundException { + if (query == null) { + return annotate(Response.status(400, "{ \"error\":400, \"reason\":\"KA-BIND: query parameter must be set\" }")); + } + SPARQLParser parser = new SPARQLParser(); + ParsedQuery sparql = parser.parseQuery(query, uri.getAbsolutePath().toString()); + + try { + sparql.getTupleExpr().visit(new BindingProfileChecker()); + } catch (Exception e) { + return annotate(Response.status(400, "{ \"error\":400, \"reason\":\"" + e.getMessage() + "\" }")); + } + return super.getAgent(asset, queryLn, query, vin, troubleCode); + } + + @Override + public Response postAgent(Object body, String asset, String queryLn, String query, String vin, List troubleCode) throws NotFoundException { + if (body == null || String.valueOf(body).isEmpty()) { + return annotate(Response.status(400, "{ \"error\":400, \"reason\":\"KA-BIND: query parameter must be set\" }")); + } + return super.postAgent(body, asset, queryLn, query, vin, troubleCode); + } + + @Override + public Response postSkill(String body, @NotNull String asset) throws NotFoundException { + return annotate(Response.status(404, "{ \"error\":404, \"reason\":\"KA-BIND: does not support skills\" }")); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/BindingProfileChecker.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/BindingProfileChecker.java new file mode 100644 index 00000000..a9037685 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/BindingProfileChecker.java @@ -0,0 +1,38 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming; + +import org.eclipse.rdf4j.query.algebra.StatementPattern; +import org.eclipse.rdf4j.query.algebra.helpers.AbstractQueryModelVisitor; + +public class BindingProfileChecker extends AbstractQueryModelVisitor { + @Override + public void meet(StatementPattern node) throws Exception { + if (!node.getPredicateVar().isConstant()) { + throw new Exception("Predicate must be not constant."); + } + if (!node.getPredicateVar().getValue().isIRI()) { + throw new Exception("Predicate must be IRI."); + } + if ("http://www.w3.org/1999/02/22-rdf-syntax-ns#type".equals(node.getPredicateVar().getValue().stringValue())) { + if (!node.getObjectVar().isConstant()) { + throw new Exception("Object of rdf:type must be constant."); + } + } + super.meet(node); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/Bootstrap.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/Bootstrap.java new file mode 100644 index 00000000..33b3bfb6 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/Bootstrap.java @@ -0,0 +1,173 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.info.Contact; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.info.License; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.tractusx.agents.conforming.api.JsonProvider; +import org.eclipse.tractusx.agents.conforming.api.SparqlProvider; +import org.eclipse.tractusx.agents.conforming.api.XmlProvider; +import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.edc.http.transfer.AgentSourceServlet; +import org.glassfish.jersey.media.multipart.MultiPartFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.servlet.ServletContainer; +import sun.misc.Signal; + +import java.io.IOException; + +@OpenAPIDefinition( + info = @Info( + title = "Swagger Server", + version = "0.8.7", + description = "# Motivation This API is designed along the [W3C SPARQL 1.1](https://www.w3.org/TR/sparql11-query/) specification. It represents the core interface of the Catena-X Knowledge Agents (CX KA) Architecture to enable federated (i.e. distributed, but independent) and sovereign (i.e. collaborative, but controlled and secured) data processing over GAIA-X/IDS dataspaces. For that purpose, this API is used in three different functions/building blocks of CX KA: 1. As a Consumer-facing entrypoint into the dataspace (the so-called Matchmaking Agent). 2. As a Provider-facing callback from the dataspace into the backend (the so-called Binding Agent). 3. As an intermediate Transfer protocol between \"Sinks\" representing SPARQL Remote Service Contexts (=sub queries/routines) and the corresponding \"Sources\" representing backend-bound SPARQL Graph Contexts. These Sinks and Sources are to be implemented using the EDC (Eclipse Dataspace Components) framework. For each of these three functions, a particular \"profile\" of this API (here: a fragment or variant of the full-blown SPARQL 1.1 specification) is employed: 1. The KA-MATCH profile allows to call federated SPARQL logic as stored procedures (so-called Skills) based on a rich set of meta-data (ontology) 2. The KA-BIND profile allows to delegate non-federated and data-focussed SPARQL sub-queries by compiling them into native backend API calls (e.g. in SQL or REST). 3. The KA-TRANSFER profile allows to wrap (and unwrap) well-defined header and protocol information from SPARQL into the generic payload of the EDC Http transfer. This API is already designed with alternative query protocols (such as GRAPHQL or Federated SQL) in mind. # Examples ## Invoke a Locally-Stored Parameterized Skill (Simple) ``` curl --location '${KA-MATCH}/agent?asset=urn%3Acx%3ASkill%3Aconsumer%3ALifetime&(vin=WBAAL31029PZ00001&troubleCode=P0746&troubleCode=P0745)&(vin=WBAAL31029PZ00002&troubleCode=P0744)&(vin=WBAAL31029PZ00003&troubleCode=P0743)' \\ --header 'Authorization: Basic ${UuencodedUsernameColonPassword}' ``` ## Invoke a Dataspace-Stored Parameterized Skill (Flexible) ``` curl --location '${KA-MATCH}/agent?asset=${EDC-BUSINESSPARTNER}%23urn%3Acx%3ASkill%3Aconsumer%3ALifetime' \\ --header 'Content-Type: application/sparql-results+json' \\ --header 'Authorization: Basic ${UuencodedUsernameColonPassword}' \\ --data '{ \"head\": { \"vars\": [ \"vin\", \"troubleCode\" ] }, \"results\": { \"bindings\": [ { \"vin\": { \"type\": \"literal\", \"value\": \"WBAAL31029PZ00001\" }, \"troubleCode\": { \"type\": \"literal\", \"value\": \"P0746\" } }, { \"vin\": { \"type\": \"literal\", \"value\": \"WBAAL31029PZ00001\" }, \"troubleCode\": { \"type\": \"literal\", \"value\": \"P0745\" } }, { \"vin\": { \"type\": \"literal\", \"value\": \"WBAAL31029PZ00002\" }, \"troubleCode\": { \"type\": \"literal\", \"value\": \"P0744\" } } ] } }' ``` ## Register a Parameterized Skill ``` curl --location '${KA-MATCH}/agent/skill?asset=urn%3Acx%3ASkill%3Aconsumer%3ALifetime' \\ --header 'Content-Type: application/sparql-query' \\ --header 'Authorization: Basic ${UuencodedUsernameColonPassword}' \\ --data-raw 'PREFIX xsd: PREFIX rdf: PREFIX rdfs: PREFIX cx: ############################################################################################ # Catena-X Knowledge Agents Sample Federated Skill # Realizes a 5-Step Business Process # \"Remaining Useful Life Prognosis based on Diagnosis TroubleCodes\" ############################################################################################ # Preconditions: # - A Contract Offering from OEM (e.g. BMW) to CONSUMER (e.g. ADAC) # - VIN-VAN Conversion # - DTC Analysis/Resolution (including the READING of PartType and Description) # - Serial Part & SUPPLIER Lookup # - A Contract Offering from SUPPLIER (e.g. ZF) to OEM # - Telematics data (including the PROPAGATION of LoadSpectrum) # - RUL Prognosis Invocation (including the DISTRIBUTION of RUL results) ############################################################################################ #### # 5. Project the actual output of the Skill on CONSUMER side #### SELECT ?van ?troubleCode ?description ?affectedPart ?distanceKm ?timeDays ?vin WHERE { #### # 1. The CONSUMER detects a trouble code on a car in his fleet #### VALUES (?vin ?troubleCode) { (\"@vin\"^^xsd:string \"@troubleCode\"^^xsd:string) }. #### # 2. The CONSUMER looks up the OEM (connector) associated to the VIN # using the Federated Data Catalogue (Catalogue=Default Graph) #### ?oem cx:isIssuerOfVehicleIdentificationNumber ?vin; cx:hasConnector ?oemConnector. ?oemConnector cx:offersAsset ?diagnoseAsset. ?diagnoseAsset rdf:type ; rdfs:isDefinedBy . #### # 3. The CONSUMER delegates the following logic to the OEM (connector) #### SERVICE ?oemConnector { #### # 3.1 The OEM (e.g. BMW) anomyzes the VIN into an anomymous (VAN) node #. and gets some master data with it #### ?van cx:isAnonymousVehicle ?vin; cx:hasRegistration ?registration. #### # 3.2 The OEM analyzes the DTC-affected part type (Diagnosis Graph) #### GRAPH ?diagnoseAsset { ?Dtc rdf:type cx:DTC; cx:Code ?troubleCode; cx:affects [ cx:EnDenomination ?partType ]; cx:Description ?description. } # OEM#Diagnosis context #### # 3.3 The OEM obtains fresh telematics/load-spectrum data for the vehicle # focussed to the problematic partType (Telematics Graph) #### ?van cx:latestMileageReceived ?mileage; cx:latestDetailReceived ?telematicsDetail. ?telematicsDetail cx:hasPartType ?partType; cx:hasLoadSpectrum ?loadSpectrum. #### # 3.4 The OEM looks up the serialized part of the VAN (Traceability Graph) # and the supplier address in the dataspace #### ?serializedPart cx:isComponentOf+ ?van; cx:hasPartType ?partType; cx:hasName ?affectedPart; cx:hasSupplier [ cx:hasConnector ?tieraConnector ]. ?tieraConnector cx:offersAsset ?prognosisAsset. ?prognosisAsset rdfs:isDefinedBy . #### # 4. The OEM (and not the CONSUMER) delegates to the SUPPLIER (connector) # which means that load spectrum data etc is only exchanged using their # contract and between their connectors. #### SERVICE ?tieraConnector { #### # 4.1 The SUPPLIER adds additional measurement information #### ?telematicsDetail cx:hasFile ?loadSpectrumFile; cx:hasHeader ?loadSpectrumHeader. #### # 4.2 The SUPPLIER invokes a prognosis model associated the part type using the load-spectrum data #### GRAPH ?prognosisAsset { ?invocation rdf:type cx:LifetimePrognosis; # <--General vehicle info cx:loadCollectiveMileage ?mileage; cx:loadCollectiveRegistrationDate ?registration; # <--Part Info from the OEM cx:loadCollectiveComponent ?affectedPart; cx:loadCollectiveBody ?loadSpectrum; # <--Additional info from the SUPPLIER cx:loadCollectiveFile ?loadSpectrumFile; cx:loadCollectiveHeader ?loadSpectrumHeader; # -->the actual prognosis output cx:remainingDistance ?distanceKm; cx:remainingTime ?timeDays. } # SUPPLIER#Prognosis context } # SUPPLIER context } # OEM context # now we do reporting/operationalising on the CONSUMER side } ORDER BY ?remainingDistance LIMIT 5' ``` ## Invoke an Ad-hoc Query ``` curl --location '${KA-BIND}/agent' \\ --header 'Content-Type: application/sparql-query' \\ --header 'Authorization: Basic ${UuencodedUsernameColonPassword}' \\ --data-raw 'PREFIX xsd: PREFIX rdf: PREFIX rdfs: PREFIX cx: # Sample Graph Context that is Delegated/Instantiated to a Binding Agent Call SELECT ?partType ?description WHERE { VALUES (?troubleCode) { (\"P0745\"^^xsd:string) (\"P0746\"^^xsd:string) }. ?Dtc rdf:type cx:DTC; cx:Code ?troubleCode; cx:affects [ cx:EnDenomination ?partType ]; cx:Description ?description. } ``` ", + termsOfService = "http://catenax.io", + contact = @Contact(email = "info@catenax.io"), + license = @License( + name = "Eclipse Public License", + url = "https://www.eclipse.org/legal/epl-2.0/" + ) + ) +) + +public class Bootstrap { + + private Monitor monitor; + Server externalServer; + Server internalServer; + + /** + * Starts Grizzly HTTP server exposing JAX-RS resources defined in this application. + */ + public Bootstrap() { + handleSignal("TERM"); + SharedObjectManager sharedObjectManager = SharedObjectManager.getInstance(); + this.monitor = sharedObjectManager.getMonitor(); + ResourceConfig internalServerConfig = new ResourceConfig(); + AgentConfig conf = sharedObjectManager.getAgentConfig(); + internalServerConfig.register(AgentSourceServlet.class); + monitor.debug(String.format("Registering %s", "AgentSourceController Constructor")); + + // For AgentSource endpoint accessed by data plane + int port = conf.getMatchmakingPortInternal(); + monitor.debug(String.format("Starting servver on port %s", port)); + internalServer = new Server(port); + ServletContextHandler internalContext = new ServletContextHandler(ServletContextHandler.SESSIONS); + internalContext.setContextPath("/"); + internalServer.setHandler(internalContext); + internalContext.addServlet(AgentSourceServlet.class, "/agentsource"); + + // For AgentController and GraphController endpoints (public endpoints) + ServletContextHandler handler = new ServletContextHandler(ServletContextHandler.SESSIONS); + handler.setContextPath("/api"); + ResourceConfig resourceConfig = new ResourceConfig(); + resourceConfig.packages("io.catenax.knowledge.agents.conforming"); + resourceConfig.register(JsonProvider.class); + resourceConfig.register(XmlProvider.class); + resourceConfig.register(SparqlProvider.class); + resourceConfig.register(BindingAgent.class); + resourceConfig.register(TransferAgent.class); + resourceConfig.register(MatchmakingAgent.class); + resourceConfig.packages("org.glassfish.jersey.examples.multipart"); + resourceConfig.register(MultiPartFeature.class); + monitor.debug(String.format("Registering agreement controller %s", sharedObjectManager.getAgreementController())); + resourceConfig.register(sharedObjectManager.getAgreementController()); + monitor.debug("registering AgentController"); + resourceConfig.register(sharedObjectManager.getAgentController()); + monitor.debug("registering GraphController"); + resourceConfig.register(sharedObjectManager.getGraphController()); + handler.addServlet(new ServletHolder(new ServletContainer(resourceConfig)), "/*"); + externalServer = new Server(8280); + externalServer.setHandler(handler); + + // Start the external server + Thread externalServerThread = new Thread(() -> { + monitor.debug("Trying to start external server"); + try { + externalServer.start(); + externalServer.join(); + } catch (Exception e) { + e.printStackTrace(); + } + }); + + // Start the internal server + Thread internalServerThread = new Thread(() -> { + monitor.debug("Trying to start internal server"); + try { + internalServer.start(); + internalServer.join(); + } catch (Exception e) { + e.printStackTrace(); + } + }); + + // Start both servers concurrently + externalServerThread.start(); + internalServerThread.start(); + + // Wait for both server threads to finish + try { + externalServerThread.join(); + internalServerThread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } + + /** + * Main method. + * + * @param args arguments + * @throws IOException in case some strange things happen + */ + public static void main(String[] args) throws IOException { + new Bootstrap(); + System.out.println("Started Matchmaking Agent."); + while (true) { + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + } + + private void shutdown() { + System.out.println("Shutdown initiated"); + internalServer.destroy(); + externalServer.destroy(); + System.exit(0); + } + + private void handleSignal(String name) { + Signal signal = new Signal(name); + Signal.handle(signal, signalEvent -> { + System.out.println("Signal received: " + signal.getName()); + if ("TERM".equals(signal.getName())) { + shutdown(); + } + }); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/ConformingAgent.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/ConformingAgent.java new file mode 100644 index 00000000..99c87f77 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/ConformingAgent.java @@ -0,0 +1,295 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming; + +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.eclipse.tractusx.agents.conforming.api.AgentApi; +import org.eclipse.tractusx.agents.conforming.api.NotFoundException; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import java.util.regex.Matcher; +import javax.validation.constraints.NotNull; + +public class ConformingAgent extends AgentApi { + + public static String emptyJson = "{\n" + + " \"head\": {\n" + + " \"vars\": [\n" + + " ]\n" + + " },\n" + + " \"results\": {\n" + + " \"bindings\": [\n" + + " ]\n" + + " }\n" + + "}"; + + public static String simpleJson = "{\n" + + " \"head\": {\n" + + " \"vars\": [\n" + + " \"subject\",\n" + + " \"predicate\",\n" + + " \"object\"\n" + + " ]\n" + + " },\n" + + " \"results\": {\n" + + " \"bindings\": [\n" + + " {\n" + + " \"subject\": {\n" + + " \"type\": \"uri\",\n" + + " \"value\": \"urn:cx:AnonymousSerializedPart#GB4711\"\n" + + " },\n" + + " \"predicate\": {\n" + + " \"type\": \"uri\",\n" + + " \"value\": \"https://w3id.org/catenax/ontology#hasPartType\"\n" + + " },\n" + + " \"object\": {\n" + + " \"type\": \"literal\",\n" + + " \"value\": \"engine control module\",\n" + + " \"datatype\": \"http://www.w3.org/1999/02/22-rdf-syntax-ns#langString\",\n" + + " \"xml:lang\": \"en\"\n" + + " }\n" + + " }\n" + + " ]\n" + + " }\n" + + "}"; + + public static String simpleBindJson = "{\n" + + " \"head\": {\n" + + " \"vars\": [\n" + + " \"subject\",\n" + + " \"predicate\",\n" + + " \"object\",\n" + + " \"bindingVar\"\n" + + " ]\n" + + " },\n" + + " \"results\": {\n" + + " \"bindings\": [\n" + + " {\n" + + " \"bindingVar\": {\n" + + " \"type\": \"literal\",\n" + + " \"value\": \"0\"\n" + + " },\n" + + " \"subject\": {\n" + + " \"type\": \"uri\",\n" + + " \"value\": \"urn:cx:AnonymousSerializedPart#GB4711\"\n" + + " },\n" + + " \"predicate\": {\n" + + " \"type\": \"uri\",\n" + + " \"value\": \"hhttps://w3id.org/catenax/ontology#hasPartType\"\n" + + " },\n" + + " \"object\": {\n" + + " \"type\": \"literal\",\n" + + " \"value\": \"engine control module\",\n" + + " \"datatype\": \"http://www.w3.org/1999/02/22-rdf-syntax-ns#langString\",\n" + + " \"xml:lang\": \"en\"\n" + + " }\n" + + " }\n" + + " ]\n" + + " }\n" + + "}"; + + public static String emptyXml = "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + public static String simpleXml = "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " urn:cx:AnonymousSerializedPart#GB4711\n" + + " \n" + + " \n" + + " https://w3id.org/catenax/ontology#hasPartType\n" + + " \n" + + " \n" + + " engine control module\n" + + " \n" + + " \n" + + " \n" + + ""; + + public static String simpleBindXml = "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 0\n" + + " \n" + + " \n" + + " urn:cx:AnonymousSerializedPart#GB4711\n" + + " \n" + + " \n" + + " https://w3id.org/catenax/ontology#hasPartType\n" + + " \n" + + " \n" + + " engine control module\n" + + " \n" + + " \n" + + " \n" + + ""; + + public static MediaType srj = MediaType.valueOf("application/sparql-results+json"); + public static MediaType srx = MediaType.valueOf("application/sparql-results+xml"); + public static MediaType sq = MediaType.valueOf("application/sparql-query"); + + public boolean useSimple = true; + public int status = 200; + public String warnings = "[ { \"source-tenant\": \"BPNL00000003CQI9\", \"target-tenant\": \"BPNL00000003COJN\", \"target-asset\": \"urn:cx:GraphAsset#TestAsset\", \"problem\": \"Could not access graph.\", \"context\": \"SPARQL-QUERY 1027\" } ]"; + java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("\\?(binding[0-9]+)"); + + @Override + public Response getAgent(String asset, String queryLn, String query, String vin, List troubleCode) throws NotFoundException { + MediaType resultType = getDefaultResultType(); + if (resultType == null) { + return annotate(Response.status(400, "KA-BIND/KA-MATCH: Only supports application/sparql-results+json|xml compatible Accept header")); + } + String bindingVar = null; + if (query != null) { + Matcher matcher = pattern.matcher(query); + if (matcher.find()) { + bindingVar = matcher.group(1); + } + } + return annotate(compute(resultType, bindingVar)); + } + + @Override + public Response postAgent(Object body, String asset, String queryLn, String query, String vin, List troubleCode) throws NotFoundException { + MediaType resultType = getDefaultResultType(); + if (resultType == null) { + return annotate(Response.status(400, "KA-BIND/KA-MATCH: Only supports application/sparql-results+json|xml compatible Accept header")); + } + MediaType bodyType = MediaType.valueOf(headers.getHeaderString("Content-Type")); + if (!bodyType.isCompatible(sq) && !bodyType.isCompatible(srj) && !bodyType.isCompatible(srx)) { + return annotate(Response.status(400, "KA-BIND/KA-MATCH postAgent only accepts application/sparql-query|results+json|xml in body.")); + } + String bindingVar = null; + String toCheck = query; + if (query == null) { + toCheck = String.valueOf(body); + } + if (toCheck != null) { + Matcher matcher = pattern.matcher(toCheck); + if (matcher.find()) { + bindingVar = matcher.group(1); + } + } + return annotate(compute(resultType, bindingVar)); + } + + @Override + public Response postSkill(String body, @NotNull String asset) throws NotFoundException { + if (asset.length() == 0) { + return Response.status(400, "KA-BIND/KA-MATCH postSkill requires a non-empty asset name.").build(); + } + MediaType bodyType = MediaType.valueOf(headers.getHeaderString("Content-Type")); + if (body != null || body.isEmpty() || !bodyType.isCompatible(sq)) { + return Response.status(400, "KA-BIND/KA-MATCH postSkill only accepts application/sparql-query|results+json|xml in body.").build(); + } + return Response.ok().build(); + } + + protected MediaType getDefaultResultType() { + if (headers.getHeaderString("Accept") != null) { + String[] compartments = headers.getHeaderString("Accept").split(","); + for (String compartment : compartments) { + String[] qualifiers = compartment.split(";"); + try { + MediaType wantedEncoding = MediaType.valueOf(qualifiers[0]); + if (wantedEncoding.isCompatible(srj)) { + return srj; + } else if (wantedEncoding.isCompatible(srx)) { + return srx; + } + } catch (IllegalArgumentException iae) { + System.err.printf("Warning: Ingoring unsupported accepted mediatype %s%n", qualifiers[0]); + } + } + return null; + } + return srj; + } + + /** + * produces a standard response + */ + protected Map computeBody(MediaType resultType, String bindingVar) { + String target; + if (useSimple) { + if (resultType.isCompatible(srj)) { + target = getSimpleJson(bindingVar); + } else { + target = getSimpleXml(bindingVar); + } + } else { + if (resultType.isCompatible(srj)) { + target = emptyJson; + } else { + target = emptyXml; + } + } + return Map.of(resultType.toString(), target.getBytes()); + } + + protected String getSimpleJson(String bindingVar) { + if (bindingVar != null) { + return simpleBindJson.replaceAll("bindingVar", bindingVar); + } + return simpleJson; + } + + protected String getSimpleXml(String bindingVar) { + if (bindingVar != null) { + return simpleBindXml.replaceAll("bindingVar", bindingVar); + } else { + return simpleXml; + } + } + + /** + * produces a standard response + */ + protected Response.ResponseBuilder compute(MediaType resultType, String bindingVar) { + AtomicReference response = new AtomicReference<>(Response.status(status)); + Map body = computeBody(resultType, bindingVar); + body.forEach((key, value) -> response.set(response.get().type(key).entity(value))); + return response.get(); + } + + protected Response annotate(Response.ResponseBuilder builder) { + return builder.build(); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/MatchmakingAgent.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/MatchmakingAgent.java new file mode 100644 index 00000000..59f2ebc9 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/MatchmakingAgent.java @@ -0,0 +1,57 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming; + +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Response; +import org.eclipse.tractusx.agents.conforming.api.NotFoundException; + +import java.util.List; + +/** + * Implements a standard matchmaking agent + */ +@Path("/match") +public class MatchmakingAgent extends ConformingAgent { + + public MatchmakingAgent() { + status = 203; + } + + @Override + public Response getAgent(String asset, String queryLn, String query, String vin, List troubleCode) throws NotFoundException { + if (query == null && asset == null) { + return annotate(Response.status(400, "{ \"error\":400, \"reason\":\"KA-MATCH: query or asset parameter must be set\" }")); + } + return super.getAgent(asset, queryLn, query, vin, troubleCode); + } + + @Override + public Response postAgent(Object body, String asset, String queryLn, String query, String vin, List troubleCode) throws NotFoundException { + if ((body == null || String.valueOf(body).isEmpty()) && asset == null) { + return annotate(Response.status(400, "{ \"error\":400, \"reason\":\"KA-BIND: body or asset parameter must be set\" }")); + } + return super.postAgent(body, asset, queryLn, query, vin, troubleCode); + } + + @Override + protected Response annotate(Response.ResponseBuilder builder) { + return builder.header("cx_warnings", warnings) + .header("Access-Control-Expose-Headers", "cx_warnings, content-length, content-type") + .build(); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/SharedObjectManager.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/SharedObjectManager.java new file mode 100644 index 00000000..5aa719af --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/SharedObjectManager.java @@ -0,0 +1,199 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +package org.eclipse.tractusx.agents.conforming; + +import com.google.gson.Gson; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import org.apache.jena.query.Syntax; +import org.apache.jena.sparql.serializer.SerializerRegistry; +import org.apache.jena.sparql.service.ServiceExecutorRegistry; +import org.eclipse.edc.spi.monitor.ConsoleMonitor; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.system.configuration.Config; +import org.eclipse.edc.spi.system.configuration.ConfigFactory; +import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.edc.AgreementControllerImpl; +import org.eclipse.tractusx.agents.edc.SkillStore; +import org.eclipse.tractusx.agents.edc.http.AgentController; +import org.eclipse.tractusx.agents.edc.http.DelegationServiceImpl; +import org.eclipse.tractusx.agents.edc.http.GraphController; +import org.eclipse.tractusx.agents.edc.rdf.RdfStore; +import org.eclipse.tractusx.agents.edc.service.DataManagementImpl; +import org.eclipse.tractusx.agents.edc.service.DataspaceSynchronizer; +import org.eclipse.tractusx.agents.edc.service.EdcSkillStore; +import org.eclipse.tractusx.agents.edc.sparql.DataspaceServiceExecutor; +import org.eclipse.tractusx.agents.edc.sparql.SparqlQueryProcessor; +import org.eclipse.tractusx.agents.edc.sparql.SparqlQuerySerializerFactory; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +public class SharedObjectManager { + private static final SharedObjectManager INSTANCE = new SharedObjectManager(); + private Monitor monitor; + private TypeManager typeManager; + private AgentConfig agentConfig; + private RdfStore rdfStore; + private ServiceExecutorRegistry reg; + private SparqlQueryProcessor processor; + private DataManagementImpl catalogService; + private SkillStore skillStore; + private AgreementControllerImpl agreementController; + private AgentController agentController; + private GraphController graphController; + private DelegationServiceImpl delegationService; + private DataspaceSynchronizer synchronizer; + private OkHttpClient httpClient; + + + private SharedObjectManager() { + // Initialize shared objects + this.monitor = new ConsoleMonitor(); + this.typeManager = new TypeManager(); + Properties props = new Properties(); + FileInputStream input = null; + try { + if (System.getProperty("property.file.location") == null) { + input = new FileInputStream("/app/configuration.properties"); + } else { + input = new FileInputStream(System.getProperty("property.file.location")); + } + props.load(input); + } catch (IOException ex) { + ex.printStackTrace(); + } finally { + if (input != null) { + try { + input.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + Config emptyConfig = ConfigFactory.fromProperties(props); + this.agentConfig = new AgentConfig(monitor, emptyConfig); + this.httpClient = new OkHttpClient(); + this.catalogService = new DataManagementImpl(monitor, typeManager, httpClient, agentConfig); + agreementController = new AgreementControllerImpl(monitor, agentConfig, catalogService); + this.rdfStore = new RdfStore(agentConfig, monitor); + ScheduledExecutorService executorService = Executors.newScheduledThreadPool(agentConfig.getThreadPoolSize()); + synchronizer = new DataspaceSynchronizer(executorService, agentConfig, catalogService, rdfStore, monitor); + this.reg = new ServiceExecutorRegistry(); + reg.addBulkLink(new DataspaceServiceExecutor(monitor, agreementController, agentConfig, httpClient, executorService, typeManager)); + SparqlQuerySerializerFactory arqQuerySerializerFactory = new SparqlQuerySerializerFactory(); + SerializerRegistry.get().addQuerySerializer(Syntax.syntaxARQ, arqQuerySerializerFactory); + SerializerRegistry.get().addQuerySerializer(Syntax.syntaxSPARQL_10, arqQuerySerializerFactory); + SerializerRegistry.get().addQuerySerializer(Syntax.syntaxSPARQL_11, arqQuerySerializerFactory); + this.processor = new SparqlQueryProcessor(reg, monitor, agentConfig, rdfStore, typeManager); + this.skillStore = new EdcSkillStore(catalogService, typeManager, agentConfig); + this.delegationService = new DelegationServiceImpl(agreementController, monitor, httpClient, typeManager, agentConfig); + this.agentController = new AgentController(monitor, agreementController, agentConfig, processor, skillStore, delegationService); + this.graphController = new GraphController(monitor, rdfStore, catalogService, agentConfig); + + } + + public static String convertToCurl(Request request) { + StringBuilder curlCommand = new StringBuilder("curl"); + + // Add method + curlCommand.append(" -X ").append(request.method()); + + // Add headers + request.headers().toMultimap().forEach((name, values) -> { + values.forEach(value -> curlCommand.append(" -H '").append(name).append(": ").append(value).append("'")); + }); + + // Add request body if present + if (request.body() != null) { + Gson gson = new Gson(); + String bodyString = gson.toJson(request.body().toString()); + curlCommand.append(" -d '").append(bodyString).append("'"); + } + + // Add URL + curlCommand.append(" '").append(request.url()).append("'"); + + return curlCommand.toString(); + } + + public static SharedObjectManager getInstance() { + return INSTANCE; + } + + public Monitor getMonitor() { + return monitor; + } + + public TypeManager getTypeManager() { + return typeManager; + } + + public AgentConfig getAgentConfig() { + return agentConfig; + } + + public RdfStore getRdfStore() { + return rdfStore; + } + + public ServiceExecutorRegistry getReg() { + return reg; + } + + public SparqlQueryProcessor getProcessor() { + return processor; + } + + public DataManagementImpl getCatalogService() { + return catalogService; + } + + public SkillStore getSkillStore() { + return skillStore; + } + + public AgreementControllerImpl getAgreementController() { + return agreementController; + } + + public DelegationServiceImpl getDelegationService() { + return delegationService; + } + + public DataspaceSynchronizer getSynchronizer() { + return synchronizer; + } + + public OkHttpClient getHttpClient() { + return httpClient; + } + + public AgentController getAgentController() { + return agentController; + } + + public GraphController getGraphController() { + return graphController; + } + +} \ No newline at end of file diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/TransferAgent.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/TransferAgent.java new file mode 100644 index 00000000..f5e0aa0e --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/TransferAgent.java @@ -0,0 +1,109 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming; + +import jakarta.annotation.PostConstruct; +import jakarta.validation.constraints.NotNull; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.eclipse.tractusx.agents.conforming.api.NotFoundException; +import org.glassfish.jersey.media.multipart.FormDataMultiPart; + +import java.util.List; + +/** + * Implements a standard transfer agent + */ +@Path("/transfer") +public class TransferAgent extends ConformingAgent { + + /** + * the actual delegator to use + */ + ConformingAgent delegator = new MatchmakingAgent(); + + @PostConstruct + public void init() { + delegator.application = application; + delegator.securityContext = securityContext; + delegator.headers = headers; + delegator.request = request; + delegator.response = response; + delegator.uri = uri; + } + + @Override + public Response getAgent(String asset, String queryLn, String query, String vin, List troubleCode) throws NotFoundException { + Response intermediate = delegator.getAgent(asset, queryLn, query, vin, troubleCode); + return compute(intermediate); + } + + @Override + public Response postAgent(Object body, String asset, String queryLn, String query, String vin, List troubleCode) throws NotFoundException { + Response intermediate = delegator.postAgent(body, asset, queryLn, query, vin, troubleCode); + return compute(intermediate); + } + + @Override + public Response postSkill(String body, @NotNull String asset) throws NotFoundException { + return Response.status(404, "{ \"error\":404, \"reason\":\"KA-BIND: does not support skills\" }").build(); + } + + @Override + protected MediaType getDefaultResultType() { + if (this.uri.getQueryParameters().containsKey("cx_accepts")) { + List allCompartments = this.uri.getQueryParameters().get("cx_accepts"); + for (String compartments : allCompartments) { + for (String compartment : compartments.split(",")) { + String[] qualifiers = compartment.split(";"); + try { + MediaType wantedEncoding = MediaType.valueOf(qualifiers[0]); + if (wantedEncoding.isCompatible(srj)) { + return srj; + } else if (wantedEncoding.isCompatible(srx)) { + return srx; + } + } catch (IllegalArgumentException iae) { + // we simply return null then + } + } + } + return null; + } + return srj; + } + + /** + * produces a standard response + */ + protected Response compute(Response delegateResponse) { + Response.ResponseBuilder response = Response.status(delegateResponse.getStatus()).type(MediaType.MULTIPART_FORM_DATA); + FormDataMultiPart mpe = new FormDataMultiPart(); + if (delegateResponse.hasEntity()) { + mpe.bodyPart(delegateResponse.getEntity(), delegateResponse.getMediaType()); + } + if (delegateResponse.getHeaders().containsKey("cx_warnings")) { + mpe.bodyPart(delegateResponse.getHeaderString("cx_warnings"), MediaType.APPLICATION_JSON_TYPE); + } + if (mpe.getBodyParts().size() > 0) { + response = response.entity(mpe); + } + return response.build(); + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentConfig.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentConfig.java new file mode 100644 index 00000000..564d5866 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentConfig.java @@ -0,0 +1,405 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc; + +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.system.configuration.Config; + +import java.util.Map; +import java.util.regex.Pattern; + +/** + * typed wrapper around the + * EDC configuration + */ +public class AgentConfig { + + public static final String DEFAULT_ASSET_PROPERTY = "cx.agent.asset.default"; + public static final String DEFAULT_ASSET_NAME = "urn:x-arq:DefaultGraph"; + + public static final String ASSET_FILE_PROPERTY = "cx.agent.asset.file"; + + public static final String ACCESS_POINT_PROPERTY = "cx.agent.accesspoint.name"; + public static final String DEFAULT_ACCESS_POINT = "api"; + + public static final String VERBOSE_PROPERTY = "cx.agent.sparql.verbose"; + public static final boolean DEFAULT_VERBOSE_PROPERTY = false; + + public static final String CONTROL_PLANE_MANAGEMENT_PROVIDER = "cx.agent.controlplane.management.provider"; + public static final String CONTROL_PLANE_MANAGEMENT = "cx.agent.controlplane.management"; + public static final String CONTROL_PLANE_IDS = "cx.agent.controlplane.protocol"; + + public static final String BUSINESS_PARTNER_NUMBER = "edc.participant.id"; + public static final String CONTROL_PLANE_AUTH_HEADER = "edc.api.auth.header"; + public static final String CONTROL_PLANE_AUTH_VALUE = "edc.api.auth.key"; + + public static final String NEGOTIATION_TIMEOUT_PROPERTY = "cx.agent.negotiation.timeout"; + public static final long DEFAULT_NEGOTIATION_TIMEOUT = 30000; + + public static final String NEGOTIATION_POLLINTERVAL_PROPERTY = "cx.agent.negotiation.poll"; + public static final long DEFAULT_NEGOTIATION_POLLINTERVAL = 1000; + + public static final String DATASPACE_SYNCINTERVAL_PROPERTY = "cx.agent.dataspace.synchronization"; + public static final long DEFAULT_DATASPACE_SYNCINTERVAL = -1; + + public static final String DATASPACE_SYNCCONNECTORS_PROPERTY = "cx.agent.dataspace.remotes"; + + public static final String RDF_STORE = "cx.agent.rdf.store"; + + public static final String VALIDATION_ENDPOINTS = "edc.dataplane.token.validation.endpoints"; + + public static final String FEDERATION_SERVICE_BATCH_SIZE = "cx.agent.federation.batch.max"; + public static final long DEFAULT_FEDERATION_SERVICE_BATCH_SIZE = Long.MAX_VALUE; + + public static final String THREAD_POOL_SIZE = "cx.agent.threadpool.size"; + public static final int DEFAULT_THREAD_POOL_SIZE = 4; + + public static final String CONNECT_TIMEOUT_PROPERTY = "cx.agent.connect.timeout"; + public static final String WRITE_TIMEOUT_PROPERTY = "cx.agent.write.timeout"; + public static final String CALL_TIMEOUT_PROPERTY = "cx.agent.call.timeout"; + public static final String READ_TIMEOUT_PROPERTY = "cx.agent.read.timeout"; + public static final int DEFAULT_READ_TIMEOUT = 1080000; + + public static final String CALLBACK_ENDPOINT = "cx.agent.callback"; + + public static final String DEFAULT_SKILL_CONTRACT_PROPERTY = "cx.agent.skill.contract.default"; + + public static final String DEFAULT_GRAPH_CONTRACT_PROPERTY = "cx.agent.graph.contract.default"; + + public static final String SERVICE_ALLOW_PROPERTY = "cx.agent.service.allow"; + public static final String DEFAULT_SERVICE_ALLOW_PATTERN = "(http|edc)s?://.*"; + + public static final String SERVICE_DENY_PROPERTY = "cx.agent.service.deny"; + public static final String DEFAULT_SERVICE_DENY_PATTERN = "^$"; + + public static final String SERVICE_ALLOW_ASSET_PROPERTY = "cx.agent.service.asset.allow"; + public static final String DEFAULT_SERVICE_ALLOW_ASSET_PATTERN = "(http|edc)s://.*"; + + public static final String SERVICE_DENY_ASSET_PROPERTY = "cx.agent.service.asset.deny"; + public static final String DEFAULT_SERVICE_DENY_ASSET_PATTERN = "^$"; + + public static final String TX_EDC_VERSION_PROPERTY = "cx.agent.edc.version"; + + public static final String MATCHMAKING_PORT_INTERNAL = "cx.agent.matchmaking.internal.api"; + + /** + * precompiled stuff + */ + protected final Pattern serviceAllowPattern; + protected final Pattern serviceDenyPattern; + protected final Pattern serviceAssetAllowPattern; + protected final Pattern serviceAssetDenyPattern; + + /** + * references to EDC services + */ + protected final Config config; + protected final Monitor monitor; + + /** + * creates the typed config + * + * @param monitor logger + * @param config untyped config + */ + public AgentConfig(Monitor monitor, Config config) { + this.monitor = monitor; + this.config = config; + serviceAllowPattern = Pattern.compile(config.getString(SERVICE_ALLOW_PROPERTY, DEFAULT_SERVICE_ALLOW_PATTERN)); + serviceDenyPattern = Pattern.compile(config.getString(SERVICE_DENY_PROPERTY, DEFAULT_SERVICE_DENY_PATTERN)); + serviceAssetAllowPattern = Pattern.compile(config.getString(SERVICE_ALLOW_ASSET_PROPERTY, DEFAULT_SERVICE_ALLOW_ASSET_PATTERN)); + serviceAssetDenyPattern = Pattern.compile(config.getString(SERVICE_DENY_ASSET_PROPERTY, DEFAULT_SERVICE_DENY_ASSET_PATTERN)); + } + + /** + * access + * + * @return callback endpoint + */ + public String getCallbackEndpoint() { + return config.getString(CALLBACK_ENDPOINT); + } + + /** + * access + * + * @return the name of the default asset/graph + */ + public String getDefaultAsset() { + return config.getString(DEFAULT_ASSET_PROPERTY, DEFAULT_ASSET_NAME); + } + + public String getBusinessPartnerNumber() { + return config.getString(BUSINESS_PARTNER_NUMBER, "anonymous"); + } + + /** + * access + * + * @return initial file to load + */ + public String[] getAssetFiles() { + String[] files = config.getString(ASSET_FILE_PROPERTY, "").split(","); + if (files.length == 1 && (files[0] == null || files[0].length() == 0)) { + return null; + } + return files; + } + + /** + * access + * + * @return name of the sparql access point + */ + public String getAccessPoint() { + return config.getString(ACCESS_POINT_PROPERTY, DEFAULT_ACCESS_POINT); + } + + /** + * access + * + * @return uri of the control plane management endpoint (without concrete api) + */ + public String getControlPlaneManagementUrl() { + return config.getString(CONTROL_PLANE_MANAGEMENT, null); + } + + /** + * access + * + * @return uri of the control plane management endpoint (without concrete api) + */ + public String getControlPlaneManagementProviderUrl() { + return config.getString(CONTROL_PLANE_MANAGEMENT_PROVIDER, config.getString(CONTROL_PLANE_MANAGEMENT, null)); + } + + /** + * access + * + * @return uri of the control plane ids endpoint (without concrete api) + */ + public String getControlPlaneIdsUrl() { + return config.getString(CONTROL_PLANE_IDS, null); + } + + /** + * access + * + * @return a map of key/value paris to be used when interacting with the control plane management endpoint + */ + public Map getControlPlaneManagementHeaders() { + String key = config.getString(CONTROL_PLANE_AUTH_HEADER, "X-Api-Key"); + String value = config.getString(CONTROL_PLANE_AUTH_VALUE, null); + if (key != null && value != null) { + return Map.of(key, value); + } + return Map.of(); + } + + /** + * access + * + * @return the default overall timeout when waiting for a negotation result + */ + public long getNegotiationTimeout() { + return config.getLong(NEGOTIATION_TIMEOUT_PROPERTY, DEFAULT_NEGOTIATION_TIMEOUT); + } + + /** + * access + * + * @return the thread pool size of the agent executors + */ + public int getThreadPoolSize() { + return config.getInteger(THREAD_POOL_SIZE, DEFAULT_THREAD_POOL_SIZE); + } + + /** + * access + * + * @return the default overall timeout when waiting for a negotation result + */ + public long getNegotiationPollInterval() { + return config.getLong(NEGOTIATION_POLLINTERVAL_PROPERTY, DEFAULT_NEGOTIATION_POLLINTERVAL); + } + + /** + * access + * + * @return the synchronization interval between individual sync calls, -1 if no sync + */ + public long getDataspaceSynchronizationInterval() { + return config.getLong(DATASPACE_SYNCINTERVAL_PROPERTY, DEFAULT_DATASPACE_SYNCINTERVAL); + } + + /** + * access + * + * @return array of connector urls to synchronize, null if no sync + */ + public String[] getDataspaceSynchronizationConnectors() { + String[] connectors = config.getString(DATASPACE_SYNCCONNECTORS_PROPERTY, "").split(","); + if (connectors.length == 1 && (connectors[0] == null || connectors[0].length() == 0)) { + return null; + } + return connectors; + } + + public String getRdfStore() { + return config.getString(RDF_STORE, null); + } + + /** + * access + * + * @return array of validation endpoints + */ + public String[] getValidatorEndpoints() { + return config.getConfig(VALIDATION_ENDPOINTS).getEntries().values().toArray(new String[0]); + } + + /** + * access + * + * @return whether sparql engine is set to verbose + */ + public boolean isSparqlVerbose() { + return config.getBoolean(VERBOSE_PROPERTY, DEFAULT_VERBOSE_PROPERTY); + } + + /** + * access + * + * @return maximal batch size for remote service calls + */ + public long getFederationServiceBatchSize() { + return config.getLong(FEDERATION_SERVICE_BATCH_SIZE, DEFAULT_FEDERATION_SERVICE_BATCH_SIZE); + } + + /** + * access + * + * @return outgoing socket connect timeout + */ + public Integer getConnectTimeout() { + return config.getInteger(CONNECT_TIMEOUT_PROPERTY, null); + } + + /** + * access + * + * @return outgoing socket read timeout + */ + public Integer getReadTimeout() { + return config.getInteger(READ_TIMEOUT_PROPERTY, DEFAULT_READ_TIMEOUT); + } + + /** + * access + * + * @return outgoing socket write timeout + */ + public Integer getWriteTimeout() { + return config.getInteger(WRITE_TIMEOUT_PROPERTY, null); + } + + /** + * access + * + * @return outgoing socket write timeout + */ + public Integer getCallTimeout() { + return config.getInteger(CALL_TIMEOUT_PROPERTY, null); + } + + /** + * access + * + * @return default skill contract + */ + public String getDefaultSkillContract() { + return config.getString(DEFAULT_SKILL_CONTRACT_PROPERTY, null); + } + + /** + * access + * + * @return default graph contract + */ + public String getDefaultGraphContract() { + return config.getString(DEFAULT_GRAPH_CONTRACT_PROPERTY, null); + } + + /** + * * access + * + * @return regular expression for allowed service URLs + */ + public Pattern getServiceAllowPattern() { + return serviceAllowPattern; + } + + /** + * access + * + * @return regular expression for denied service URLs + */ + public Pattern getServiceDenyPattern() { + return serviceDenyPattern; + } + + /** + * access + * + * @return regular expression for allowed service URLs in assets + */ + public Pattern getServiceAssetAllowPattern() { + return serviceAssetAllowPattern; + } + + /** + * access + * + * @return regular expression for denied service URLs in assets + */ + public Pattern getServiceAssetDenyPattern() { + return serviceAssetDenyPattern; + } + + /** + * access + * + * @return tx edc version as a string + */ + public String getEdcVersion() { + return config.getString(TX_EDC_VERSION_PROPERTY, "0.5.0"); + } + + /** + * check + * + * @return whether the edc version is less than 23.09 + */ + public boolean isPrerelease() { + return getEdcVersion().compareTo("0.5.0") <= 0; + } + + public int getMatchmakingPortInternal() { + return config.getInteger(MATCHMAKING_PORT_INTERNAL); + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentExtension.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentExtension.java new file mode 100644 index 00000000..b5096119 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentExtension.java @@ -0,0 +1,195 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc; + +import okhttp3.OkHttpClient; +import org.apache.jena.query.Syntax; +import org.apache.jena.sparql.serializer.SerializerRegistry; +import org.apache.jena.sparql.service.ServiceExecutorRegistry; +import org.eclipse.edc.connector.dataplane.http.spi.HttpRequestParamsProvider; +import org.eclipse.edc.connector.dataplane.spi.pipeline.PipelineService; +import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.runtime.metamodel.annotation.Requires; +import org.eclipse.edc.spi.http.EdcHttpClient; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.security.Vault; +import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.edc.web.spi.WebService; +import org.eclipse.tractusx.agents.edc.http.AgentController; +import org.eclipse.tractusx.agents.edc.http.DelegationServiceImpl; +import org.eclipse.tractusx.agents.edc.http.HttpClientFactory; +import org.eclipse.tractusx.agents.edc.rdf.RdfStore; +import org.eclipse.tractusx.agents.edc.service.DataManagementImpl; +import org.eclipse.tractusx.agents.edc.service.DataspaceSynchronizer; +import org.eclipse.tractusx.agents.edc.service.EdcSkillStore; +import org.eclipse.tractusx.agents.edc.sparql.DataspaceServiceExecutor; +import org.eclipse.tractusx.agents.edc.sparql.SparqlQueryProcessor; +import org.eclipse.tractusx.agents.edc.sparql.SparqlQuerySerializerFactory; +import org.eclipse.tractusx.agents.edc.validation.SwitchingDataPlaneTokenValidatorController; + +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.regex.Pattern; + +/** + * EDC extension that initializes the Agent subsystem (Agent Sources, Agent Endpoint and Federation Callbacks + */ +@Requires(HttpRequestParamsProvider.class) +public class AgentExtension implements ServiceExtension { + + /** + * static constants + */ + protected static final String DEFAULT_CONTEXT_ALIAS = "default"; + protected static final String CALLBACK_CONTEXT_ALIAS = "callback"; + public static final Pattern GRAPH_PATTERN = Pattern.compile("((?[^#]+)#)?(?.*Graph(Asset)?.*)"); + public static final Pattern SKILL_PATTERN = Pattern.compile("((?[^#]+)#)?(?.*Skill(Asset)?.*)"); + + + /** + * dependency injection part + */ + @Inject + protected WebService webService; + + + @Inject + protected PipelineService pipelineService; + + @Inject + protected Vault vault; + + @Inject + protected TypeManager typeManager; + + // we reuse the http settings of the http transfer + @Inject + protected EdcHttpClient edcHttpClient; + @Inject + protected OkHttpClient httpClient; + + /** + * refers a scheduler + * TODO maybe reuse an injected scheduler + */ + protected ScheduledExecutorService executorService; + + /** + * data synchronization service + */ + protected DataspaceSynchronizer synchronizer; + + /** + * access + * + * @return name of the extension + */ + @Override + public String name() { + return "Knowledge Agents Extension"; + } + + /** + * runs on extension initialization + * + * @param context EDC bootstrap context + */ + @Override + public void initialize(ServiceExtensionContext context) { + Monitor monitor = context.getMonitor(); + + monitor.debug(String.format("Initializing %s", name())); + + AgentConfig config = new AgentConfig(monitor, context.getConfig()); + Map.Entry instance = HttpClientFactory.create(edcHttpClient, httpClient, pipelineService, config); + edcHttpClient = instance.getKey(); + httpClient = instance.getValue(); + + DataManagementImpl catalogService = new DataManagementImpl(monitor, typeManager, httpClient, config); + + AgreementControllerImpl agreementController = new AgreementControllerImpl(monitor, config, catalogService); + monitor.debug(String.format("Registering agreement controller %s", agreementController)); + webService.registerResource(CALLBACK_CONTEXT_ALIAS, agreementController); + + RdfStore rdfStore = new RdfStore(config, monitor); + + executorService = Executors.newScheduledThreadPool(config.getThreadPoolSize()); + synchronizer = new DataspaceSynchronizer(executorService, config, catalogService, rdfStore, monitor); + + SwitchingDataPlaneTokenValidatorController validatorController = new SwitchingDataPlaneTokenValidatorController(httpClient, config, monitor); + if (validatorController.isEnabled()) { + monitor.debug(String.format("Registering switching validator controller %s", validatorController)); + webService.registerResource(DEFAULT_CONTEXT_ALIAS, validatorController); + } + + // EDC Remoting Support + ServiceExecutorRegistry reg = new ServiceExecutorRegistry(); + reg.addBulkLink(new DataspaceServiceExecutor(monitor, agreementController, config, httpClient, executorService, typeManager)); + //reg.add(new DataspaceServiceExecutor(monitor,agreementController,config,httpClient)); + + // Ontop and other deep nesting-afraid providers/optimizers + // should be supported by not relying on the Fuseki syntax graph + SparqlQuerySerializerFactory arqQuerySerializerFactory = new SparqlQuerySerializerFactory(); + SerializerRegistry.get().addQuerySerializer(Syntax.syntaxARQ, arqQuerySerializerFactory); + SerializerRegistry.get().addQuerySerializer(Syntax.syntaxSPARQL_10, arqQuerySerializerFactory); + SerializerRegistry.get().addQuerySerializer(Syntax.syntaxSPARQL_11, arqQuerySerializerFactory); + + // the actual sparql engine inside the EDC + SparqlQueryProcessor processor = new SparqlQueryProcessor(reg, monitor, config, rdfStore, typeManager); + + // stored procedure store and transport endpoint + SkillStore skillStore = new EdcSkillStore(catalogService, typeManager, config); + DelegationServiceImpl delegationService = new DelegationServiceImpl(agreementController, monitor, httpClient, typeManager, config); + + // register endpoint /agent + AgentController agentController = new AgentController(monitor, agreementController, config, processor, skillStore, delegationService); + monitor.debug(String.format("Registering agent controller %s", agentController)); + webService.registerResource(DEFAULT_CONTEXT_ALIAS, agentController); + + // register endpoint /agentsource + //AgentSourceController agentSourceController = new AgentSourceController(monitor, config, processor, skillStore, delegationService); + //AgentSourceController agentSourceController = new AgentSourceController(monitor, config, processor, skillStore); + //monitor.debug(String.format("Registering agent source controller %s", agentSourceController)); + //webService.registerResource(DEFAULT_CONTEXT_ALIAS, agentSourceController); + + monitor.debug(String.format("Initialized %s", name())); + + // mho HttpRequestFactory httpRequestFactory = new HttpRequestFactory(); + // mho AgentSourceFactory sourceFactory = new AgentSourceFactory(edcHttpClient, new AgentSourceRequestParamsSupplier(vault, typeManager, config, monitor), monitor, httpRequestFactory, processor, skillStore); + // mho pipelineService.registerFactory(sourceFactory); + } + + /** + * start scheduled services + */ + @Override + public void start() { + synchronizer.start(); + } + + /** + * Signals the extension to release resources and shutdown. + * stop any schedules services + */ + @Override + public void shutdown() { + synchronizer.shutdown(); + } +} \ No newline at end of file diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentProtocol.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentProtocol.java new file mode 100644 index 00000000..165fe0a5 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentProtocol.java @@ -0,0 +1,36 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc; + +/** + * lists the various protocols supported + */ +public enum AgentProtocol { + + SPARQL_HTTP("cx-common:Protocol?w3c:http:SPARQL"), + SKILL_HTTP("cx-common:Protocol?w3c:http:SKILL"); + + private final String protocolId; + + AgentProtocol(String protocolId) { + this.protocolId = protocolId; + } + + public String getProtocolId() { + return protocolId; + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgreementController.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgreementController.java new file mode 100644 index 00000000..86208478 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgreementController.java @@ -0,0 +1,44 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc; + +import jakarta.ws.rs.WebApplicationException; +import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; + +/** + * Interface to any agreement controller + */ +public interface AgreementController { + + /** + * check whether an agreement for the asset already exists + * + * @param asset id of the asset + * @return endpoint data reference, null if non-existant + */ + EndpointDataReference get(String asset); + + /** + * negotiates an endpoint for the given asset + * + * @param remoteUrl the connector + * @param asset id of the asset + * @return endpoint data reference + * @throws WebApplicationException in case agreement could not be made (in time) + */ + EndpointDataReference createAgreement(String remoteUrl, String asset) throws WebApplicationException; +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgreementControllerImpl.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgreementControllerImpl.java new file mode 100644 index 00000000..5ab110b0 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgreementControllerImpl.java @@ -0,0 +1,437 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc; + +import com.nimbusds.jose.JWSObject; +import jakarta.json.JsonValue; +import jakarta.ws.rs.BadRequestException; +import jakarta.ws.rs.ClientErrorException; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.InternalServerErrorException; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.types.domain.DataAddress; +import org.eclipse.edc.spi.types.domain.callback.CallbackAddress; +import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; +import org.eclipse.tractusx.agents.edc.jsonld.JsonLd; +import org.eclipse.tractusx.agents.edc.model.ContractAgreement; +import org.eclipse.tractusx.agents.edc.model.ContractNegotiation; +import org.eclipse.tractusx.agents.edc.model.ContractNegotiationRequest; +import org.eclipse.tractusx.agents.edc.model.ContractOfferDescription; +import org.eclipse.tractusx.agents.edc.model.DcatCatalog; +import org.eclipse.tractusx.agents.edc.model.DcatDataset; +import org.eclipse.tractusx.agents.edc.model.OdrlPolicy; +import org.eclipse.tractusx.agents.edc.model.TransferProcess; +import org.eclipse.tractusx.agents.edc.model.TransferRequest; +import org.eclipse.tractusx.agents.edc.service.DataManagement; +import org.eclipse.tractusx.agents.edc.service.DataManagementImpl; +import org.eclipse.tractusx.agents.edc.service.DataspaceSynchronizer; + +import java.io.IOException; +import java.text.ParseException; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + + +/** + * An endpoint/service that receives information from the control plane + */ +@Consumes({MediaType.APPLICATION_JSON}) +@Path("/endpoint-data-reference") +public class AgreementControllerImpl implements AgreementController { + + /** + * which transfer to use + */ + public static final String TRANSFER_TYPE = "HttpProxy"; + + /** + * EDC service references + */ + protected final Monitor monitor; + protected final DataManagement dataManagement; + protected final AgentConfig config; + + /** + * memory store for links from assets to the actual transfer addresses + * TODO make this a distributed cache + * TODO let this cache evict invalidate references automatically + */ + // hosts all pending processes + protected final Set activeAssets = new HashSet<>(); + // any contract agreements indexed by asset + protected final Map agreementStore = new HashMap<>(); + // any transfer processes indexed by asset, the current process should + // always adhere to the above agreement + protected final Map processStore = new HashMap<>(); + // at the end of provisioning and endpoint reference will be set + // that fits to the current transfer process + protected final Map endpointStore = new HashMap<>(); + + /** + * creates an agreement controller + * + * @param monitor logger + * @param config typed config + * @param dataManagement data management service wrapper + */ + public AgreementControllerImpl(Monitor monitor, AgentConfig config, DataManagement dataManagement) { + this.monitor = monitor; + this.dataManagement = dataManagement; + this.config = config; + } + + /** + * render nicely + */ + @Override + public String toString() { + return super.toString() + "/endpoint-data-reference"; + } + + /** + * this is called by the control plane when an agreement has been made + * + * @param dataReference contains the actual call token + */ + @POST + public void receiveEdcCallback(EndpointDataReference dataReference) { + var agreementId = dataReference.getId(); + monitor.debug(String.format("An endpoint data reference for agreement %s has been posted.", agreementId)); + synchronized (agreementStore) { + for (Map.Entry process : processStore.entrySet()) { + if (process.getValue().getId().equals(agreementId)) { + synchronized (endpointStore) { + monitor.debug(String.format("Agreement %s belongs to asset %s.", agreementId, process.getKey())); + endpointStore.put(process.getKey(), dataReference); + return; + } + } + } + } + monitor.debug(String.format("Agreement %s has no active asset. Guess that came for another plane. Ignoring.", agreementId)); + } + + /** + * accesses an active endpoint for the given asset + * + * @param assetId id of the agreed asset + * @return endpoint found, null if not found or invalid + */ + @Override + public EndpointDataReference get(String assetId) { + synchronized (activeAssets) { + if (!activeAssets.contains(assetId)) { + monitor.debug(String.format("Asset %s is not active", assetId)); + return null; + } + synchronized (endpointStore) { + EndpointDataReference result = endpointStore.get(assetId); + if (result != null) { + String token = result.getAuthCode(); + if (token != null) { + try { + JWSObject jwt = JWSObject.parse(token); + Object expiryObject = jwt.getPayload().toJSONObject().get("exp"); + if (expiryObject instanceof Long) { + // token times are in seconds + if (!new Date((Long) expiryObject * 1000).before(new Date(System.currentTimeMillis() + 30 * 1000))) { + return result; + } + } + } catch (ParseException | NumberFormatException e) { + monitor.debug(String.format("Active asset %s has invalid agreement token.", assetId)); + } + } + endpointStore.remove(assetId); + } + monitor.debug(String.format("Active asset %s has timed out or was not installed.", assetId)); + synchronized (processStore) { + processStore.remove(assetId); + synchronized (agreementStore) { + ContractAgreement agreement = agreementStore.get(assetId); + if (agreement != null && agreement.getContractSigningDate() + 600000L <= System.currentTimeMillis()) { + agreementStore.remove(assetId); + } + activeAssets.remove(assetId); + } + } + } + } + return null; + } + + /** + * sets active + * + * @param asset name + */ + protected void activate(String asset) { + synchronized (activeAssets) { + if (activeAssets.contains(asset)) { + throw new ClientErrorException("Cannot agree on an already active asset.", Response.Status.CONFLICT); + } + activeAssets.add(asset); + } + } + + /** + * sets active + * + * @param asset name + */ + protected void deactivate(String asset) { + synchronized (activeAssets) { + activeAssets.remove(asset); + } + synchronized (agreementStore) { + agreementStore.remove(asset); + } + synchronized (processStore) { + processStore.remove(asset); + } + } + + /** + * register an agreement + * + * @param asset name + * @param agreement object + */ + protected void registerAgreement(String asset, ContractAgreement agreement) { + synchronized (agreementStore) { + agreementStore.put(asset, agreement); + } + } + + /** + * register a process + * + * @param asset name + * @param process object + */ + protected void registerProcess(String asset, TransferProcess process) { + synchronized (processStore) { + processStore.put(asset, process); + } + } + + /** + * creates a new agreement (asynchronously) + * and waits for the result + * TODO make this federation aware: multiple assets, different policies + * + * @param remoteUrl ids endpoint url of the remote connector + * @param asset name of the asset to agree upon + */ + @Override + public EndpointDataReference createAgreement(String remoteUrl, String asset) throws WebApplicationException { + monitor.debug(String.format("About to create an agreement for asset %s at connector %s", asset, remoteUrl)); + + activate(asset); + + DcatCatalog contractOffers; + + try { + contractOffers = dataManagement.findContractOffers(remoteUrl, asset); + } catch (IOException io) { + deactivate(asset); + throw new InternalServerErrorException(String.format("Error when resolving contract offers from %s for asset %s through data management api.", remoteUrl, asset), io); + } + + if (contractOffers.getDatasets().isEmpty()) { + deactivate(asset); + throw new BadRequestException(String.format("There is no contract offer in remote connector %s related to asset %s.", remoteUrl, asset)); + } + + // TODO implement a cost-based offer choice + DcatDataset contractOffer = contractOffers.getDatasets().get(0); + Map assetProperties = DataspaceSynchronizer.getProperties(contractOffer); + OdrlPolicy policy = contractOffer.hasPolicy(); + String offerId = policy.getId(); + JsonValue offerType = assetProperties.get("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"); + monitor.debug(String.format("About to create an agreement for contract offer %s (for asset %s of type %s at connector %s)", offerId, asset, + offerType, remoteUrl)); + + var contractOfferDescription = new ContractOfferDescription( + offerId, + asset, + policy + ); + var contractNegotiationRequest = ContractNegotiationRequest.Builder.newInstance() + .offerId(contractOfferDescription) + .connectorId("provider") + .connectorAddress(String.format(DataManagementImpl.DSP_PATH, remoteUrl)) + .protocol("dataspace-protocol-http") + .localBusinessPartnerNumber(config.getBusinessPartnerNumber()) + .remoteBusinessPartnerNumber(contractOffers.getParticipantId()) + .build(); + String negotiationId; + + try { + negotiationId = dataManagement.initiateNegotiation(contractNegotiationRequest); + } catch (IOException ioe) { + deactivate(asset); + throw new InternalServerErrorException(String.format("Error when initiating negotation for offer %s through data management api.", offerId), ioe); + } + + monitor.debug(String.format("About to check negotiation %s for contract offer %s (for asset %s at connector %s)", negotiationId, offerId, asset, remoteUrl)); + + // Check negotiation state + ContractNegotiation negotiation = null; + + long startTime = System.currentTimeMillis(); + + try { + while ((System.currentTimeMillis() - startTime < config.getNegotiationTimeout()) && + (negotiation == null || + (!negotiation.getState().equals("FINALIZED") && !negotiation.getState().equals("TERMINATED")))) { + Thread.sleep(config.getNegotiationPollInterval()); + negotiation = dataManagement.getNegotiation( + negotiationId + ); + } + } catch (InterruptedException e) { + monitor.info(String.format("Negotiation thread for asset %s negotiation %s has been interrupted. Giving up.", asset, negotiationId), e); + } catch (IOException e) { + monitor.warning(String.format("Negotiation thread for asset %s negotiation %s run into problem. Giving up.", asset, negotiationId), e); + } + + if (negotiation == null || !negotiation.getState().equals("FINALIZED")) { + deactivate(asset); + if (negotiation != null) { + String errorDetail = negotiation.getErrorDetail(); + if (errorDetail != null) { + monitor.severe(String.format("Contract Negotiation %s failed because of %s", negotiationId, errorDetail)); + } + } + throw new InternalServerErrorException(String.format("Contract Negotiation %s for asset %s was not successful.", negotiationId, asset)); + } + + monitor.debug(String.format("About to check agreement %s for contract offer %s (for asset %s at connector %s)", negotiation.getContractAgreementId(), offerId, asset, remoteUrl)); + + ContractAgreement agreement; + + try { + agreement = dataManagement.getAgreement(negotiation.getContractAgreementId()); + } catch (IOException ioe) { + deactivate(asset); + throw new InternalServerErrorException(String.format("Error when retrieving agreement %s for negotiation %s.", negotiation.getContractAgreementId(), negotiationId), ioe); + } + + if (agreement == null || !agreement.getAssetId().endsWith(asset)) { + deactivate(asset); + throw new InternalServerErrorException(String.format("Agreement %s does not refer to asset %s.", negotiation.getContractAgreementId(), asset)); + } + + registerAgreement(asset, agreement); + + DataAddress dataDestination = DataAddress.Builder.newInstance() + .type(TRANSFER_TYPE) + .build(); + + CallbackAddress address = + CallbackAddress.Builder.newInstance().uri(config.getCallbackEndpoint()).build(); + + TransferRequest transferRequest = TransferRequest.Builder.newInstance() + .assetId(asset) + .contractId(agreement.getId()) + .connectorId(config.getBusinessPartnerNumber()) + .connectorAddress(String.format(DataManagementImpl.DSP_PATH, remoteUrl)) + .protocol("dataspace-protocol-http") + .dataDestination(dataDestination) + .managedResources(false) + .callbackAddresses(List.of(address)) + .build(); + + monitor.debug(String.format("About to initiate transfer for agreement %s (for asset %s at connector %s)", negotiation.getContractAgreementId(), asset, remoteUrl)); + + String transferId; + + try { + transferId = dataManagement.initiateHttpProxyTransferProcess(transferRequest); + } catch (IOException ioe) { + deactivate(asset); + throw new InternalServerErrorException(String.format("HttpProxy transfer for agreement %s could not be initiated.", agreement.getId()), ioe); + } + + monitor.debug(String.format("About to check transfer %s (for asset %s at connector %s)", transferId, asset, remoteUrl)); + + // Check negotiation state + TransferProcess process = null; + + startTime = System.currentTimeMillis(); + + // EDC 0.5.1 has a problem with the checker configuration and wont process to COMPLETED + String expectedTransferState = config.isPrerelease() ? "COMPLETED" : "STARTED"; + + try { + while ((System.currentTimeMillis() - startTime < config.getNegotiationTimeout()) && (process == null || !process.getState().equals(expectedTransferState))) { + Thread.sleep(config.getNegotiationPollInterval()); + process = dataManagement.getTransfer( + transferId + ); + registerProcess(asset, process); + } + } catch (InterruptedException e) { + monitor.info(String.format("Process thread for asset %s transfer %s has been interrupted. Giving up.", asset, transferId), e); + } catch (IOException e) { + monitor.warning(String.format("Process thread for asset %s transfer %s run into problem. Giving up.", asset, transferId), e); + } + + if (process == null || !process.getState().equals(expectedTransferState)) { + deactivate(asset); + throw new InternalServerErrorException(String.format("Transfer process %s for agreement %s and asset %s could not be provisioned.", transferId, agreement.getId(), asset)); + } + + // finally wait a bit for the endpoint data reference in case + // that the process was signalled earlier than the callbacks + startTime = System.currentTimeMillis(); + + EndpointDataReference reference = null; + + try { + while ((System.currentTimeMillis() - startTime < config.getNegotiationTimeout()) && (reference == null)) { + Thread.sleep(config.getNegotiationPollInterval()); + synchronized (endpointStore) { + reference = endpointStore.get(asset); + } + } + } catch (InterruptedException e) { + monitor.info(String.format("Wait thread for reference to asset %s has been interrupted. Giving up.", asset), e); + } + + // mark the type in the endpoint + if (reference != null) { + for (Map.Entry prop : assetProperties.entrySet()) { + reference.getProperties().put(prop.getKey(), JsonLd.asString(prop.getValue())); + } + } + + // now delegate to the original getter + return get(asset); + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/MonitorWrapper.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/MonitorWrapper.java new file mode 100644 index 00000000..d3aff72f --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/MonitorWrapper.java @@ -0,0 +1,106 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc; + +import org.eclipse.edc.spi.monitor.Monitor; +import org.slf4j.Marker; +import org.slf4j.event.Level; +import org.slf4j.helpers.AbstractLogger; + +/** + * A (better) adapter to bridge slf4j to EDC logging + */ +public class MonitorWrapper extends AbstractLogger { + + final Monitor instance; + + public MonitorWrapper(String name, Monitor monitor) { + this.name = name; + this.instance = monitor; + } + + @Override + public boolean isTraceEnabled() { + return false; + } + + @Override + public boolean isTraceEnabled(Marker marker) { + return false; + } + + @Override + public boolean isDebugEnabled() { + return true; + } + + @Override + public boolean isDebugEnabled(Marker marker) { + return true; + } + + @Override + public boolean isInfoEnabled() { + return true; + } + + @Override + public boolean isInfoEnabled(Marker marker) { + return true; + } + + @Override + public boolean isWarnEnabled() { + return true; + } + + @Override + public boolean isWarnEnabled(Marker marker) { + return true; + } + + @Override + public boolean isErrorEnabled() { + return true; + } + + @Override + public boolean isErrorEnabled(Marker marker) { + return true; + } + + @Override + protected String getFullyQualifiedCallerName() { + return null; + } + + @Override + protected void handleNormalizedLoggingCall(Level level, Marker marker, String msg, Object[] arguments, Throwable throwable) { + switch (level) { + case ERROR: + instance.severe(msg, throwable); + break; + default: + case INFO: + instance.info(msg, throwable); + break; + case DEBUG: + instance.debug(msg, throwable); + break; + } + } +} \ No newline at end of file diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/SkillDistribution.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/SkillDistribution.java new file mode 100644 index 00000000..d9dd6912 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/SkillDistribution.java @@ -0,0 +1,73 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc; + +/** + * enumerates the various skill distribution/run modes + */ +public enum SkillDistribution { + CONSUMER("consumer"), + PROVIDER("provider"), + ALL("all"); + + private final String mode; + + /** + * access + * + * @param mode the textual mode + */ + SkillDistribution(final String mode) { + this.mode = mode; + } + + /** + * access + * + * @return mode a semantic value + */ + public String getDistributionMode() { + return "cx-common:SkillDistribution?run=" + this.mode; + } + + /** + * access + * + * @return mode as argument + */ + public String getMode() { + return this.mode; + } + + /** + * access + * + * @param mode as argument + * @return respective enum (or ALL if it does not fir) + */ + public static SkillDistribution valueOfMode(String mode) { + if (mode != null) { + if (mode.endsWith("consumer")) { + return CONSUMER; + } else if (mode.endsWith("provider")) { + return PROVIDER; + } + } + return ALL; + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/SkillStore.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/SkillStore.java new file mode 100644 index 00000000..1b7b3998 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/SkillStore.java @@ -0,0 +1,76 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc; + +import java.util.Optional; +import java.util.regex.Matcher; + +/** + * interface to a skill store + */ +public interface SkillStore { + + /** + * match a given asset + * + * @param key asset name + * @return matcher + */ + static Matcher matchSkill(String key) { + return AgentExtension.SKILL_PATTERN.matcher(key); + } + + /** + * check a given asset for being a skill + * + * @param key asset name + * @return whether the asset encodes a skill + */ + boolean isSkill(String key); + + /** + * register a skill + * + * @param key asset name required + * @param skill query text required + * @param name of skill optional + * @param description of skill optional + * @param version of skill optional + * @param contract of skill optional + * @param dist of skill required + * @param isFederated whether skill maybe synchronized in catalogue + * @param ontologies a set of ontologies + * @return skill id + */ + String put(String key, String skill, String name, String description, String version, String contract, SkillDistribution dist, boolean isFederated, String... ontologies); + + /** + * return the skill distribution + * + * @param key asset name + * @return skill distribution mode + */ + SkillDistribution getDistribution(String key); + + /** + * return the stored skill text + * + * @param key asset name + * @return optional skill text if registered + */ + Optional get(String key); +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/Tuple.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/Tuple.java new file mode 100644 index 00000000..d96ed7b5 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/Tuple.java @@ -0,0 +1,108 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * A tuple contains a binding of variables to a single value. + */ +public class Tuple { + + Map bindings; + + /** + * create a fresh tuple + */ + public Tuple() { + bindings = new HashMap<>(); + } + + /** + * create a tuple with existing bindings + * + * @param bindings map of variable names to string values + */ + public Tuple(Map bindings) { + this.bindings = bindings; + } + + /** + * adds a binding + * + * @param key variable name + * @param value string-based value + * @throws Exception in case the variable is already bound + */ + public void add(String key, String value) throws Exception { + if (bindings.containsKey(key)) { + throw new Exception(String.format("Cannot host several values for key %s in simple binding.", key)); + } + bindings.put(key, value); + } + + /** + * access a binding + * + * @param key variable name + * @return bound value (null of not bound) + */ + public String get(String key) { + return bindings.get(key); + } + + /** + * access + * + * @return the set of bound variables + */ + public Set getVariables() { + return bindings.keySet(); + } + + /** + * clone this tuple + * + * @return a detached tuple with the same bindings + */ + @Override + public Tuple clone() { + return new Tuple(new HashMap<>(bindings)); + } + + /** + * merges this tuple with another + * + * @param other other tuple + * @return a detached tuple with the combined bindings of this an the other tuple + */ + public Tuple merge(Tuple other) { + Map newTuple = new HashMap<>(bindings); + newTuple.putAll(other.bindings); + return new Tuple(newTuple); + } + + /** + * render this tuple + */ + @Override + public String toString() { + return "Tuple(" + bindings.toString() + ")"; + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/TupleSet.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/TupleSet.java new file mode 100644 index 00000000..586800b6 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/TupleSet.java @@ -0,0 +1,138 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc; + +import org.apache.jena.ext.com.google.common.collect.ArrayListMultimap; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Implementation of a compact representation of + * a tuple set that is the explosion of + * - multivalue bindings of individual variables + * - logical combination of several tuple sets + */ +public class TupleSet { + + ArrayListMultimap bindings = ArrayListMultimap.create(); + List explodes = new ArrayList<>(); + + /** + * add a binding to the tuple set + * + * @param key variable + * @param value string value + * @throws Exception in case that the variable is already bound in the combined tuple sets + */ + public void add(String key, String value) throws Exception { + if (explodes.stream().anyMatch(explode -> explode.hasVariable(key))) { + throw new Exception(String.format("Could not bind variable %s on higher level as it is already bound in an embedded binding.", key)); + } + bindings.put(key, value); + } + + /** + * flattens the representation + * + * @param variables a set of variables + * @return set of flat tuples. + * @throws Exception in case that the representation has unintended intersections + */ + public Collection getTuples(String... variables) throws Exception { + + List ownVars = new ArrayList<>(); + List explodedVars = new ArrayList<>(); + for (String var : variables) { + if (bindings.containsKey(var)) { + ownVars.add(var); + } else { + explodedVars.add(var); + } + } + Collection explosion = new ArrayList<>(); + for (TupleSet explode : explodes) { + explosion.addAll(explode.getTuples(explodedVars.toArray(new String[0]))); + } + if (ownVars.size() > 0) { + for (String key : ownVars) { + if (explosion.size() == 0) { + for (String value : bindings.get(key)) { + Tuple tuple = new Tuple(); + tuple.add(key, value); + explosion.add(tuple); + } + } else { + Collection nextExplosion = new ArrayList<>(); + for (String value : bindings.get(key)) { + for (Tuple yetTuple : explosion) { + Tuple tuple = yetTuple.clone(); + tuple.add(key, value); + nextExplosion.add(tuple); + } + } + explosion = nextExplosion; + } + } + } + return explosion; + } + + /** + * checks whether a particular variable is bound + * + * @param key variable name + * @return existance flag + */ + public boolean hasVariable(String key) { + return bindings.containsKey(key) || explodes.stream().anyMatch(explode -> explode.hasVariable(key)); + } + + /** + * compute the set of bound variables + * + * @return set of bound variables + */ + public Set getVariables() { + Set myVars = new HashSet<>(bindings.keySet()); + for (TupleSet explode : explodes) { + myVars.addAll(explode.getVariables()); + } + return myVars; + } + + /** + * merge another tupleset into this one + * + * @param other tupleset + */ + public void merge(TupleSet other) { + explodes.add(other); + } + + /** + * render this object + */ + @Override + public String toString() { + return "Tuple(" + bindings.toString() + "+" + Arrays.toString(explodes.toArray()) + ")"; + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentController.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentController.java new file mode 100644 index 00000000..b1cde041 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentController.java @@ -0,0 +1,487 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriInfo; +import org.apache.http.HttpStatus; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.edc.AgentExtension; +import org.eclipse.tractusx.agents.edc.AgreementController; +import org.eclipse.tractusx.agents.edc.SkillDistribution; +import org.eclipse.tractusx.agents.edc.SkillStore; +import org.eclipse.tractusx.agents.edc.sparql.SparqlQueryProcessor; + +import java.util.Optional; +import java.util.regex.Matcher; + +/** + * The Agent Controller exposes a REST API endpoint + * with which the EDC tenant can issue queries and execute + * skills in interaction with local resources and the complete + * Dataspace (the so-called Matchmaking Agent that is also hit by + * incoming Agent transfers). + * TODO exchange fixed memory store by configurable options + * TODO generalize sub-protocols from SparQL + */ +@Path("/agent") +public class AgentController { + + // EDC services + protected final Monitor monitor; + protected final AgreementController agreementController; + protected final AgentConfig config; + protected final SkillStore skillStore; + + // the actual Matchmaking Agent is a Fuseki engine + protected final SparqlQueryProcessor processor; + protected final DelegationService delegationService; + + /** + * creates a new agent controller + * + * @param monitor logging subsystem + * @param agreementController agreement controller for remote skill/queries + * @param config configuration + * @param processor sparql processor + */ + public AgentController(Monitor monitor, AgreementController agreementController, AgentConfig config, SparqlQueryProcessor processor, SkillStore skillStore, DelegationService delegationService) { + this.monitor = monitor; + this.agreementController = agreementController; + this.config = config; + this.processor = processor; + this.skillStore = skillStore; + this.delegationService = delegationService; + monitor.debug("AgentController is initialized"); + } + + /** + * render nicely + */ + @Override + public String toString() { + return super.toString() + "/agent"; + } + + /** + * endpoint for posting a sparql query (maybe as a stored skill with a bindingset) + * + * @param asset can be a named graph for executing a query or a skill asset + * @return response + */ + @POST + @Consumes({"application/sparql-query", "application/sparql-results+json"}) + public Response postSparqlQuery(@QueryParam("asset") String asset, + @Context HttpHeaders headers, + @Context HttpServletRequest request, + @Context HttpServletResponse response, + @Context UriInfo uri + ) { + monitor.debug(String.format("Received a SparQL POST request %s for asset %s", request, asset)); + return executeQuery(asset, headers, request, response, uri); + } + + /** + * endpoint for posting a url-encoded form-based query + * this is the default mode for graphdb which + * sends the actual query language and other params together + * with the query text in the body and expects a + * special content disposition in the response header which + * marks the body as a kind of file attachement. + * + * @param asset can be a named graph for executing a query or a skill asset + * @return response compatible with graphdb convention + */ + @POST + @Consumes({"application/x-www-form-urlencoded"}) + public Response postFormQuery(@QueryParam("asset") String asset, + @Context HttpHeaders headers, + @Context HttpServletRequest request, + @Context HttpServletResponse response, + @Context UriInfo uri) { + monitor.debug(String.format("Received a Form-based POST request %s for asset %s", request, asset)); + Response result = executeQuery(asset, headers, request, response, uri); + response.addHeader("Content-Disposition", "attachement; filename=query-result.srjs"); + return result; + } + + /** + * endpoint for posting a url-encoded form-based query + * this is the default mode for graphdb which + * sends the actual query language and other params together + * with the query text in the body and expects a + * special content disposition in the response header which + * marks the body as a kind of file attachement. + * + * @param asset can be a named graph for executing a query or a skill asset + * @return response compatible with graphdb convention + */ + @POST + @Path("/repositories/AGENT") + @Consumes({"application/x-www-form-urlencoded"}) + public Response postFormRepositoryQuery(@QueryParam("asset") String asset, + @Context HttpHeaders headers, + @Context HttpServletRequest request, + @Context HttpServletResponse response, + @Context UriInfo uri) { + monitor.debug(String.format("Received a Form-based POST repository request %s for asset %s", request, asset)); + Response result = executeQuery(asset, headers, request, response, uri); + response.addHeader("Content-Disposition", "attachement; filename=query-result.srjs"); + return result; + } + + /** + * endpoint for getting a query + * + * @param asset can be a named graph for executing a query or a skill asset + * @return response + */ + @GET + public Response getQuery(@QueryParam("asset") String asset, + @Context HttpHeaders headers, + @Context HttpServletRequest request, + @Context HttpServletResponse response, + @Context UriInfo uri) { + monitor.debug(String.format("Received a GET request %s for asset %s", request, asset)); + return executeQuery(asset, headers, request, response, uri); + } + + /** + * 2nd endpoint for getting a query + * + * @param asset can be a named graph for executing a query or a skill asset + * @return response + */ + @GET + @Path("/repositories/AGENT") + public Response getRepositoryQuery(@QueryParam("asset") String asset, + @Context HttpHeaders headers, + @Context HttpServletRequest request, + @Context HttpServletResponse response, + @Context UriInfo uri) { + monitor.debug(String.format("Received a GET repository request %s for asset %s", request, asset)); + return executeQuery(asset, headers, request, response, uri); + } + + /** + * check import status + * + * @return response + */ + @GET + @Path("/repositories/AGENT/import/active") + public Response getRepositoryImportQuery( + @Context HttpServletRequest request + ) { + monitor.debug(String.format("Received a GET repository import active request %s", request)); + return Response.status(406, "Not Acceptable (HTTP status 406)").build(); + } + + /** + * check size + * + * @return response + */ + @GET + @Path("/rest/repositories/AGENT/size") + public Response getRestRepositorySizeQuery( + @Context HttpServletRequest request + ) { + monitor.debug(String.format("Received a GET rest repository size request %s", request)); + return Response.ok("{\n" + + " \"inferred\": 70,\n" + + " \"total\": 70,\n" + + " \"explicit\": 0\n" + + "}").type(jakarta.ws.rs.core.MediaType.APPLICATION_JSON_TYPE).build(); + } + + /** + * check size + * + * @return response + */ + @GET + @Path("/repositories/AGENT/size") + public Response getRepositorySizeQuery( + @Context HttpServletRequest request + ) { + monitor.debug(String.format("Received a GET repository size request %s", request)); + return Response.ok("0").type(jakarta.ws.rs.core.MediaType.APPLICATION_JSON_TYPE).build(); + } + + /** + * check import status + * + * @return response + */ + @GET + @Path("/rest/repositories/AGENT/import/active") + public Response getRestRepositoryImportQuery( + @Context HttpServletRequest request + ) { + monitor.debug(String.format("Received a GET rest repository import active request %s", request)); + return Response.ok("0").type(jakarta.ws.rs.core.MediaType.APPLICATION_JSON_TYPE).build(); + } + + /** + * return version info for graphdb/fedx integration + * + * @return version string + */ + @GET + @Path("/rest/info/version") + public String getVersion( + @Context HttpServletRequest request + ) { + monitor.debug(String.format("Received a GET Version request %s", request)); + return "0.8.4"; + } + + /** + * return protocol info for graphdb/fedx integration + * + * @return protocol string + */ + @GET + @Path("/protocol") + public String getProtocol( + @Context HttpServletRequest request + ) { + monitor.debug(String.format("Received a GET Protocol request %s", request)); + return "12"; + } + + /** + * return version info for graphdb/fedx integration + * + * @return version string + */ + @GET + @Path("/rest/locations/id") + public String getId( + @Context HttpServletRequest request + ) { + monitor.debug(String.format("Received a GET Id request %s", request)); + return "Catena-X Knowledge Agent"; + } + + /** + * return repositories for graphdb/fedx integration + * + * @return single repo as json + */ + @GET + @Path("/rest/repositories") + public String getRestRepositories( + @Context HttpServletRequest request, + @Context UriInfo uri + ) { + monitor.debug(String.format("Received a GET Rest Repositories request %s", request)); + String url = uri.getAbsolutePath().toString(); + url = url.substring(0, url.length() - 18); + url = HttpUtils.urlEncode(url); + return "[\n" + + " {\n" + + " \"id\": \"AGENT\",\n" + + " \"title\": \"Catena-X Knowledge Agent Dataspace Endpoint\",\n" + + " \"uri\": \"" + url + "\",\n" + + " \"externalUrl\": \"" + url + "\",\n" + + " \"local\": false,\n" + + " \"type\": \"fuseki\",\n" + + " \"sesameType\": \"cx:AgentController\",\n" + + " \"location\": \"Catena-X Dev Dataspace\",\n" + + " \"readable\": true,\n" + + " \"writable\": true,\n" + + " \"unsupported\": false,\n" + + " \"state\": \"RUNNING\"\n" + + " }\n" + + "]"; + } + + /** + * return repositories for graphdb/fedx integration + * + * @return single repo as csv + */ + @GET + @Path("/repositories") + public Response getRepositories( + @Context HttpServletRequest request, + @Context UriInfo uri + ) { + monitor.debug(String.format("Received a GET Repositories request %s", request)); + String url = uri.getAbsolutePath().toString(); + url = url.substring(0, url.length() - 13); + url = HttpUtils.urlEncode(url); + Response.ResponseBuilder builder = Response.ok("uri,id,title,readable,writable\n" + url + ",AGENT,Catena-X Knowledge Agent Dataspace Endpoint,true,true\n"); + builder.type("text/csv;charset=UTF-8"); + builder.header("Content-Disposition", "attachment; filename=repositories.csv"); + return builder.build(); + } + + /** + * return repositories for graphdb/fedx integration + * + * @return single repo as csv + */ + @GET + @Path("/repositories/AGENT/namespaces") + public Response getNamespaces( + @Context HttpServletRequest request + ) { + monitor.debug(String.format("Received a GET Namespaces request %s", request)); + Response.ResponseBuilder builder = Response.ok("prefix,namespace\n" + + "rdf,http://www.w3.org/1999/02/22-rdf-syntax-ns#\n" + + "owl,http://www.w3.org/2002/07/owl#\n" + + "xsd,http://www.w3.org/2001/XMLSchema#\n" + + "rdfs,http://www.w3.org/2000/01/rdf-schema#\n" + + "cx,https://w3id.org/catenax/ontology#\n"); + builder.type("text/csv;charset=UTF-8"); + builder.header("Content-Disposition", "attachment; filename=namespaces.csv"); + return builder.build(); + } + + /** + * the actual execution is done by delegating to the Fuseki engine + * + * @param asset target graph + * @return a response + */ + public Response executeQuery(String asset, HttpHeaders headers, HttpServletRequest request, HttpServletResponse response, UriInfo uri) { + String skill = null; + String graph = null; + String remoteUrl = null; + + if (asset != null) { + Matcher matcher = AgentExtension.GRAPH_PATTERN.matcher(asset); + if (matcher.matches()) { + remoteUrl = matcher.group("url"); + graph = matcher.group("graph"); + } else { + matcher = SkillStore.matchSkill(asset); + if (!matcher.matches()) { + return Response.status(Response.Status.BAD_REQUEST).build(); + } + remoteUrl = matcher.group("url"); + skill = matcher.group("skill"); + } + } + + if (remoteUrl != null) { + // we need to delegate to the agent under remote URL + DelegationResponse intermediateResponse = delegationService.executeQueryRemote(remoteUrl, skill, graph, headers, request, response, uri); + // in case runMode = provider the response already contains the final result + if (intermediateResponse.getQueryString() == null) { + return intermediateResponse.getResponse(); + } else { + // in case runMode = consumer we set the skill text to the downloaded text and advance + skill = intermediateResponse.getQueryString(); + asset = null; + } + } + + try { + // exchange skill against text + if (asset != null) { + if (skillStore.isSkill(asset)) { + Optional skillOption = skillStore.get(asset); + if (skillOption.isPresent()) { + skill = skillOption.get(); + } else { + return HttpUtils.respond(monitor, headers, HttpStatus.SC_NOT_FOUND, "The requested skill is not registered.", null); + } + } + } + + processor.execute(request, response, skill, graph); + // kind of redundant, but javax.ws.rs likes it this way + return Response.status(response.getStatus()).build(); + } catch (WebApplicationException e) { + return HttpUtils.respond(monitor, headers, e.getResponse().getStatus(), e.getMessage(), e.getCause()); + } + } + + /** + * endpoint for posting a skill + * + * @param query mandatory query + * @param asset asset key + * @param name asset name + * @param description asset description + * @param version asset version + * @param contract asset contract + * @param mode asset mode + * @param isFederated whether it appears in fed catalogue + * @param ontologies list of ontologies + * @return only status + */ + @POST + @Path("/skill") + @Consumes({ "application/sparql-query" }) + public Response postSkill(String query, + @QueryParam("asset") String asset, + @QueryParam("assetName") String name, + @QueryParam("assetDescription") String description, + @QueryParam("assetVersion") String version, + @QueryParam("contract") String contract, + @QueryParam("distributionMode") SkillDistribution mode, + @QueryParam("isFederated") boolean isFederated, + @QueryParam("ontology") String[] ontologies + ) { + monitor.debug(String.format("Received a POST skill request %s %s %s %s %s %b %s ", asset, name, description, version, contract, mode.getMode(), isFederated, query)); + Response.ResponseBuilder rb; + if (skillStore.put(asset, query, name, description, version, contract, mode, isFederated, ontologies) != null) { + rb = Response.ok(); + } else { + rb = Response.status(HttpStatus.SC_CREATED); + } + return rb.build(); + } + + /** + * endpoint for getting a skill + * + * @param asset can be a named graph for executing a query or a skill asset + * @return response + */ + @GET + @Path("/skill") + @Produces({"application/sparql-query"}) + public Response getSkill(@QueryParam("asset") String asset) { + monitor.debug(String.format("Received a GET skill request %s", asset)); + Response.ResponseBuilder rb; + String query = skillStore.get(asset).orElse(null); + if (query == null) { + rb = Response.status(HttpStatus.SC_NOT_FOUND); + } else { + rb = Response.ok(query); + } + return rb.build(); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentHttpAction.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentHttpAction.java new file mode 100644 index 00000000..4c802ce1 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentHttpAction.java @@ -0,0 +1,170 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import org.apache.http.HttpStatus; +import org.apache.jena.fuseki.servlets.HttpAction; +import org.apache.jena.fuseki.system.ActionCategory; +import org.eclipse.tractusx.agents.edc.TupleSet; +import org.slf4j.Logger; + +import java.net.URLDecoder; +import java.util.Iterator; +import java.util.Stack; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import static java.nio.charset.StandardCharsets.UTF_8; + + +/** + * HttpAction which may either contain + * a query or a predefined skill. In each case + * the parameterization/input binding can be done either by + * url parameters, by a binding set body or both. + */ +public class AgentHttpAction extends HttpAction { + final String skill; + final String graphs; + final TupleSet tupleSet = new TupleSet(); + + /** + * regexes to deal with url parameters + */ + public static final String URL_PARAM_REGEX = "(?[^=&]+)=(?[^&]+)"; + public static final Pattern URL_PARAM_PATTERN = Pattern.compile(URL_PARAM_REGEX); + public static final String RESULTSET_CONTENT_TYPE = "application/sparql-results+json"; + + /** + * creates a new http action + * + * @param id call id + * @param logger the used logging output + * @param request servlet input + * @param response servlet output + * @param skill option skill reference + */ + public AgentHttpAction(long id, Logger logger, HttpServletRequest request, HttpServletResponse response, String skill, String graphs) { + super(id, logger, ActionCategory.ACTION, request, response); + this.skill = skill; + this.graphs = graphs; + parseArgs(request, response); + parseBody(request, response); + } + + /** + * parses parameters + */ + protected void parseArgs(HttpServletRequest request, HttpServletResponse response) { + String params = ""; + String uriParams = request.getQueryString(); + if (uriParams != null) { + params = URLDecoder.decode(uriParams, UTF_8); + } + Matcher paramMatcher = URL_PARAM_PATTERN.matcher(params); + Stack ts = new Stack<>(); + ts.push(tupleSet); + while (paramMatcher.find()) { + String key = paramMatcher.group("key"); + String value = paramMatcher.group("value"); + while (key.startsWith("(")) { + key = key.substring(1); + ts.push(new TupleSet()); + } + if (key.length() <= 0) { + response.setStatus(HttpStatus.SC_BAD_REQUEST); + return; + } + String realValue = value.replace(")", ""); + if (value.length() <= 0) { + response.setStatus(HttpStatus.SC_BAD_REQUEST); + return; + } + try { + if (!"asset".equals(key) && !"query".equals(key)) { + ts.peek().add(key, realValue); + } + } catch (Exception e) { + response.setStatus(HttpStatus.SC_BAD_REQUEST); + return; + } + while (value.endsWith(")")) { + TupleSet set1 = ts.pop(); + ts.peek().merge(set1); + value = value.substring(0, value.length() - 1); + } + } + } + + /** + * parses the body + */ + protected void parseBody(HttpServletRequest request, HttpServletResponse response) { + if (RESULTSET_CONTENT_TYPE.equals(request.getContentType())) { + ObjectMapper om = new ObjectMapper(); + try { + JsonNode bindingSet = om.readTree(request.getInputStream()); + ArrayNode bindings = ((ArrayNode) bindingSet.get("results").get("bindings")); + for (int count = 0; count < bindings.size(); count++) { + TupleSet ts = new TupleSet(); + JsonNode binding = bindings.get(count); + Iterator vars = binding.fieldNames(); + while (vars.hasNext()) { + String var = vars.next(); + JsonNode value = binding.get(var).get("value"); + ts.add(var, value.textValue()); + } + tupleSet.merge(ts); + } + } catch (Exception e) { + response.setStatus(HttpStatus.SC_BAD_REQUEST); + } + } + } + + /** + * access + * + * @return optional skill + */ + public String getSkill() { + return skill; + } + + /** + * access + * + * @return optional skill + */ + public String getGraphs() { + return graphs; + } + + /** + * access + * + * @return the actual input bindings + */ + public TupleSet getInputBindings() { + return tupleSet; + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationResponse.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationResponse.java new file mode 100644 index 00000000..3d691b5b --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationResponse.java @@ -0,0 +1,73 @@ +// Copyright (c) 2023, 2024 T-Systems International GmbH +// Copyright (c) 2023 ,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import jakarta.ws.rs.core.Response; + +/** + * A wrapper around the response of a + * call to another agent in the dataspace + * Depending on the run mode (provider/consumer), + * this response could optionally host the text of + * a skill to be executed locally. + */ +public class DelegationResponse { + protected final String queryString; + protected final Response response; + + /** + * Construct a new wrapper response for runMode = consumer + * + * @param queryString downloaded text of the skill + * @param response the response Object to return + */ + public DelegationResponse(String queryString, Response response) { + this.queryString = queryString; + this.response = response; + } + + /** + * Construct a new wrapper response for runMode = provider + * + * @param response the response Object to return + */ + public DelegationResponse(Response response) { + this.response = response; + this.queryString = null; + } + + /** + * access + * + * @return downloaded text of skill (should be not null if runMode = consumer) + */ + public String getQueryString() { + return queryString; + } + + /** + * access + * + * @return the response Object to return (should be not null in each case) + */ + public Response getResponse() { + return response; + } + + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationService.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationService.java new file mode 100644 index 00000000..6bdd4237 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationService.java @@ -0,0 +1,43 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.UriInfo; + +/** + * interface to a service that may + * delegate agent http calls into the + * dataspace + */ +public interface DelegationService { + /** + * delegate the given call into the dataspace + * + * @param remoteUrl target EDC + * @param skill name of the remote skill (may be empty, then graph must be set) + * @param graph name of the remote graph (may be empty, then skill must be set) + * @param headers url call headers + * @param request url request + * @param response final response + * @param uri original uri + * @return an intermediate response which may contain a textual skill to be executed locally otherwise the actual result has already been put into the final response's state + */ + DelegationResponse executeQueryRemote(String remoteUrl, String skill, String graph, HttpHeaders headers, HttpServletRequest request, HttpServletResponse response, UriInfo uri); +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationServiceImpl.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationServiceImpl.java new file mode 100644 index 00000000..16d9d2c2 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationServiceImpl.java @@ -0,0 +1,367 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import com.fasterxml.jackson.core.type.TypeReference; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriInfo; +import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpStatus; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; +import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.edc.AgreementController; +import org.eclipse.tractusx.agents.edc.sparql.CatenaxWarning; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * A service that may delegate an incoming + * agent http request ot another agent in the + * dataspace + * deals with the special case of remote/provided (textual) + * skills which should be executed locally nevertheless + */ +public class DelegationServiceImpl implements DelegationService { + + protected final AgreementController agreementController; + protected final Monitor monitor; + protected final OkHttpClient client; + public static final TypeReference> WARNING_TYPE_REFERENCE = new TypeReference<>(){}; + protected final TypeManager typeManager; + protected final AgentConfig config; + + /** + * creates a new delegation service + * + * @param agreementController EDC agreement helper + * @param monitor logging facility + * @param client outgoing http infrastructure + */ + public DelegationServiceImpl(AgreementController agreementController, Monitor monitor, OkHttpClient client, TypeManager typeManager, AgentConfig config) { + this.agreementController = agreementController; + this.monitor = monitor; + this.client = client; + this.typeManager = typeManager; + this.config = config; + } + + /** + * the actual execution is done by delegating to the Dataspace + * + * @param remoteUrl remote connector + * @param skill target skill + * @param graph target graph + * @return a wrapped response which indicates the runMode that the execution should be done + */ + public DelegationResponse executeQueryRemote(String remoteUrl, String skill, String graph, HttpHeaders headers, HttpServletRequest request, HttpServletResponse response, UriInfo uri) { + Pattern serviceAllowPattern = config.getServiceAllowPattern(); + if (!serviceAllowPattern.matcher(remoteUrl).matches()) { + return new DelegationResponse(HttpUtils.respond(monitor, headers, HttpStatus.SC_FORBIDDEN, String.format("Service %s does not match the allowed service pattern %s", remoteUrl, serviceAllowPattern.pattern()), null)); + } + Pattern serviceDenyPattern = config.getServiceDenyPattern(); + if (serviceDenyPattern.matcher(remoteUrl).matches()) { + return new DelegationResponse(HttpUtils.respond(monitor, headers, HttpStatus.SC_FORBIDDEN, String.format("Service %s matches the denied service pattern %s", remoteUrl, serviceDenyPattern.pattern()), null)); + } + String asset = skill != null ? skill : graph; + EndpointDataReference endpoint = agreementController.get(asset); + if (endpoint == null) { + try { + endpoint = agreementController.createAgreement(remoteUrl, asset); + } catch (WebApplicationException e) { + return new DelegationResponse(HttpUtils.respond(monitor, headers, e.getResponse().getStatus(), String.format("Could not get an agreement from connector %s to asset %s", remoteUrl, asset), e.getCause())); + } + } + if (endpoint == null) { + return new DelegationResponse(HttpUtils.respond(monitor, headers, HttpStatus.SC_FORBIDDEN, String.format("Could not get an agreement from connector %s to asset %s", remoteUrl, asset), null)); + } + if ("GET".equals(request.getMethod())) { + try { + return sendGetRequest(endpoint, "", headers, response, uri); + } catch (IOException e) { + return new DelegationResponse(HttpUtils.respond(monitor, headers, HttpStatus.SC_INTERNAL_SERVER_ERROR, String.format("Could not delegate remote GET call to connector %s asset %s", remoteUrl, asset), e)); + } + } else if ("POST".equals(request.getMethod())) { + try { + return sendPostRequest(endpoint, "", headers, request, response, uri); + } catch (IOException e) { + return new DelegationResponse(HttpUtils.respond(monitor, headers, HttpStatus.SC_INTERNAL_SERVER_ERROR, String.format("Could not delegate remote POST call to connector %s asset %s", remoteUrl, asset), e)); + } + } else { + return new DelegationResponse(HttpUtils.respond(monitor, headers, HttpStatus.SC_METHOD_NOT_ALLOWED, String.format("%s calls to connector %s asset %s are not allowed", request.getMethod(), remoteUrl, asset), null)); + } + + } + + /** + * route a get request + * + * @param dataReference the encoded call embedding + * @param subUrl protocol-specific part + * @return a wrapped response which indicates the runMode that the execution should be done + * @throws IOException in case something strange happens + */ + public DelegationResponse sendGetRequest(EndpointDataReference dataReference, String subUrl, HttpHeaders headers, HttpServletResponse response, UriInfo uri) throws IOException { + var url = getUrl(dataReference.getEndpoint(), subUrl, headers, uri); + + monitor.debug(String.format("About to delegate GET %s", url)); + + var requestBuilder = new okhttp3.Request.Builder() + .url(url); + + if (dataReference.getAuthKey() != null) { + requestBuilder = requestBuilder.addHeader(dataReference.getAuthKey(), Objects.requireNonNull(dataReference.getAuthCode())); + } + + var newRequest = requestBuilder.build(); + + return new DelegationResponse(sendRequest(newRequest, response), Response.status(response.getStatus()).build()); + } + + /** + * route a post request + * + * @param dataReference the encoded call embedding + * @param subUrl protocol-specific part + * @return a wrapped response which indicates the runMode that the execution should be done + * @throws IOException in case something strange happens + */ + public DelegationResponse sendPostRequest(EndpointDataReference dataReference, String subUrl, HttpHeaders headers, HttpServletRequest request, HttpServletResponse response, UriInfo uri) throws IOException { + var url = getUrl(dataReference.getEndpoint(), subUrl, headers, uri); + + String contentType = request.getContentType(); + okhttp3.MediaType parsedContentType = okhttp3.MediaType.parse(contentType); + + monitor.debug(String.format("About to delegate POST %s with content type %s", url, contentType)); + + var requestBuilder = new okhttp3.Request.Builder() + .url(url) + .addHeader("Content-Type", contentType); + + if (dataReference.getAuthKey() != null) { + requestBuilder = requestBuilder.addHeader(dataReference.getAuthKey(), Objects.requireNonNull(dataReference.getAuthCode())); + } + + requestBuilder.post(okhttp3.RequestBody.create(request.getInputStream().readAllBytes(), parsedContentType)); + + var newRequest = requestBuilder.build(); + + return new DelegationResponse(sendRequest(newRequest, response), Response.status(response.getStatus()).build()); + } + + protected static final Pattern PARAMETER_KEY_ALLOW = Pattern.compile("^(?!asset$)[^&?=]+$"); + protected static final Pattern PARAMETER_VALUE_ALLOW = Pattern.compile("^.+$"); + + /** + * computes the url to target the given data plane + * + * @param connectorUrl data plane url + * @param subUrl sub-path to use + * @param headers containing additional info that we need to wrap into a transfer request + * @return typed url + */ + protected HttpUrl getUrl(String connectorUrl, String subUrl, HttpHeaders headers, UriInfo uri) { + var url = connectorUrl; + + // EDC public api slash problem + if (!url.endsWith("/") && !url.contains("#")) { + url = url + "/"; + } + + if (subUrl != null && !subUrl.isEmpty()) { + url = url + subUrl; + } + + HttpUrl.Builder httpBuilder = Objects.requireNonNull(okhttp3.HttpUrl.parse(url)).newBuilder(); + for (Map.Entry> param : uri.getQueryParameters().entrySet()) { + String key = param.getKey(); + if (PARAMETER_KEY_ALLOW.matcher(key).matches()) { + for (String value : param.getValue()) { + if (PARAMETER_VALUE_ALLOW.matcher(value).matches()) { + String recodeKey = HttpUtils.urlEncodeParameter(key); + String recodeValue = HttpUtils.urlEncodeParameter(value); + httpBuilder = httpBuilder.addQueryParameter(recodeKey, recodeValue); + } + } + } + } + + List mediaTypes = headers.getAcceptableMediaTypes(); + if (mediaTypes.isEmpty() || mediaTypes.stream().anyMatch(MediaType.APPLICATION_JSON_TYPE::isCompatible)) { + httpBuilder = httpBuilder.addQueryParameter("cx_accept", HttpUtils.urlEncodeParameter("application/json")); + } else { + String mediaParam = mediaTypes.stream().map(MediaType::toString).collect(Collectors.joining(", ")); + mediaParam = HttpUtils.urlEncodeParameter(mediaParam); + httpBuilder.addQueryParameter("cx_accept", mediaParam); + } + return httpBuilder.build(); + } + + /** + * generic sendRequest method which extracts the result string of textual responses + * + * @param request predefined request + * @param response the final response + * @return the text of a downloaded skill if runMode = consumer, null otherwise + * @throws IOException in case something goes wrong + */ + protected String sendRequest(okhttp3.Request request, HttpServletResponse response) throws IOException { + try (var myResponse = client.newCall(request).execute()) { + + if (!myResponse.isSuccessful()) { + monitor.warning(String.format("Data plane call was not successful: %s", myResponse.code())); + } + + Optional> warnings = Optional.empty(); + + var body = myResponse.body(); + + if (body != null) { + okhttp3.MediaType contentType = body.contentType(); + InputStream inputStream = new BufferedInputStream(body.byteStream()); + + // + // Analyze whether this response contains a multipart body + // while maintaining the state of the inputstream (mark/reset approach) + // + inputStream.mark(2); + byte[] boundaryBytes = new byte[2]; + String boundary = ""; + if (inputStream.read(boundaryBytes) > 0) { + boundary = new String(boundaryBytes); + } + inputStream.reset(); + if ("--".equals(boundary)) { + // + // Multipart Case separates the actual result (last part) from the warnings (first part) + // + if (contentType != null) { + int boundaryIndex; + boundaryIndex = contentType.toString().indexOf(";boundary="); + if (boundaryIndex >= 0) { + boundary = boundary + contentType.toString().substring(boundaryIndex + 10); + } + } + StringBuilder nextPart = null; + String embeddedContentType = null; + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + for (String line = reader.readLine(); line != null; line = reader.readLine()) { + if (boundary.equals(line)) { + if (nextPart != null && embeddedContentType != null) { + if (embeddedContentType.equals("application/cx-warnings+json")) { + List nextWarnings = typeManager.readValue(nextPart.toString(), WARNING_TYPE_REFERENCE); + if (warnings.isPresent()) { + warnings.get().addAll(nextWarnings); + } else { + warnings = Optional.of(nextWarnings); + } + } else { + inputStream = new ByteArrayInputStream(nextPart.toString().getBytes()); + contentType = okhttp3.MediaType.parse(embeddedContentType); + } + } + nextPart = new StringBuilder(); + String contentLine = reader.readLine(); + if (contentLine != null && contentLine.startsWith("Content-Type: ")) { + embeddedContentType = contentLine.substring(14); + } else { + embeddedContentType = null; + } + } else if (nextPart != null) { + nextPart.append(line); + nextPart.append("\n"); + } + } + reader.close(); + // multipart parsing through, now look at the actual result in the last part + if (nextPart != null && embeddedContentType != null) { + // is it a downloaded skill text? + if (embeddedContentType.equals("application/sparql-query")) { + // immediately return + return nextPart.toString(); + } else if (embeddedContentType.equals("application/cx-warnings+json")) { + // is it a trailing warnings structure + List nextWarnings = typeManager.readValue(nextPart.toString(), WARNING_TYPE_REFERENCE); + if (warnings.isPresent()) { + warnings.get().addAll(nextWarnings); + } else { + warnings = Optional.of(nextWarnings); + } + } else { + // it is a normal "result" that we take as the actual response + inputStream = new ByteArrayInputStream(nextPart.toString().getBytes()); + contentType = okhttp3.MediaType.parse(embeddedContentType); + } + } + } + // if we got a simple skill text as answer (not multipart) + if (contentType.toString().equals("application/sparql-query")) { + // return the skill text + return IOUtils.toString(inputStream, Charset.defaultCharset()); + } + // else set the response status a + response.setStatus(myResponse.code()); + // and the response headers (including the completed warnings + for (String header : myResponse.headers().names()) { + for (String value : myResponse.headers().values(header)) { + if (header.equals("cx_warnings")) { + List nextWarnings = typeManager.getMapper().readValue(value, WARNING_TYPE_REFERENCE); + if (nextWarnings != null) { + if (warnings.isPresent()) { + warnings.get().addAll(nextWarnings); + } else { + warnings = Optional.of(nextWarnings); + } + } + } else if (!header.equalsIgnoreCase("content-length")) { + response.addHeader(header, value); + } + } + } + warnings.ifPresent(catenaxWarnings -> response.addHeader("cx_warnings", typeManager.writeValueAsString(catenaxWarnings))); + if (contentType != null) { + response.setContentType(contentType.toString()); + } + // and finally copy the body from intermediate response to final response + IOUtils.copy(inputStream, response.getOutputStream()); + inputStream.close(); + } + } + return null; + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/GraphController.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/GraphController.java new file mode 100644 index 00000000..5a452044 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/GraphController.java @@ -0,0 +1,158 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.ResponseBuilder; +import jakarta.ws.rs.core.UriInfo; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.edc.rdf.ExternalFormat; +import org.eclipse.tractusx.agents.edc.rdf.RdfStore; +import org.eclipse.tractusx.agents.edc.service.DataManagement; + +import java.io.IOException; + +/** + * The Graph Controller exposes a REST API endpoint + * with which the EDC tenant can manage graph content + * which can be published as assets. + */ +@Path("/graph") +public class GraphController { + + // EDC services + protected final Monitor monitor; + protected final RdfStore store; + protected final DataManagement management; + protected final AgentConfig config; + + /** + * creates a new agent controller + * + * @param monitor logging subsystem + * @param store the rdf store to extend + */ + public GraphController(Monitor monitor, RdfStore store, DataManagement management, AgentConfig config) { + this.monitor = monitor; + this.store = store; + this.management = management; + this.config = config; + } + + /** + * render nicely + */ + @Override + public String toString() { + return super.toString() + "/graph"; + } + + /** + * endpoint for posting a ttl into a local graph asset + * + * @param content mandatory content + * @param asset asset key + * @param name asset name + * @param description asset description + * @param version asset version + * @param contract asset contract + * @param shape asset shape + * @param isFederated whether it appears in fed catalogue + * @param ontologies list of ontologies + * @return response indicating the number of triples updated + */ + @POST + @Consumes({"text/turtle", "text/csv"}) + public Response postAsset(String content, + @QueryParam("asset") String asset, + @QueryParam("assetName") String name, + @QueryParam("assetDescription") String description, + @QueryParam("assetVersion") String version, + @QueryParam("contract") String contract, + @QueryParam("shape") String shape, + @QueryParam("isFederated") boolean isFederated, + @QueryParam("ontology") String[] ontologies, + @Context HttpServletRequest request + ) { + ExternalFormat format = ExternalFormat.valueOfFormat(request.getContentType()); + monitor.debug(String.format("Received a POST asset request %s %s %s %s %s %b in format %s", asset, name, description, version, contract, shape, isFederated, format)); + if (format == null) { + return Response.status(Response.Status.BAD_REQUEST).build(); + } + try { + if (name == null) { + name = "No name given"; + } + if (description == null) { + description = "No description given"; + } + if (version == null) { + version = "unknown version"; + } + if (contract == null) { + contract = config.getDefaultGraphContract(); + } + String ontologiesString = String.join(", ", ontologies); + if (shape == null) { + shape = String.format("@prefix : <%s#> .\\n", asset); + } + management.createOrUpdateGraph(asset, name, description, version, contract, ontologiesString, shape, isFederated); + long reg = store.registerAsset(asset, content, format); + MediaType med = MediaType.APPLICATION_JSON_TYPE; + ResponseBuilder resBuild = Response.ok(reg, med); + Response res = resBuild.build(); + return res; + //return Response.ok(store.registerAsset(asset, content, format), MediaType.APPLICATION_JSON_TYPE).build(); + } catch (IOException e) { + return Response.status(Response.Status.BAD_REQUEST).build(); + } + } + + /** + * endpoint for deleting a local graph asset + * + * @param asset can be a named graph for executing a query or a skill asset + * @return response + */ + @DELETE + public Response deleteAsset(@QueryParam("asset") String asset, + @Context HttpHeaders headers, + @Context HttpServletRequest request, + @Context HttpServletResponse response, + @Context UriInfo uri + ) { + monitor.debug(String.format("Received a DELETE request %s for asset %s", request, asset)); + try { + management.deleteAsset(asset); + return Response.ok(store.deleteAsset(asset), MediaType.APPLICATION_JSON_TYPE).build(); + } catch (IOException e) { + return Response.status(Response.Status.BAD_REQUEST).build(); + } + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientAdapter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientAdapter.java new file mode 100644 index 00000000..fdde30e7 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientAdapter.java @@ -0,0 +1,177 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import okhttp3.Call; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +import java.io.IOException; +import java.net.Authenticator; +import java.net.CookieHandler; +import java.net.ProxySelector; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.ByteBuffer; +import java.time.Duration; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.Flow; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; + +/** + * Wrapper that hides OkHttpClient behind a java.net.http.HttpClient + */ +public class HttpClientAdapter extends HttpClient { + + protected final OkHttpClient delegate; + + /** + * creates a new wrapper + * + * @param delegate the real client + */ + public HttpClientAdapter(OkHttpClient delegate) { + this.delegate = delegate; + } + + + @Override + public Optional cookieHandler() { + return Optional.empty(); + } + + @Override + public Optional connectTimeout() { + return Optional.empty(); + } + + @Override + public Redirect followRedirects() { + return null; + } + + @Override + public Optional proxy() { + return Optional.empty(); + } + + @Override + public SSLContext sslContext() { + return null; + } + + @Override + public SSLParameters sslParameters() { + return null; + } + + @Override + public Optional authenticator() { + return Optional.empty(); + } + + @Override + public Version version() { + return null; + } + + @Override + public Optional executor() { + return Optional.empty(); + } + + @Override + public HttpResponse send(HttpRequest request, HttpResponse.BodyHandler responseBodyHandler) throws IOException, InterruptedException { + var builder = new Request.Builder(); + request.headers().map().forEach((key, values) -> values.forEach(value -> builder.header(key, value))); + if (request.bodyPublisher().isPresent()) { + var bodyPublisher = request.bodyPublisher().get(); + + var subscriber = new Flow.Subscriber() { + + private ByteBuffer body; + private Throwable problem; + private boolean ready; + + @Override + public void onSubscribe(Flow.Subscription subscription) { + subscription.request(bodyPublisher.contentLength()); + } + + @Override + public void onNext(ByteBuffer item) { + if (body == null) { + body = item; + } else if (item != null) { + ByteBuffer combined = ByteBuffer.allocate(body.capacity() + item.capacity()); + combined.put(body); + combined.put(item); + combined.flip(); + body = combined; + } + } + + @Override + public void onError(Throwable throwable) { + problem = throwable; + } + + @Override + public void onComplete() { + ready = true; + } + }; + + bodyPublisher.subscribe(subscriber); + long startTime = System.currentTimeMillis(); + while (System.currentTimeMillis() - startTime < 2000 && !subscriber.ready) { + Thread.sleep(100); + } + if (!subscriber.ready) { + throw new IOException("Could not wrap request because body cannot be read"); + } + if (subscriber.problem != null) { + throw new IOException("Could not wrap request because body cannot be read", subscriber.problem); + } + builder.method(request.method(), RequestBody.create(subscriber.body.array(), MediaType.parse(request.headers().firstValue("Content-Type").get()))); + } else { + builder.method(request.method(), null); + } + builder.url(request.uri().toURL()); + Request okRequest = builder.build(); + Call okCall = delegate.newCall(okRequest); + Response okResponse = okCall.execute(); + return (HttpResponse) new HttpResponseAdapter(okResponse, request); + } + + @Override + public CompletableFuture> sendAsync(HttpRequest request, HttpResponse.BodyHandler responseBodyHandler) { + throw new UnsupportedOperationException("sendAsync"); + } + + @Override + public CompletableFuture> sendAsync(HttpRequest request, HttpResponse.BodyHandler responseBodyHandler, HttpResponse.PushPromiseHandler pushPromiseHandler) { + throw new UnsupportedOperationException("sendAsync"); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientFactory.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientFactory.java new file mode 100644 index 00000000..e8f08a61 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientFactory.java @@ -0,0 +1,134 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import okhttp3.OkHttpClient; +import org.eclipse.edc.connector.dataplane.spi.pipeline.DataSourceFactory; +import org.eclipse.edc.connector.dataplane.spi.pipeline.PipelineService; +import org.eclipse.edc.spi.http.EdcHttpClient; +import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Field; +import java.util.AbstractMap; +import java.util.Collection; +import java.util.Map; +import java.util.Optional; + +/** + * Extended Http Client Factory which has configurable timeouts + */ +public class HttpClientFactory { + + protected static Class httpDataSourceFactory; + protected static Field sourceFactories; + protected static Field httpClient; + protected static Field okHttpClient; + protected static Field connectTimeoutMillis; + protected static Field callTimeoutMillis; + protected static Field readTimeoutMillis; + protected static Field writeTimeoutMillis; + protected static Field pingIntervalMillis; + + static { + try { + sourceFactories = HttpClientFactory.class.getClassLoader().loadClass("org.eclipse.edc.connector.dataplane.framework.pipeline.PipelineServiceImpl").getDeclaredField("sourceFactories"); + sourceFactories.setAccessible(true); + httpDataSourceFactory = HttpClientFactory.class.getClassLoader().loadClass("org.eclipse.edc.connector.dataplane.http.pipeline.HttpDataSourceFactory"); + httpClient = httpDataSourceFactory.getDeclaredField("httpClient"); + httpClient.setAccessible(true); + okHttpClient = HttpClientFactory.class.getClassLoader().loadClass("org.eclipse.edc.connector.core.base.EdcHttpClientImpl").getDeclaredField("okHttpClient"); + okHttpClient.setAccessible(true); + connectTimeoutMillis = OkHttpClient.class.getDeclaredField("connectTimeoutMillis"); + connectTimeoutMillis.setAccessible(true); + readTimeoutMillis = OkHttpClient.class.getDeclaredField("readTimeoutMillis"); + readTimeoutMillis.setAccessible(true); + writeTimeoutMillis = OkHttpClient.class.getDeclaredField("writeTimeoutMillis"); + writeTimeoutMillis.setAccessible(true); + pingIntervalMillis = OkHttpClient.class.getDeclaredField("pingIntervalMillis"); + pingIntervalMillis.setAccessible(true); + callTimeoutMillis = OkHttpClient.class.getDeclaredField("pingIntervalMillis"); + callTimeoutMillis.setAccessible(true); + } catch (ClassNotFoundException | NoSuchFieldException e) { + System.err.println("HttpClientFactory could not be initialised. Leaving default okhttp settings."); + } + } + + /** + * Create an modified OkHttpClient instance + * + * @param config agent config + * @param client parent/blueprint instance + * @return the modified OkHttpClient + */ + @NotNull + public static Map.Entry create(EdcHttpClient edcClient, OkHttpClient client, PipelineService service, AgentConfig config) { + Integer connectTimeout = config.getConnectTimeout(); + Integer readTimeout = config.getReadTimeout(); + Integer callTimeout = config.getCallTimeout(); + Integer writeTimeout = config.getWriteTimeout(); + + if (connectTimeout != null || readTimeout != null || callTimeout != null || writeTimeout != null) { + try { + edcClient = ((Collection) sourceFactories.get(service)).stream().flatMap(factory -> { + if (httpDataSourceFactory.equals(factory.getClass())) { + try { + return Optional.of((EdcHttpClient) httpClient.get(factory)).stream(); + } catch (IllegalArgumentException | IllegalAccessException e) { + System.err.println("HttpClientFactory could not reuse okhttp client."); + } + } + return Optional.empty().stream(); + } + ).findFirst().orElse(edcClient); + client = (OkHttpClient) okHttpClient.get(edcClient); + } catch (IllegalArgumentException | IllegalAccessException e) { + System.err.println("HttpClientFactory could not reuse okhttp client."); + } + if (connectTimeoutMillis != null && connectTimeout != null) { + try { + connectTimeoutMillis.set(client, connectTimeout); + } catch (IllegalArgumentException | IllegalAccessException e) { + System.err.println("HttpClientFactory could not set connectTimeout"); + } + } + if (readTimeoutMillis != null && readTimeout != null) { + try { + readTimeoutMillis.set(client, readTimeout); + } catch (IllegalArgumentException | IllegalAccessException e) { + System.err.println("HttpClientFactory could not set readTimeout"); + } + } + if (callTimeoutMillis != null && callTimeout != null) { + try { + callTimeoutMillis.set(client, callTimeout); + } catch (IllegalArgumentException | IllegalAccessException e) { + System.err.println("HttpClientFactory could not set callTimeout"); + } + } + if (writeTimeoutMillis != null && writeTimeout != null) { + try { + writeTimeoutMillis.set(client, writeTimeout); + } catch (IllegalArgumentException | IllegalAccessException e) { + System.err.println("HttpClientFactory could not set writeTimeout"); + } + } + } + return new AbstractMap.SimpleEntry(edcClient, client); + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpResponseAdapter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpResponseAdapter.java new file mode 100644 index 00000000..34b500b6 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpResponseAdapter.java @@ -0,0 +1,89 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import okhttp3.Response; +import okhttp3.ResponseBody; + +import java.io.InputStream; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpHeaders; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.Optional; +import javax.net.ssl.SSLSession; + +/** + * wraps OkHttp Response to java.net.http version + */ +public class HttpResponseAdapter implements HttpResponse { + + Response delegate; + HttpHeaders headers; + HttpRequest request; + + public HttpResponseAdapter(Response delegate, HttpRequest request) { + this.delegate = delegate; + this.request = request; + headers = HttpHeaders.of(delegate.headers().toMultimap(), (key, value) -> true); + } + + @Override + public int statusCode() { + return delegate.code(); + } + + @Override + public HttpRequest request() { + return request; + } + + @Override + public Optional> previousResponse() { + return Optional.empty(); + } + + @Override + public HttpHeaders headers() { + return headers; + } + + @Override + public InputStream body() { + ResponseBody body = delegate.body(); + if (body != null) { + return body.byteStream(); + } + return null; + } + + @Override + public Optional sslSession() { + return Optional.empty(); + } + + @Override + public URI uri() { + return request.uri(); + } + + @Override + public HttpClient.Version version() { + return HttpClient.Version.HTTP_1_1; + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletContextAdapter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletContextAdapter.java new file mode 100644 index 00000000..decd58a2 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletContextAdapter.java @@ -0,0 +1,347 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import okhttp3.Request; + +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.EventListener; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import javax.servlet.Filter; +import javax.servlet.FilterRegistration; +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; +import javax.servlet.SessionCookieConfig; +import javax.servlet.SessionTrackingMode; +import javax.servlet.descriptor.JspConfigDescriptor; + +/** + * Servlet context adapter which hides a mock okhttp request + */ +public class HttpServletContextAdapter implements ServletContext { + + Request request; + protected final Map attributes = new HashMap<>(); + + public HttpServletContextAdapter(Request request) { + this.request = request; + } + + @Override + public String getContextPath() { + return ""; + } + + @Override + public ServletContext getContext(String uripath) { + return this; + } + + @Override + public int getMajorVersion() { + return 1; + } + + @Override + public int getMinorVersion() { + return 1; + } + + @Override + public int getEffectiveMajorVersion() { + return 1; + } + + @Override + public int getEffectiveMinorVersion() { + return 1; + } + + @Override + public String getMimeType(String file) { + return null; + } + + @Override + public Set getResourcePaths(String path) { + return null; + } + + @Override + public URL getResource(String path) throws MalformedURLException { + return null; + } + + @Override + public InputStream getResourceAsStream(String path) { + return null; + } + + @Override + public RequestDispatcher getRequestDispatcher(String path) { + return null; + } + + @Override + public RequestDispatcher getNamedDispatcher(String name) { + return null; + } + + @Override + public Servlet getServlet(String name) throws ServletException { + return null; + } + + @Override + public Enumeration getServlets() { + return null; + } + + @Override + public Enumeration getServletNames() { + return null; + } + + @Override + public void log(String msg) { + + } + + @Override + public void log(Exception exception, String msg) { + + } + + @Override + public void log(String message, Throwable throwable) { + + } + + @Override + public String getRealPath(String path) { + return null; + } + + @Override + public String getServerInfo() { + return null; + } + + @Override + public String getInitParameter(String name) { + return null; + } + + @Override + public Enumeration getInitParameterNames() { + return null; + } + + @Override + public boolean setInitParameter(String name, String value) { + return false; + } + + @Override + public Object getAttribute(String name) { + return attributes.get(name); + } + + @Override + public Enumeration getAttributeNames() { + return Collections.enumeration(attributes.keySet()); + } + + @Override + public void setAttribute(String name, Object object) { + attributes.put(name, object); + } + + @Override + public void removeAttribute(String name) { + attributes.remove(name); + } + + @Override + public String getServletContextName() { + return null; + } + + @Override + public ServletRegistration.Dynamic addServlet(String servletName, String className) { + return null; + } + + @Override + public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) { + return null; + } + + @Override + public ServletRegistration.Dynamic addServlet(String servletName, Class servletClass) { + return null; + } + + @Override + public ServletRegistration.Dynamic addJspFile(String servletName, String jspFile) { + return null; + } + + @Override + public T createServlet(Class clazz) throws ServletException { + return null; + } + + @Override + public ServletRegistration getServletRegistration(String servletName) { + return null; + } + + @Override + public Map getServletRegistrations() { + return null; + } + + @Override + public FilterRegistration.Dynamic addFilter(String filterName, String className) { + return null; + } + + @Override + public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) { + return null; + } + + @Override + public FilterRegistration.Dynamic addFilter(String filterName, Class filterClass) { + return null; + } + + @Override + public T createFilter(Class clazz) throws ServletException { + return null; + } + + @Override + public FilterRegistration getFilterRegistration(String filterName) { + return null; + } + + @Override + public Map getFilterRegistrations() { + return null; + } + + @Override + public SessionCookieConfig getSessionCookieConfig() { + return null; + } + + @Override + public void setSessionTrackingModes(Set sessionTrackingModes) { + + } + + @Override + public Set getDefaultSessionTrackingModes() { + return null; + } + + @Override + public Set getEffectiveSessionTrackingModes() { + return null; + } + + @Override + public void addListener(String className) { + + } + + @Override + public void addListener(T t) { + + } + + @Override + public void addListener(Class listenerClass) { + + } + + @Override + public T createListener(Class clazz) throws ServletException { + return null; + } + + @Override + public JspConfigDescriptor getJspConfigDescriptor() { + return null; + } + + @Override + public ClassLoader getClassLoader() { + return null; + } + + @Override + public void declareRoles(String... roleNames) { + + } + + @Override + public String getVirtualServerName() { + return null; + } + + @Override + public int getSessionTimeout() { + return 0; + } + + @Override + public void setSessionTimeout(int sessionTimeout) { + + } + + @Override + public String getRequestCharacterEncoding() { + return null; + } + + @Override + public void setRequestCharacterEncoding(String encoding) { + + } + + @Override + public String getResponseCharacterEncoding() { + return null; + } + + @Override + public void setResponseCharacterEncoding(String encoding) { + + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletRequestAdapter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletRequestAdapter.java new file mode 100644 index 00000000..a0c71696 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletRequestAdapter.java @@ -0,0 +1,433 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import okhttp3.Request; +import okio.Buffer; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import javax.servlet.AsyncContext; +import javax.servlet.DispatcherType; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpUpgradeHandler; +import javax.servlet.http.Part; + +/** + * Wraps an ok Request into a javax servlet request + */ +public class HttpServletRequestAdapter implements HttpServletRequest { + + protected final Request request; + protected final ServletContext context; + + public HttpServletRequestAdapter(Request request, ServletContext context) { + this.request = request; + this.context = context; + } + + @Override + public String getAuthType() { + return null; + } + + @Override + public Cookie[] getCookies() { + return new Cookie[0]; + } + + @Override + public long getDateHeader(String name) { + return 0; + } + + @Override + public String getHeader(String name) { + return request.header(name); + } + + @Override + public Enumeration getHeaders(String name) { + return Collections.enumeration(request.headers().values(name)); + } + + @Override + public Enumeration getHeaderNames() { + return Collections.enumeration(request.headers().names()); + } + + @Override + public int getIntHeader(String name) { + try { + return Integer.parseInt(request.header(name)); + } catch (NumberFormatException nfe) { + throw new RuntimeException(nfe); + } + } + + @Override + public String getMethod() { + return request.method(); + } + + @Override + public String getPathInfo() { + return request.url().encodedPath(); + } + + @Override + public String getPathTranslated() { + return request.url().encodedPath(); + } + + @Override + public String getContextPath() { + return request.url().encodedPath(); + } + + @Override + public String getQueryString() { + return request.url().query(); + } + + @Override + public String getRemoteUser() { + return null; + } + + @Override + public boolean isUserInRole(String role) { + return false; + } + + @Override + public Principal getUserPrincipal() { + return null; + } + + @Override + public String getRequestedSessionId() { + return null; + } + + @Override + public String getRequestURI() { + return request.url().uri().toString(); + } + + @Override + public StringBuffer getRequestURL() { + return new StringBuffer(request.url().url().toString()); + } + + @Override + public String getServletPath() { + return ""; + } + + @Override + public HttpSession getSession(boolean create) { + return null; + } + + @Override + public HttpSession getSession() { + return null; + } + + @Override + public String changeSessionId() { + return null; + } + + @Override + public boolean isRequestedSessionIdValid() { + return false; + } + + @Override + public boolean isRequestedSessionIdFromCookie() { + return false; + } + + @Override + public boolean isRequestedSessionIdFromURL() { + return false; + } + + @Override + public boolean isRequestedSessionIdFromUrl() { + return false; + } + + @Override + public boolean authenticate(HttpServletResponse response) throws IOException, ServletException { + return false; + } + + @Override + public void login(String username, String password) throws ServletException { + + } + + @Override + public void logout() throws ServletException { + + } + + @Override + public Collection getParts() throws IOException, ServletException { + return List.of(); + } + + @Override + public Part getPart(String name) throws IOException, ServletException { + return null; + } + + @Override + public T upgrade(Class handlerClass) throws IOException, ServletException { + return null; + } + + @Override + public Object getAttribute(String name) { + return context.getAttribute(name); + } + + @Override + public Enumeration getAttributeNames() { + return context.getAttributeNames(); + } + + @Override + public String getCharacterEncoding() { + return null; + } + + @Override + public void setCharacterEncoding(String env) throws UnsupportedEncodingException { + + } + + @Override + public int getContentLength() { + try { + return (int) request.body().contentLength(); + } catch (IOException e) { + return -1; + } + } + + @Override + public long getContentLengthLong() { + try { + return request.body().contentLength(); + } catch (IOException e) { + return -1L; + } + } + + @Override + public String getContentType() { + var body = request.body(); + if (body != null) { + var contentType = body.contentType(); + if (contentType != null) { + return contentType.toString(); + } + } + return null; + } + + @Override + public ServletInputStream getInputStream() throws IOException { + Buffer buffer = new Buffer(); + request.body().writeTo(buffer); + ByteArrayInputStream bais = new ByteArrayInputStream(buffer.readByteArray()); + return new ServletInputStreamDelegator(bais); + } + + @Override + public String getParameter(String name) { + return request.url().queryParameter(name); + } + + @Override + public Enumeration getParameterNames() { + return Collections.enumeration(request.url().queryParameterNames()); + } + + @Override + public String[] getParameterValues(String name) { + return request.url().queryParameterValues(name).toArray(new String[0]); + } + + @Override + public Map getParameterMap() { + Map parameterMap = new HashMap<>(); + for (String queryParameterName : request.url().queryParameterNames()) { + parameterMap.put(queryParameterName, getParameterValues(queryParameterName)); + } + return parameterMap; + } + + @Override + public String getProtocol() { + return request.url().isHttps() ? "HTTPS" : "HTTP"; + } + + @Override + public String getScheme() { + return request.url().scheme(); + } + + @Override + public String getServerName() { + return request.url().host(); + } + + @Override + public int getServerPort() { + return request.url().port(); + } + + @Override + public BufferedReader getReader() throws IOException { + return new BufferedReader(new StringReader(request.body().toString())); + } + + @Override + public String getRemoteAddr() { + return request.url().fragment(); + } + + @Override + public String getRemoteHost() { + return request.url().host(); + } + + @Override + public void setAttribute(String name, Object o) { + context.setAttribute(name, o); + } + + @Override + public void removeAttribute(String name) { + context.removeAttribute(name); + } + + @Override + public Locale getLocale() { + return null; + } + + @Override + public Enumeration getLocales() { + return null; + } + + @Override + public boolean isSecure() { + return false; + } + + @Override + public RequestDispatcher getRequestDispatcher(String path) { + return null; + } + + @Override + public String getRealPath(String path) { + return null; + } + + @Override + public int getRemotePort() { + return request.url().port(); + } + + @Override + public String getLocalName() { + return ""; + } + + @Override + public String getLocalAddr() { + return ""; + } + + @Override + public int getLocalPort() { + return 0; + } + + @Override + public ServletContext getServletContext() { + return context; + } + + @Override + public AsyncContext startAsync() throws IllegalStateException { + return null; + } + + @Override + public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException { + return null; + } + + @Override + public boolean isAsyncStarted() { + return false; + } + + @Override + public boolean isAsyncSupported() { + return false; + } + + @Override + public AsyncContext getAsyncContext() { + return null; + } + + @Override + public DispatcherType getDispatcherType() { + return null; + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletResponseAdapter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletResponseAdapter.java new file mode 100644 index 00000000..7a6733bb --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletResponseAdapter.java @@ -0,0 +1,238 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import okhttp3.MediaType; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Collection; +import java.util.Locale; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; + +/** + * builds a ok response from an in-memory servlet response implementation + */ +public class HttpServletResponseAdapter implements HttpServletResponse { + + Response.Builder builder = new Response.Builder(); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ServletOutputStream sos = new ServletOutputStreamDelegator(bos); + + String contentType; + long contentLength; + + public HttpServletResponseAdapter(Request request) { + builder.request(request); + builder.protocol(Protocol.HTTP_1_1); + } + + @Override + public void addCookie(Cookie cookie) { + } + + @Override + public boolean containsHeader(String name) { + return false; + } + + @Override + public String encodeURL(String url) { + return null; + } + + @Override + public String encodeRedirectURL(String url) { + return null; + } + + @Override + public String encodeUrl(String url) { + return null; + } + + @Override + public String encodeRedirectUrl(String url) { + return null; + } + + @Override + public void sendError(int sc, String msg) throws IOException { + + } + + @Override + public void sendError(int sc) throws IOException { + + } + + @Override + public void sendRedirect(String location) throws IOException { + + } + + @Override + public void setDateHeader(String name, long date) { + builder.header(name, String.valueOf(date)); + } + + @Override + public void addDateHeader(String name, long date) { + builder.addHeader(name, String.valueOf(date)); + } + + @Override + public void setHeader(String name, String value) { + builder.header(name, value); + } + + @Override + public void addHeader(String name, String value) { + builder.addHeader(name, value); + } + + @Override + public void setIntHeader(String name, int value) { + builder.header(name, String.valueOf(value)); + } + + @Override + public void addIntHeader(String name, int value) { + builder.addHeader(name, String.valueOf(value)); + } + + @Override + public void setStatus(int sc) { + builder.code(sc).message(String.format("Status %d", sc)); + } + + @Override + public void setStatus(int sc, String sm) { + builder.code(sc).message(sm); + } + + @Override + public int getStatus() { + return builder.build().code(); + } + + @Override + public String getHeader(String name) { + return builder.build().header(name); + } + + @Override + public Collection getHeaders(String name) { + return builder.build().headers().values(name); + } + + @Override + public Collection getHeaderNames() { + return builder.build().headers().names(); + } + + @Override + public String getCharacterEncoding() { + return null; + } + + @Override + public String getContentType() { + return contentType; + } + + @Override + public ServletOutputStream getOutputStream() throws IOException { + return sos; + } + + @Override + public PrintWriter getWriter() throws IOException { + return new PrintWriter(bos); + } + + @Override + public void setCharacterEncoding(String charset) { + } + + @Override + public void setContentLength(int len) { + contentLength = len; + } + + @Override + public void setContentLengthLong(long len) { + contentLength = len; + } + + @Override + public void setContentType(String type) { + contentType = type; + } + + @Override + public void setBufferSize(int size) { + } + + @Override + public int getBufferSize() { + return 0; + } + + @Override + public void flushBuffer() throws IOException { + } + + @Override + public void resetBuffer() { + } + + @Override + public boolean isCommitted() { + return false; + } + + @Override + public void reset() { + + } + + @Override + public void setLocale(Locale loc) { + + } + + @Override + public Locale getLocale() { + return null; + } + + public Response toResponse() { + if (contentType != null) { + ResponseBody body = ResponseBody.create(bos.toByteArray(), MediaType.parse(contentType)); + builder.body(body); + } + return builder.build(); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpUtils.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpUtils.java new file mode 100644 index 00000000..dfcfb02e --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpUtils.java @@ -0,0 +1,160 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response; +import org.eclipse.edc.spi.monitor.Monitor; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; + +/** + * Utilities to deal with Http Protocol stuff + */ +public class HttpUtils { + + public static final String DEFAULT_ENCODING = System.getProperty("fis.encoding", "UTF-8"); + + /** + * ensure that the given parameter string is correctly + * encoded + * + * @param pattern maybe undecoded patterm + * @return a url encoded string + */ + public static String urlEncode(String pattern) { + try { + return URLEncoder.encode(pattern, DEFAULT_ENCODING); + } catch (UnsupportedEncodingException e) { + // this should never happen + return pattern; + } + } + + /** + * ensure that the given parameter string is correctly + * encoded + * TODO optimize + * + * @param parameter maybe undecoded parameter + * @return a url encoded string which additionally encodes some URL-prefix related symbols + */ + public static String urlEncodeParameter(String parameter) { + if (parameter == null || parameter.length() == 0) return ""; + try { + parameter = urlDecodeParameter(parameter); + return encodeParameter(urlEncode(parameter)); + } catch (UnsupportedEncodingException e) { + // this should never happen + return parameter; + } + } + + /** + * ensure that the given parameter string is correctly decoded + * + * @param parameter maybe encoded parameter + * @return a url decoded string + */ + public static String urlDecodeParameter(String parameter) { + if (parameter == null || parameter.length() == 0) return ""; + try { + return URLDecoder.decode(parameter, DEFAULT_ENCODING); + } catch (UnsupportedEncodingException e) { + // this should never happen + return parameter; + } + } + + /** + * ensure that the given parameter string is correctly + * encoded + * TODO optimize + * + * @param parameter maybe undecoded parameter + * @return a url encoded string which additionally encodes some URL-prefix related symbols + */ + public static String encodeParameter(String parameter) throws UnsupportedEncodingException { + if (parameter == null || parameter.length() == 0) return ""; + return parameter.replace("?", "%3F") + .replace("=", "%3D") + .replace("{", "%7B") + .replace("}", "%7D") + .replace("/", "%2F"); + } + + /** + * creates a response from a given setting + * depending on the accept type + * + * @param monitor logging system to save the reference error + * @param headers of the request + * @param message error message + * @param cause error object + * @return http response with the right body and reference to the logging subsystem + */ + public static Response respond(Monitor monitor, HttpHeaders headers, int status, String message, Throwable cause) { + int messageCode = message.hashCode(); + if (monitor != null) { + if (cause != null) { + monitor.warning(String.format("Response with error id %d delivered message %s under cause %s", messageCode, message, cause.getMessage()), cause); + } else { + monitor.warning(String.format("Response with error id %d delivered message %s", messageCode, message)); + } + } + var builder = Response.status(status); + String accept = headers.getHeaderString("Accept"); + if (accept == null || accept.length() == 0) { + accept = "*/*"; + } + if (accept.contains("*/*")) { + accept = "application/json"; + } + if (accept.contains("application/json")) { + builder.type("application/json"); + builder.entity("{ " + + "\"status\":" + String.valueOf(status) + "," + + "\"message\":\"" + messageCode + "\" }"); + } else if (accept.contains("text/xml") || accept.contains("application/xml")) { + builder.type(accept.contains("text/xml") ? "text/xml" : "application/xml"); + builder.entity(" " + + "" + String.valueOf(status) + "" + + "" + messageCode + " "); + } else if (accept.contains("text/html")) { + builder.type("text/html"); + builder.entity("\n" + + "\n" + + "\n" + + " Agent Subsystem Error\n" + + "\n" + + "\n" + + "\n" + + "

An Problem has occured in the Catena-X Agent subsystem.

\n" + + "

Status: " + String.valueOf(status) + "

\n" + + "

" + messageCode + "

\n" + + "\n" + + "\n" + + ""); + } else { + builder.type("text/plain"); + builder.entity(messageCode); + } + return builder.build(); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapter.java new file mode 100644 index 00000000..46772340 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapter.java @@ -0,0 +1,92 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import org.eclipse.edc.spi.monitor.Monitor; + +import java.lang.reflect.Proxy; + +/** + * An invocation handler which maps all jakarta objects + * to a javax.servlet level + */ +public interface JakartaAdapter { + + /** + * access + * + * @return the wrapper object + */ + TARGET getDelegate(); + + /** + * access + * + * @return EDC logging support + */ + Monitor getMonitor(); + + /** + * unwrap logic + * + * @param types array of type annotations + * @param args array of objects + * @return unwrapped array of objects + * @throws Throwable in case something strange happens + */ + @SuppressWarnings("rawtypes") + static Object[] unwrap(Class[] types, Object[] args) throws Throwable { + if (args == null) args = new Object[0]; + for (int count = 0; count < args.length; count++) { + if (types[count].getCanonicalName().startsWith("javax.servlet") && args[count] != null) { + JakartaAdapter wrapper; + if (args[count] instanceof JakartaAdapter) { + wrapper = (JakartaAdapter) args[count]; + } else { + // we assume its a proxy + wrapper = (JakartaAdapter) Proxy.getInvocationHandler(args[count]); + } + args[count] = wrapper.getDelegate(); + Class jakartaClass = JakartaAdapter.class.getClassLoader().loadClass(types[count].getCanonicalName().replace("javax.servlet", "jakarta.servlet")); + types[count] = jakartaClass; + } + } + return args; + } + + /** + * wrap logic + * + * @param jakarta original object + * @param javaxClass target interfaces + * @param monitor EDC loggin subsystem + * @param target interfaces as generics + * @return wrapped object + */ + static TARGET javaxify(Object jakarta, Class javaxClass, Monitor monitor) { + if (javax.servlet.ServletInputStream.class.equals(javaxClass)) { + return (TARGET) new JakartaServletInputStreamAdapter((jakarta.servlet.ServletInputStream) jakarta, monitor); + } + if (javax.servlet.ServletOutputStream.class.equals(javaxClass)) { + return (TARGET) new JakartaServletOutputStreamAdapter((jakarta.servlet.ServletOutputStream) jakarta, monitor); + } + return (TARGET) Proxy.newProxyInstance(JakartaAdapterImpl.class.getClassLoader(), + new Class[]{ javaxClass }, + new JakartaAdapterImpl(jakarta, monitor)); + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapterImpl.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapterImpl.java new file mode 100644 index 00000000..0b38ae6f --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapterImpl.java @@ -0,0 +1,62 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import org.eclipse.edc.spi.monitor.Monitor; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +/** + * An invocation handler which maps all jakarta objects + * to a javax.servlet level + */ +public class JakartaAdapterImpl implements InvocationHandler, JakartaAdapter { + + Object jakartaDelegate; + Monitor monitor; + + public JakartaAdapterImpl(Object jakartaDelegate, Monitor monitor) { + this.jakartaDelegate = jakartaDelegate; + this.monitor = monitor; + } + + @Override + public Object getDelegate() { + return jakartaDelegate; + } + + @Override + public Monitor getMonitor() { + return monitor; + } + + @SuppressWarnings("rawtypes") + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Class[] types = method.getParameterTypes(); + args = JakartaAdapter.unwrap(types, args); + Method targetMethod = jakartaDelegate.getClass().getMethod(method.getName(), types); + Object result = targetMethod.invoke(jakartaDelegate, args); + //monitor.debug(String.format("Jakarta wrapper mapped method %s to target method %s on args %s with result %s",method,targetMethod,Arrays.toString(args),result)); + if ((!method.getReturnType().isAssignableFrom(targetMethod.getReturnType())) && result != null) { + result = JakartaAdapter.javaxify(result, method.getReturnType(), monitor); + } + return result; + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletInputStreamAdapter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletInputStreamAdapter.java new file mode 100644 index 00000000..c624c373 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletInputStreamAdapter.java @@ -0,0 +1,80 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import jakarta.servlet.ServletInputStream; +import org.eclipse.edc.spi.monitor.Monitor; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import javax.servlet.ReadListener; + +/** + * An invocation handler which maps all jakarta input stream + * to a javax.servlet level + */ +public class JakartaServletInputStreamAdapter extends javax.servlet.ServletInputStream implements JakartaAdapter { + + jakarta.servlet.ServletInputStream jakartaDelegate; + Monitor monitor; + + public JakartaServletInputStreamAdapter(jakarta.servlet.ServletInputStream jakartaDelegate, Monitor monitor) { + this.jakartaDelegate = jakartaDelegate; + this.monitor = monitor; + } + + @Override + public jakarta.servlet.ServletInputStream getDelegate() { + return jakartaDelegate; + } + + @Override + public Monitor getMonitor() { + return monitor; + } + + @Override + public boolean isFinished() { + return jakartaDelegate.isFinished(); + } + + @Override + public boolean isReady() { + return jakartaDelegate.isReady(); + } + + @Override + public void setReadListener(ReadListener readListener) { + //jakartaDelegate.setReadListener(readListener); + } + + @Override + public int read() throws IOException { + return jakartaDelegate.read(); + } + + @Override + public int read(byte @NotNull [] buf) throws IOException { + return jakartaDelegate.read(buf); + } + + @Override + public int read(byte @NotNull [] b, int off, int len) throws IOException { + return jakartaDelegate.read(b, off, len); + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletOutputStreamAdapter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletOutputStreamAdapter.java new file mode 100644 index 00000000..1b694772 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletOutputStreamAdapter.java @@ -0,0 +1,75 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import jakarta.servlet.ServletOutputStream; +import org.eclipse.edc.spi.monitor.Monitor; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import javax.servlet.WriteListener; + +/** + * An invocation handler which maps jakarta output stream + * to a javax.servlet level + */ +public class JakartaServletOutputStreamAdapter extends javax.servlet.ServletOutputStream implements JakartaAdapter { + + jakarta.servlet.ServletOutputStream jakartaDelegate; + Monitor monitor; + + public JakartaServletOutputStreamAdapter(jakarta.servlet.ServletOutputStream jakartaDelegate, Monitor monitor) { + this.jakartaDelegate = jakartaDelegate; + this.monitor = monitor; + } + + @Override + public jakarta.servlet.ServletOutputStream getDelegate() { + return jakartaDelegate; + } + + @Override + public Monitor getMonitor() { + return monitor; + } + + @Override + public boolean isReady() { + return jakartaDelegate.isReady(); + } + + @Override + public void setWriteListener(WriteListener writeListener) { + // TODO Auto-generated method stub + } + + @Override + public void write(int b) throws IOException { + jakartaDelegate.write(b); + } + + @Override + public void write(byte @NotNull [] b) throws IOException { + jakartaDelegate.write(b); + } + + @Override + public void write(byte @NotNull [] b, int off, int len) throws IOException { + jakartaDelegate.write(b, off, len); + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletInputStreamDelegator.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletInputStreamDelegator.java new file mode 100644 index 00000000..d72936ae --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletInputStreamDelegator.java @@ -0,0 +1,88 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import java.io.IOException; +import java.io.InputStream; +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; + +/** + * Delegating servlet input stream into a simple input stream + */ +public class ServletInputStreamDelegator extends ServletInputStream { + + private final InputStream sourceStream; + + private boolean finished = false; + + + /** + * Create a DelegatingServletInputStream for the given source stream. + * + * @param sourceStream the source stream (never {@code null}) + */ + public ServletInputStreamDelegator(InputStream sourceStream) { + this.sourceStream = sourceStream; + } + + /** + * Return the underlying source stream (never {@code null}). + * + * @return input stream + */ + public final InputStream getSourceStream() { + return this.sourceStream; + } + + + @Override + public int read() throws IOException { + int data = this.sourceStream.read(); + if (data == -1) { + this.finished = true; + } + return data; + } + + @Override + public int available() throws IOException { + return this.sourceStream.available(); + } + + @Override + public void close() throws IOException { + super.close(); + this.sourceStream.close(); + } + + @Override + public boolean isFinished() { + return this.finished; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(ReadListener readListener) { + throw new UnsupportedOperationException(); + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletOutputStreamDelegator.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletOutputStreamDelegator.java new file mode 100644 index 00000000..47ef06df --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletOutputStreamDelegator.java @@ -0,0 +1,59 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http; + +import java.io.IOException; +import java.io.OutputStream; +import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; + +/** + * delegates a servlet output stream to a simple outputstream + */ +public class ServletOutputStreamDelegator extends ServletOutputStream { + + final OutputStream delegate; + + public ServletOutputStreamDelegator(OutputStream delegate) { + this.delegate = delegate; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setWriteListener(WriteListener writeListener) { + } + + @Override + public void write(int b) throws IOException { + delegate.write(b); + } + + @Override + public void write(byte[] b) throws IOException { + delegate.write(b); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + delegate.write(b, off, len); + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceController.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceController.java new file mode 100644 index 00000000..80c0356b --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceController.java @@ -0,0 +1,149 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http.transfer; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriInfo; +import okhttp3.OkHttpClient; +import org.apache.jena.query.Syntax; +import org.apache.jena.sparql.serializer.SerializerRegistry; +import org.apache.jena.sparql.service.ServiceExecutorRegistry; +import org.eclipse.edc.spi.monitor.ConsoleMonitor; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.system.configuration.Config; +import org.eclipse.edc.spi.system.configuration.ConfigFactory; +import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.edc.SkillStore; +import org.eclipse.tractusx.agents.edc.http.HttpUtils; +import org.eclipse.tractusx.agents.edc.rdf.RdfStore; +import org.eclipse.tractusx.agents.edc.service.DataManagementImpl; +import org.eclipse.tractusx.agents.edc.service.EdcSkillStore; +import org.eclipse.tractusx.agents.edc.sparql.SparqlQueryProcessor; +import org.eclipse.tractusx.agents.edc.sparql.SparqlQuerySerializerFactory; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Path("/agentsource") +public class AgentSourceController extends HttpServlet { + + private static final long serialVersionUID = 1L; + // EDC services + protected Monitor monitor = null; + protected AgentConfig config = null; + protected SkillStore skillStore = null; + + // the actual Matchmaking Agent is a Fuseki engine + protected SparqlQueryProcessor processor = null; + + + public AgentSourceController() { + + this.monitor = new ConsoleMonitor(); + monitor.debug(String.format("Initializing %s", "AgentSourceController Constructor")); + Config emptyConfig = ConfigFactory.empty(); + TypeManager typeManager = new TypeManager(); + this.config = new AgentConfig(monitor, emptyConfig); + RdfStore rdfStore = new RdfStore(config, monitor); + ServiceExecutorRegistry reg = new ServiceExecutorRegistry(); + SparqlQuerySerializerFactory arqQuerySerializerFactory = new SparqlQuerySerializerFactory(); + SerializerRegistry.get().addQuerySerializer(Syntax.syntaxARQ, arqQuerySerializerFactory); + SerializerRegistry.get().addQuerySerializer(Syntax.syntaxSPARQL_10, arqQuerySerializerFactory); + SerializerRegistry.get().addQuerySerializer(Syntax.syntaxSPARQL_11, arqQuerySerializerFactory); + this.processor = new SparqlQueryProcessor(reg, monitor, config, rdfStore, typeManager); + OkHttpClient httpClient = new OkHttpClient(); + DataManagementImpl catalogService = new DataManagementImpl(monitor, typeManager, httpClient, config); + skillStore = new EdcSkillStore(catalogService, typeManager, config); + } + + /** + * render nicely + */ + @Override + public String toString() { + return super.toString() + "/agentsource"; + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String name = req.getParameter("name"); + resp.setContentType("text/plain"); + resp.getWriter().write("Hello, " + name); + } + + + /** + * endpoint for posting a sparql query (maybe as a stored skill with a bindingset) + * + * @param asset can be a named graph for executing a query or a skill asset + * @return response + */ + @POST + @Consumes({"application/sparql-query", "application/sparql-results+json"}) + public Response postSparqlQuery(@QueryParam("asset") String asset, + @Context HttpHeaders headers, + @Context HttpServletRequest request, + @Context HttpServletResponse response, + @Context UriInfo uri + ) { + monitor.debug(String.format("Received a SparQL POST request %s for asset %s", request, asset)); + return executeQuery(asset, headers, request, response, uri); + } + + /** + * the actual execution is done by delegating to the Fuseki engine + * + * @param asset target graph + * @return a response + */ + public Response executeQuery(String asset, HttpHeaders headers, HttpServletRequest request, HttpServletResponse response, UriInfo uri) { + // extract url-encoded parameters + MultivaluedMap allQueryParams = uri.getQueryParameters(); + Map resultMap = new HashMap<>(); + for (Map.Entry> entry : allQueryParams.entrySet()) { + String key = entry.getKey(); + List values = entry.getValue(); + if (!values.isEmpty()) { + resultMap.put(key, values.get(0)); + } + } + // invoke SparqlQueryProcessor + try { + processor.execute(request, response, null, asset, resultMap); + return Response.status(response.getStatus()).build(); + } catch (WebApplicationException e) { + return HttpUtils.respond(monitor, headers, e.getResponse().getStatus(), e.getMessage(), e.getCause()); + } + } + + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceHttpParamsDecorator.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceHttpParamsDecorator.java new file mode 100644 index 00000000..1aeba9ab --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceHttpParamsDecorator.java @@ -0,0 +1,230 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http.transfer; + +import org.eclipse.edc.connector.dataplane.http.spi.HttpParamsDecorator; +import org.eclipse.edc.connector.dataplane.http.spi.HttpRequestParams; +import org.eclipse.edc.spi.EdcException; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.types.domain.HttpDataAddress; +import org.eclipse.edc.spi.types.domain.transfer.DataFlowRequest; +import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.edc.http.HttpUtils; +import org.eclipse.tractusx.agents.edc.sparql.DataspaceServiceExecutor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * Decorator to implement specifics of the http-based Agent transfer protocol. + * In particular the translation back from transfer to matchmaking. + * should be placed instead of {@see org.eclipse.edc.connector.dataplane.http.params.decorators.BaseSourceHttpParamsDecorator} + */ +public class AgentSourceHttpParamsDecorator implements HttpParamsDecorator { + + /** + * static constants + */ + public static final String ASSET_PROP_ID = "https://w3id.org/edc/v0.0.1/ns/id"; + public static final String ACCEPT_HEADER = "https://w3id.org/catenax/ontology/common#acceptsContentType"; + public static final String QUERY_PARAMS = "queryParams"; + public static final String QUERY_PARAM = "query"; + public static final String METHOD = "method"; + public static final String DEFAULT_METHOD = "GET"; + public static final String PATH_SEGMENTS = "pathSegments"; + public static final String BASE_URL = "https://w3id.org/edc/v0.0.1/ns/baseUrl"; + public static final String BODY = "body"; + public static final String MEDIA_TYPE = "mediaType"; + public static final String SLASH = "/"; + + public static final String CX_ACCEPT_PARAM = "cx_accept"; + + public static final String DEFAULT_ACCEPT = "*/*"; + /** + * regexes to extract url-encoded form and query parts + */ + public static final String PARAM_GROUP = "param"; + public static final String VALUE_GROUP = "value"; + + + public static final Pattern PARAMS = Pattern.compile(String.format("(\\?|&)(?<%s>[^=&]+)=(?<%s>[^=&]*)", PARAM_GROUP, VALUE_GROUP)); + + public static final String WWW_FORM_ENCODED = "application/x-www-form-urlencoded"; + + public static final String SPARQL_QUERY = "application/sparql-query"; + + public static final String CONTENT_TYPE_DISPOSITION = "q=[0-9]+(\\.[0-9]+)?, "; + + /** + * service references + */ + protected final AgentConfig config; + protected final Monitor monitor; + + /** + * creates a new decorator + * + * @param config agent configuration + * @param monitor logging facility + */ + public AgentSourceHttpParamsDecorator(AgentConfig config, Monitor monitor) { + this.config = config; + this.monitor = monitor; + } + + /** + * check whether this is a transfer or a source request + * + * @param dataflowRequest the request to check + * @return if this is a transfer request + */ + public static boolean isTransferRequest(DataFlowRequest dataflowRequest) { + return false; + } + + /** + * parse the body or parameter string as a url-encoded form into a map + * + * @param body url-encoded form body + * @return a map of parameters + */ + public static Map> parseParams(String body) { + Map> parts = new HashMap<>(); + if (body != null) { + Matcher matcher = PARAMS.matcher(body); + while (matcher.find()) { + String paramName = matcher.group(PARAM_GROUP); + List partSet = parts.computeIfAbsent(paramName, k -> new ArrayList<>()); + partSet.add(matcher.group(VALUE_GROUP)); + } + } + return parts; + } + + public static Map> mergeParams(Map> param1, Map> param2) { + param2.forEach((key, value) -> { + if (param1.containsKey(key)) { + param1.get(key).addAll(value); + } else { + param1.put(key, value); + } + }); + return param1; + } + + /** + * Implements the decoration + * + * @param request transfer request (contains dynamic stuff) + * @param address target address (contains static stuff) + * @param params translated call content (up to now) + * @return translated call content (identical to params) + */ + @Override + public HttpRequestParams.Builder decorate(DataFlowRequest request, HttpDataAddress address, HttpRequestParams.Builder params) { + String contentType = this.extractContentType(address, request); + String body = this.extractBody(address, request); + Map> queryParams = parseParams("?" + getRequestQueryParams(address, request)); + + if (isTransferRequest(request)) { + if (!address.getStringProperty(BASE_URL).endsWith(SLASH)) { + params.baseUrl(address.getStringProperty(BASE_URL) + SLASH); + } + } else { + // we need to annotate the base url "pure" because we do not directly hit the endpoint + params.baseUrl("https://w3id.org/catenax"); + params.header(DataspaceServiceExecutor.TARGET_URL_SYMBOL.getSymbol(), address.getStringProperty(BASE_URL)); + + // there is the case where a KA-BIND protocol call is + // one-to-one routed through the transfer plane ... in which case + // we may get query parameters in the body + // in this case we leave the query in the body (and rewriting the content type) + if (contentType != null && contentType.contains(WWW_FORM_ENCODED)) { + Map> bodyParams = parseParams("&" + body); + contentType = SPARQL_QUERY; + List queries = queryParams.getOrDefault(QUERY_PARAM, bodyParams.getOrDefault(QUERY_PARAM, List.of())); + if (queries.size() != 1) { + throw new EdcException(String.format("DataFlowRequest %s: found %d queries when contentType %s is used", request.getId(), queries.size(), WWW_FORM_ENCODED)); + } + body = HttpUtils.urlDecodeParameter(queries.get(0)); + bodyParams.remove(QUERY_PARAM); + queryParams.remove(QUERY_PARAM); + mergeParams(queryParams, bodyParams); + } + String accept = address.getStringProperty(ACCEPT_HEADER, null); + List cxAccepts = queryParams.getOrDefault(CX_ACCEPT_PARAM, List.of()); + queryParams.remove(CX_ACCEPT_PARAM); + if (accept == null) { + accept = cxAccepts.stream().findFirst().orElse(DEFAULT_ACCEPT); + } + accept = accept.replace(CONTENT_TYPE_DISPOSITION, "").replace("%2F", "/"); + params.header("Accept", accept); + } + Map> addressParams = parseParams("?" + address.getQueryParams()); + mergeParams(queryParams, addressParams); + String paramString = queryParams.entrySet().stream().flatMap((param) -> param.getValue().stream().map((value) -> param.getKey() + "=" + value)).collect(Collectors.joining("&")); + params.queryParams(!paramString.isEmpty() ? paramString : null); + params.method(this.extractMethod(address, request)); + params.path(this.extractPath(address, request)); + if (contentType != null) { + params.contentType(contentType); + } + params.body(body); + params.nonChunkedTransfer(false); + return params; + } + + protected @NotNull String extractMethod(HttpDataAddress address, DataFlowRequest request) { + if (Boolean.parseBoolean(address.getProxyMethod())) { + return Optional.ofNullable(request.getProperties().get(METHOD)).orElseThrow(() -> new EdcException(String.format("DataFlowRequest %s: 'method' property is missing", request.getId()))); + } else { + return Optional.ofNullable(address.getMethod()).orElse(DEFAULT_METHOD); + } + } + + protected @Nullable String extractPath(HttpDataAddress address, DataFlowRequest request) { + return Boolean.parseBoolean(address.getProxyPath()) ? request.getProperties().get(PATH_SEGMENTS) : address.getPath(); + } + + protected @Nullable String getRequestQueryParams(HttpDataAddress address, DataFlowRequest request) { + return Boolean.parseBoolean(address.getProxyQueryParams()) ? request.getProperties().get(QUERY_PARAMS) : null; + } + + /** + * extract the content type + * + * @param address target address + * @param request data flow request + * @return the content type (which would be derived from the query language part in case the original content type is a url-encoded form) + */ + protected @Nullable String extractContentType(HttpDataAddress address, DataFlowRequest request) { + String contentType = Boolean.parseBoolean(address.getProxyBody()) ? request.getProperties().get(MEDIA_TYPE) : address.getContentType(); + return contentType; + } + + protected @Nullable String extractBody(HttpDataAddress address, DataFlowRequest request) { + return Boolean.parseBoolean(address.getProxyBody()) ? request.getProperties().get(BODY) : null; + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceRequestParamsSupplier.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceRequestParamsSupplier.java new file mode 100644 index 00000000..bb554e95 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceRequestParamsSupplier.java @@ -0,0 +1,98 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http.transfer; + +import org.eclipse.edc.connector.dataplane.http.params.decorators.BaseCommonHttpParamsDecorator; +import org.eclipse.edc.connector.dataplane.http.params.decorators.BaseSinkHttpParamsDecorator; +import org.eclipse.edc.connector.dataplane.http.spi.HttpParamsDecorator; +import org.eclipse.edc.connector.dataplane.http.spi.HttpRequestParams; +import org.eclipse.edc.connector.dataplane.http.spi.HttpRequestParamsProvider; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.security.Vault; +import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.edc.spi.types.domain.HttpDataAddress; +import org.eclipse.edc.spi.types.domain.transfer.DataFlowRequest; +import org.eclipse.tractusx.agents.edc.AgentConfig; + +import java.util.ArrayList; +import java.util.List; + + +/** + * request params supplier which correctly double encodes + * valid url symbols in the parameter section, extracts + * original headers like accept from special parameters and caters for + * translating url-encoded form bodies into their + * "normal" param+body form + */ +public class AgentSourceRequestParamsSupplier implements HttpRequestParamsProvider { + protected final List sourceDecorators = new ArrayList<>(); + protected final List sinkDecorators = new ArrayList<>(); + + /** + * the edc config section + */ + protected final AgentConfig config; + + /** + * logging subsystem + */ + protected Monitor monitor; + + /** + * creates a supplier + * + * @param vault secret host + * @param config edc config section + * @param monitor logging reference + */ + public AgentSourceRequestParamsSupplier(Vault vault, TypeManager typeManager, AgentConfig config, Monitor monitor) { + BaseCommonHttpParamsDecorator commonHttpParamsDecorator = new BaseCommonHttpParamsDecorator(vault, typeManager); + this.registerSinkDecorator(commonHttpParamsDecorator); + this.registerSourceDecorator(commonHttpParamsDecorator); + this.registerSourceDecorator(new AgentSourceHttpParamsDecorator(config, monitor)); + this.registerSinkDecorator(new BaseSinkHttpParamsDecorator()); + this.config = config; + this.monitor = monitor; + } + + @Override + public void registerSourceDecorator(HttpParamsDecorator decorator) { + this.sourceDecorators.add(decorator); + } + + @Override + public void registerSinkDecorator(HttpParamsDecorator decorator) { + this.sinkDecorators.add(decorator); + } + + @Override + public HttpRequestParams provideSourceParams(DataFlowRequest request) { + HttpRequestParams.Builder params = HttpRequestParams.Builder.newInstance(); + HttpDataAddress address = org.eclipse.edc.spi.types.domain.HttpDataAddress.Builder.newInstance().copyFrom(request.getSourceDataAddress()).build(); + this.sourceDecorators.forEach((decorator) -> decorator.decorate(request, address, params)); + return params.build(); + } + + @Override + public HttpRequestParams provideSinkParams(DataFlowRequest request) { + HttpRequestParams.Builder params = HttpRequestParams.Builder.newInstance(); + HttpDataAddress address = org.eclipse.edc.spi.types.domain.HttpDataAddress.Builder.newInstance().copyFrom(request.getDestinationDataAddress()).build(); + this.sinkDecorators.forEach((decorator) -> decorator.decorate(request, address, params)); + return params.build(); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceServlet.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceServlet.java new file mode 100644 index 00000000..33249c8b --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceServlet.java @@ -0,0 +1,140 @@ +// Copyright (c) 2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.http.transfer; + +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.tractusx.agents.conforming.SharedObjectManager; +import org.eclipse.tractusx.agents.edc.sparql.SparqlQueryProcessor; + +import java.io.IOException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +@WebServlet("/agentsource") +public class AgentSourceServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + // EDC services + private Monitor monitor = null; + private SparqlQueryProcessor processor = null; + + public AgentSourceServlet() { + + this.monitor = SharedObjectManager.getInstance().getMonitor(); + this.processor = SharedObjectManager.getInstance().getProcessor(); + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + OkHttpClient httpClient = SharedObjectManager.getInstance().getHttpClient(); + String catalogRequestBody = "{" + + "\"@context\": {}," + + "\"protocol\": \"dataspace-protocol-http\"," + + "\"providerUrl\": \"%1$s\", " + + "\"counterPartyAddress\": \"%1$s\", " + + "\"querySpec\": %2$s }"; + String dspPath = "%s/api/v1/dsp"; + String remoteControlPlaneIdsUrl = "http://oem-control-plane:8282"; + var catalogSpec = String.format(catalogRequestBody, String.format(dspPath, remoteControlPlaneIdsUrl), "{\"offset\":0,\"limit\":50,\"filterExpression\":[{\"operandLeft\":\"https://w3id.org/catenax/ontology/common#isFederated\",\"operator\":\"=\",\"operandRight\":\"true^^xsd:boolean\"}],\"sortOrder\":\"ASC\",\"sortField\":null}"); + var request = new Request.Builder().url("http://oem-control-plane2:8181/management/v2/catalog/request").post(RequestBody.create(catalogSpec, MediaType.parse("application/json"))); + request.addHeader("x-api-key", "foo"); + monitor.debug("sending in doGet" + "http://oem-control-plane2:8181", null); + monitor.debug(SharedObjectManager.getInstance().convertToCurl(request.build())); + okhttp3.Response response = httpClient.newCall(request.build()).execute(); + + resp.setContentType("text/plain"); + resp.getWriter().println("\n Hello, Agent, I am on status " + response.code()); + if (!response.isSuccessful()) { + throw new IOException("Unexpected code " + response); + } + + String responseBody = response.body().string(); + System.out.println(responseBody); + resp.getWriter().println("\n " + responseBody); + + } + + /** + * endpoint for posting a sparql query (maybe as a stored skill with a bindingset) + * + * @param asset can be a named graph for executing a query or a skill asset + * @return response + */ + + /*@Consumes({"application/sparql-query", "application/sparql-results+json"}) + public void doPost(@QueryParam("asset") String asset, + @Context HttpHeaders headers, + @Context HttpServletRequest request, + @Context HttpServletResponse response, + @Context UriInfo uri + ) { */ + @Override + public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { + resp.setContentType("application/sparql-query"); + String asset = req.getParameter("asset"); + monitor.debug(String.format("Received a SparQL POST request %s for asset %s", req, asset)); + executeQuery(asset, req, resp); + return; + } + + /** + * the actual execution is done by delegating to the Fuseki engine + * + * @param asset target graph + * @return a response + */ + public Response executeQuery(String asset, HttpServletRequest request, HttpServletResponse response) { + // extract url-encoded parameters + + Map resultMap = new HashMap<>(); + + // Get the query string from the request URL + String queryString = URLDecoder.decode(request.getQueryString(), StandardCharsets.UTF_8); + + if (queryString != null) { + // Split the query string into individual parameters + String[] queryParams = queryString.split("&"); + for (String queryParam : queryParams) { + // Split each parameter into key-value pair + String[] paramKeyValue = queryParam.split("="); + if (paramKeyValue.length == 2) { + // Add key-value pair to the result map + resultMap.put(paramKeyValue[0], paramKeyValue[1]); + } + } + } + // invoke SparqlQueryProcessor + try { + processor.execute(request, response, null, asset, resultMap); + return Response.status(response.getStatus()).build(); + } catch (WebApplicationException e) { + return null; + } + } +} \ No newline at end of file diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLd.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLd.java new file mode 100644 index 00000000..676296f4 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLd.java @@ -0,0 +1,146 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.jsonld; + +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonArrayBuilder; +import jakarta.json.JsonNumber; +import jakarta.json.JsonObject; +import jakarta.json.JsonObjectBuilder; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; +import org.eclipse.tractusx.agents.edc.model.Asset; +import org.eclipse.tractusx.agents.edc.model.ContractAgreement; +import org.eclipse.tractusx.agents.edc.model.ContractNegotiation; +import org.eclipse.tractusx.agents.edc.model.DcatCatalog; +import org.eclipse.tractusx.agents.edc.model.IdResponse; +import org.eclipse.tractusx.agents.edc.model.TransferProcess; + +import java.io.StringReader; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * base facility to deal with EDC specific JSONLD structures + */ +public class JsonLd { + + public static DcatCatalog processCatalog(String cat) { + return processCatalog(Json.createReader(new StringReader(cat)).readObject()); + } + + public static DcatCatalog processCatalog(JsonObject cat) { + return new DcatCatalog(processJsonLd(cat, null)); + } + + public static IdResponse processIdResponse(String response) { + return processIdResponse(Json.createReader(new StringReader(response)).readObject()); + } + + public static IdResponse processIdResponse(JsonObject response) { + return new IdResponse(processJsonLd(response, null)); + } + + public static ContractNegotiation processContractNegotiation(String response) { + return processContractNegotiation(Json.createReader(new StringReader(response)).readObject()); + } + + public static ContractNegotiation processContractNegotiation(JsonObject response) { + return new ContractNegotiation(processJsonLd(response, null)); + } + + public static ContractAgreement processContractAgreement(String response) { + return processContractAgreement(Json.createReader(new StringReader(response)).readObject()); + } + + public static ContractAgreement processContractAgreement(JsonObject response) { + return new ContractAgreement(processJsonLd(response, null)); + } + + public static TransferProcess processTransferProcess(String response) { + return processTransferProcess(Json.createReader(new StringReader(response)).readObject()); + } + + public static TransferProcess processTransferProcess(JsonObject response) { + return new TransferProcess(processJsonLd(response, null)); + } + + public static List processAssetList(String response) { + return processAssetList(Json.createReader(new StringReader(response)).readArray()); + } + + public static List processAssetList(JsonArray response) { + return response.stream().map(responseObject -> + new Asset(processJsonLd(responseObject.asJsonObject(), null)) + ).collect(Collectors.toList()); + } + + public static String asString(JsonValue value) { + if (value == null) { + return "null"; + } + switch (value.getValueType()) { + case STRING: + return ((JsonString) value).getString(); + case NUMBER: + return ((JsonNumber) value).numberValue().toString(); + default: + return value.toString(); + } + } + + public static JSONTYPE processJsonLd(JSONTYPE source, Map context) { + switch (source.getValueType()) { + case ARRAY: + final JsonArrayBuilder array = Json.createArrayBuilder(); + source.asJsonArray().forEach(value -> array.add(processJsonLd(value, context))); + return (JSONTYPE) array.build(); + case OBJECT: + JsonObject sourceObject = source.asJsonObject(); + Map namespaces = new HashMap<>(); + if (context != null) { + namespaces.putAll(context); + } + if (sourceObject.containsKey("@context")) { + for (Map.Entry ns : sourceObject.getJsonObject("@context").entrySet()) { + namespaces.put(ns.getKey(), JsonLd.asString(ns.getValue())); + } + } + final JsonObjectBuilder object = Json.createObjectBuilder(); + sourceObject.forEach((prop, value) -> { + int colonIndex = prop.indexOf(":"); + if (colonIndex > 0) { + String prefix = prop.substring(0, colonIndex); + if (namespaces.containsKey(prefix)) { + prefix = namespaces.get(prefix); + } else { + prefix = prefix + ":"; + } + prop = prefix + prop.substring(colonIndex + 1); + } + object.add(prop, processJsonLd(value, namespaces)); + }); + return (JSONTYPE) object.build(); + default: + return source; + } + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLdObject.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLdObject.java new file mode 100644 index 00000000..cbf98831 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLdObject.java @@ -0,0 +1,43 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.jsonld; + +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; + +import java.util.Map; + +public class JsonLdObject { + + protected JsonObject object; + + public JsonLdObject(JsonObject object) { + this.object = object; + } + + public Map getProperties() { + return object; + } + + public String getId() { + return object.getString("@id"); + } + + public String asString() { + return JsonLd.asString(object); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/Asset.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/Asset.java new file mode 100644 index 00000000..890aefcd --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/Asset.java @@ -0,0 +1,47 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.model; + +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; +import org.eclipse.tractusx.agents.edc.jsonld.JsonLdObject; + +import java.util.Map; + +/** + * represents an asset + */ +public class Asset extends JsonLdObject { + + Map publicProperties; + Map privateProperties; + + public Asset(JsonObject node) { + super(node); + this.publicProperties = node.getJsonObject("https://w3id.org/edc/v0.0.1/ns/properties"); + this.privateProperties = node.getJsonObject("https://w3id.org/edc/v0.0.1/ns/privateProperties"); + } + + public Map getPrivateProperties() { + return privateProperties; + } + + public Map getPublicProperties() { + return publicProperties; + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractAgreement.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractAgreement.java new file mode 100644 index 00000000..40160873 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractAgreement.java @@ -0,0 +1,35 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.model; + +import jakarta.json.JsonObject; +import org.eclipse.tractusx.agents.edc.jsonld.JsonLdObject; + +public class ContractAgreement extends JsonLdObject { + + public ContractAgreement(JsonObject node) { + super(node); + } + + public String getAssetId() { + return object.getString("https://w3id.org/edc/v0.0.1/ns/assetId"); + } + + public long getContractSigningDate() { + return object.getInt("https://w3id.org/edc/v0.0.1/ns/contractSigningDate"); + } +} \ No newline at end of file diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiation.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiation.java new file mode 100644 index 00000000..8494ac8d --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiation.java @@ -0,0 +1,42 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.model; + +import jakarta.json.JsonObject; +import org.eclipse.tractusx.agents.edc.jsonld.JsonLdObject; + +/** + * Result of a contract negotiation + */ +public class ContractNegotiation extends JsonLdObject { + + public ContractNegotiation(JsonObject node) { + super(node); + } + + public String getContractAgreementId() { + return object.getString("https://w3id.org/edc/v0.0.1/ns/contractAgreementId", null); + } + + public String getState() { + return object.getString("https://w3id.org/edc/v0.0.1/ns/state"); + } + + public String getErrorDetail() { + return object.getString("https://w3id.org/edc/v0.0.1/ns/errorDetail", null); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiationRequest.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiationRequest.java new file mode 100644 index 00000000..2752ecdf --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiationRequest.java @@ -0,0 +1,103 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.model; + +public class ContractNegotiationRequest { + + private String connectorAddress; + private String protocol = "dataspace-protocol-http"; + private String connectorId; + + private String localBusinessPartnerNumber; + private String remoteBusinessPartnerNumber; + private ContractOfferDescription offer; + + private ContractNegotiationRequest() { + } + + + public String getLocalBusinessPartnerNumber() { + return localBusinessPartnerNumber; + } + + public String getRemoteBusinessPartnerNumber() { + return remoteBusinessPartnerNumber; + } + + public String getConnectorAddress() { + return connectorAddress; + } + + public String getProtocol() { + return protocol; + } + + public String getConnectorId() { + return connectorId; + } + + public ContractOfferDescription getOffer() { + return offer; + } + + + public static final class Builder { + private final ContractNegotiationRequest dto; + + private Builder() { + dto = new ContractNegotiationRequest(); + } + + public static Builder newInstance() { + return new Builder(); + } + + public Builder connectorAddress(String connectorAddress) { + dto.connectorAddress = connectorAddress; + return this; + } + + public Builder protocol(String protocol) { + dto.protocol = protocol; + return this; + } + + public Builder connectorId(String connectorId) { + dto.connectorId = connectorId; + return this; + } + + public Builder offerId(ContractOfferDescription offerId) { + dto.offer = offerId; + return this; + } + + public Builder localBusinessPartnerNumber(String bpn) { + dto.localBusinessPartnerNumber = bpn; + return this; + } + + public Builder remoteBusinessPartnerNumber(String bpn) { + dto.remoteBusinessPartnerNumber = bpn; + return this; + } + + public ContractNegotiationRequest build() { + return dto; + } + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractOfferDescription.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractOfferDescription.java new file mode 100644 index 00000000..88a6f9ad --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractOfferDescription.java @@ -0,0 +1,43 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.model; + +public class ContractOfferDescription { + private final String offerId; + private final String assetId; + private final OdrlPolicy policy; + + public ContractOfferDescription(String offerId, + String assetId, + OdrlPolicy policy) { + this.offerId = offerId; + this.assetId = assetId; + this.policy = policy; + } + + public String getOfferId() { + return this.offerId; + } + + public String getAssetId() { + return this.assetId; + } + + public OdrlPolicy getPolicy() { + return this.policy; + } +} \ No newline at end of file diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatCatalog.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatCatalog.java new file mode 100644 index 00000000..34119314 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatCatalog.java @@ -0,0 +1,54 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.model; + +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; +import org.eclipse.tractusx.agents.edc.jsonld.JsonLdObject; + +import java.util.ArrayList; +import java.util.List; + +/** + * represents a dcat catalogue + */ +public class DcatCatalog extends JsonLdObject { + + List datasets = new ArrayList<>(); + + public DcatCatalog(JsonObject node) { + super(node); + JsonValue dataset = node.get("https://www.w3.org/ns/dcat/dataset"); + if (dataset != null) { + if (dataset.getValueType() == JsonValue.ValueType.ARRAY) { + for (JsonValue ds : dataset.asJsonArray()) { + datasets.add(new DcatDataset(ds.asJsonObject())); + } + } else { + datasets.add(new DcatDataset(dataset.asJsonObject())); + } + } + } + + public String getParticipantId() { + return object.getString("https://w3id.org/edc/v0.0.1/ns/participantId", "anonymous"); + } + + public List getDatasets() { + return datasets; + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatDataset.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatDataset.java new file mode 100644 index 00000000..4d27dfd3 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatDataset.java @@ -0,0 +1,62 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.model; + +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; +import org.eclipse.tractusx.agents.edc.jsonld.JsonLdObject; + +import java.util.ArrayList; +import java.util.List; + +/** + * represents a dcat data set + */ +public class DcatDataset extends JsonLdObject { + + List policies = new ArrayList<>(); + + public DcatDataset(JsonObject node) { + super(node); + JsonValue jpolicies = node.get("http://www.w3.org/ns/odrl/2/hasPolicy"); + if (jpolicies != null) { + if (jpolicies.getValueType() == JsonValue.ValueType.ARRAY) { + for (JsonValue policy : jpolicies.asJsonArray()) { + policies.add(new OdrlPolicy(policy.asJsonObject())); + } + } else { + policies.add(new OdrlPolicy(jpolicies.asJsonObject())); + } + } + } + + /** + * access default policy + * + * @return null, if no policy exists + */ + public OdrlPolicy hasPolicy() { + if (policies.isEmpty()) { + return null; + } else { + return policies.get(0); + } + } +} + + + diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/IdResponse.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/IdResponse.java new file mode 100644 index 00000000..aaf02a5e --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/IdResponse.java @@ -0,0 +1,31 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.model; + +import jakarta.json.JsonObject; +import org.eclipse.tractusx.agents.edc.jsonld.JsonLdObject; + +/** + * represents a response object + */ +public class IdResponse extends JsonLdObject { + + public IdResponse(JsonObject node) { + super(node); + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/OdrlPolicy.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/OdrlPolicy.java new file mode 100644 index 00000000..35d3c3a9 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/OdrlPolicy.java @@ -0,0 +1,31 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.model; + +import jakarta.json.JsonObject; +import org.eclipse.tractusx.agents.edc.jsonld.JsonLdObject; + +/** + * represents a policy + */ +public class OdrlPolicy extends JsonLdObject { + + public OdrlPolicy(JsonObject node) { + super(node); + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/TransferProcess.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/TransferProcess.java new file mode 100644 index 00000000..56d2ae29 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/TransferProcess.java @@ -0,0 +1,31 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.model; + +import jakarta.json.JsonObject; +import org.eclipse.tractusx.agents.edc.jsonld.JsonLdObject; + +public class TransferProcess extends JsonLdObject { + + public TransferProcess(JsonObject node) { + super(node); + } + + public String getState() { + return object.getString("https://w3id.org/edc/v0.0.1/ns/state"); + } +} \ No newline at end of file diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/TransferRequest.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/TransferRequest.java new file mode 100644 index 00000000..83eac475 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/TransferRequest.java @@ -0,0 +1,175 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.model; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import org.eclipse.edc.spi.types.domain.DataAddress; +import org.eclipse.edc.spi.types.domain.callback.CallbackAddress; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@JsonDeserialize(builder = TransferRequest.Builder.class) +public class TransferRequest { + + private String id; + private String connectorAddress; // TODO change to callbackAddress + private String contractId; + private DataAddress dataDestination; + private boolean managedResources = true; + private Map properties = new HashMap<>(); + + private Map privateProperties = new HashMap<>(); + + private String protocol; + private String connectorId; + private String providerId; + private String assetId; + + private List callbackAddresses = new ArrayList<>(); + + + public String getConnectorAddress() { + return connectorAddress; + } + + public String getId() { + return id; + } + + public String getContractId() { + return contractId; + } + + public DataAddress getDataDestination() { + return dataDestination; + } + + public boolean isManagedResources() { + return managedResources; + } + + public Map getProperties() { + return properties; + } + + public Map getPrivateProperties() { + return privateProperties; + } + + public String getProtocol() { + return protocol; + } + + public String getConnectorId() { + return connectorId; + } + + public String getProviderId() { + return connectorId; + } + + public String getAssetId() { + return assetId; + } + + public List getCallbackAddresses() { + return callbackAddresses; + } + + @JsonPOJOBuilder(withPrefix = "") + public static final class Builder { + private final TransferRequest request; + + private Builder() { + request = new TransferRequest(); + } + + @JsonCreator + public static Builder newInstance() { + return new Builder(); + } + + public Builder connectorAddress(String connectorAddress) { + request.connectorAddress = connectorAddress; + return this; + } + + public Builder id(String id) { + request.id = id; + return this; + } + + public Builder contractId(String contractId) { + request.contractId = contractId; + return this; + } + + public Builder dataDestination(DataAddress dataDestination) { + request.dataDestination = dataDestination; + return this; + } + + public Builder managedResources(boolean managedResources) { + request.managedResources = managedResources; + return this; + } + + public Builder properties(Map properties) { + request.properties = properties; + return this; + } + + public Builder privateProperties(Map privateProperties) { + request.privateProperties = privateProperties; + return this; + } + + public Builder protocol(String protocol) { + request.protocol = protocol; + return this; + } + + public Builder connectorId(String connectorId) { + request.connectorId = connectorId; + return this; + } + + public Builder providerId(String providerId) { + request.providerId = providerId; + return this; + } + + public Builder assetId(String assetId) { + request.assetId = assetId; + return this; + } + + public Builder callbackAddresses(List callbackAddresses) { + request.callbackAddresses = callbackAddresses; + return this; + } + + public TransferRequest build() { + return request; + } + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/rdf/ExternalFormat.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/rdf/ExternalFormat.java new file mode 100644 index 00000000..1d8dacc5 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/rdf/ExternalFormat.java @@ -0,0 +1,66 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.rdf; + +/** + * lists the various formats that the rdf store can import + */ +public enum ExternalFormat { + TURTLE("text/turtle"), + CSV("text/csv"); + + private final String contentType; + + /** + * Constructoe for ExternalFormat + * + * @param contentType the mime type + */ + + ExternalFormat(final String contentType) { + this.contentType = contentType; + } + + /** + * get the content type + * + * @return mode as argument + */ + + public String getContentType() { + return this.contentType; + } + + /** + * converts a mime type into a format + * + * @param contentType as argument + * @return respective enum, null if format cannot be deduced + */ + + public static ExternalFormat valueOfFormat(String contentType) { + if (contentType != null) { + if (contentType.endsWith("turtle")) { + return TURTLE; + } + if (contentType.endsWith("csv")) { + return CSV; + } + } + return null; + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/rdf/RdfStore.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/rdf/RdfStore.java new file mode 100644 index 00000000..7112d756 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/rdf/RdfStore.java @@ -0,0 +1,270 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.rdf; + + +import org.apache.jena.fuseki.server.DataAccessPoint; +import org.apache.jena.fuseki.server.DataService; +import org.apache.jena.graph.Node; +import org.apache.jena.graph.NodeFactory; +import org.apache.jena.query.TxnType; +import org.apache.jena.riot.Lang; +import org.apache.jena.riot.RDFParser; +import org.apache.jena.riot.lang.StreamRDFCounting; +import org.apache.jena.riot.system.ErrorHandler; +import org.apache.jena.riot.system.ErrorHandlerFactory; +import org.apache.jena.riot.system.StreamRDF; +import org.apache.jena.riot.system.StreamRDFLib; +import org.apache.jena.sparql.core.DatasetGraph; +import org.apache.jena.sparql.core.DatasetGraphFactory; +import org.apache.jena.sparql.core.Quad; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.edc.MonitorWrapper; + +//import java.io.*; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * a service sitting on a local RDF store/graph + * (which hosts the ontology and the federated dataspace + * representation) + */ +public class RdfStore { + + // we need a single data access point (with its default graph) + protected final DatasetGraph dataset; + protected final DataAccessPoint api; + protected final DataService service; + protected final Monitor monitor; + protected final AgentConfig config; + + protected final MonitorWrapper monitorWrapper; + + /** + * create a new RDF store (and initialise with a given ttl file) + * + * @param config EDC config + * @param monitor logging subsystem + */ + public RdfStore(AgentConfig config, Monitor monitor) { + this.config = config; + this.dataset = DatasetGraphFactory.createTxnMem(); + + DataService.Builder dataService = DataService.newBuilder(dataset); + this.service = dataService.build(); + api = new DataAccessPoint(config.getAccessPoint(), service); + this.monitor = monitor; + this.monitorWrapper = new MonitorWrapper(getClass().getName(), monitor); + monitor.debug(String.format("Activating data service %s under access point %s", service, api)); + service.goActive(); + // read file with ontology, share this dataset with the catalogue sync procedure + if (config.getAssetFiles() != null) { + startTx(); + StreamRDF dest = StreamRDFLib.dataset(dataset); + StreamRDF graphDest = StreamRDFLib.extendTriplesToQuads(getDefaultGraph(), dest); + StreamRDFCounting countingDest = StreamRDFLib.count(graphDest); + ErrorHandler errorHandler = ErrorHandlerFactory.errorHandlerStd(monitorWrapper); + for (String assetFile : config.getAssetFiles()) { + RDFParser.create() + .errorHandler(errorHandler) + .source(assetFile) + .lang(Lang.TTL) + .parse(countingDest); + monitor.debug(String.format("Initialised asset %s with file %s resulted in %d triples", config.getDefaultAsset(), assetFile, countingDest.countTriples())); + } + commit(); + monitor.info(String.format("Initialised asset %s with %d triples from %d files", config.getDefaultAsset(), countingDest.countTriples(), config.getAssetFiles().length)); + } else { + monitor.info(String.format("Initialised asset %s with 0 triples.", config.getDefaultAsset())); + } + } + + public static final String CSV_REGEX = "(\"[^\"]*\")?([^%s]*)"; + + /** + * registers (overwrites/extends) an asset + * + * @param asset asset iri + * @param content stream for rdf data + * @param format the format of the stream + * @return number of resulting triples + */ + public long registerAsset(String asset, String content, ExternalFormat format) { + if (!asset.contains("/")) { + asset = "http://server/unset-base/" + asset; + } + monitor.info(String.format("Upserting asset %s with turtle source.", asset)); + startTx(); + StreamRDF dest = StreamRDFLib.dataset(dataset); + StreamRDF graphDest = StreamRDFLib.extendTriplesToQuads(NodeFactory.createURI(asset), dest); + StreamRDFCounting countingDest = StreamRDFLib.count(graphDest); + ErrorHandler errorHandler = ErrorHandlerFactory.errorHandlerStd(monitorWrapper); + switch (format) { + default: + RDFParser.create() + .errorHandler(errorHandler) + .source(new ByteArrayInputStream(content.getBytes())) + .lang(Lang.TTL) + .parse(countingDest); + break; + case CSV: + countingDest.start(); + Pattern csvCell = Pattern.compile(String.format(CSV_REGEX, ",")); + try (BufferedReader reader = new BufferedReader(new StringReader(content))) { + String header = reader.readLine(); + List predicates = new ArrayList<>(); + if (header != null) { + int position = 0; + Matcher headerMatcher = csvCell.matcher(header); + while (position <= header.length() && headerMatcher.find(position)) { + predicates.add(NodeFactory.createURI(headerMatcher.group())); + position = headerMatcher.end() + 1; + } + reader.lines().forEach(factLine -> { + int fposition = 0; + Matcher factMatcher = csvCell.matcher(factLine); + if (factMatcher.find(fposition)) { + Node subject = NodeFactory.createURI(factMatcher.group()); + fposition = factMatcher.end() + 1; + for (int fact = 1; fact < predicates.size() && fposition <= factLine.length() && factMatcher.find(fposition); fact++) { + Node object = parseObject(factMatcher.group()); + countingDest.triple(NodeFactory.createTripleNode(subject, predicates.get(fact), object).getTriple()); + fposition = factMatcher.end() + 1; + } + } + }); + } + } catch (IOException e) { + monitor.warning("An exception has occurred while parsing a CSV stream. Ignoring some/all data.", e); + } + countingDest.finish(); + break; + } + long numberOfTriples = countingDest.countTriples(); + monitor.debug(String.format("Upserting asset %s resulted in %d triples", asset, numberOfTriples)); + commit(); + return numberOfTriples; + } + + /** + * parses a given rdf snippet into a node + * + * @param group rdf snippet node + * @return a parsed node + */ + private Node parseObject(String group) { + if (group.startsWith("<")) { + group = group.replaceAll("[\\<\\>]", ""); + return NodeFactory.createURI(group); + } else if (group.contains("^^")) { + int index = group.lastIndexOf("^^"); + String type = group.substring(index + 2); + group = group.substring(0, index - 1); + } + return NodeFactory.createLiteral(group); + } + + /** + * deletes an asset + * + * @param asset asset iri + * @return number of deleted triples + */ + public long deleteAsset(String asset) { + if (!asset.contains("/")) { + asset = "http://server/unset-base/" + asset; + } + monitor.info(String.format("Deleting asset %s.", asset)); + startTx(); + Quad findAssets = Quad.create(NodeFactory.createURI(asset), Node.ANY, Node.ANY, Node.ANY); + Iterator assetQuads = getDataSet().find(findAssets); + int tupleCount = 0; + while (assetQuads.hasNext()) { + getDataSet().delete(assetQuads.next()); + tupleCount++; + } + monitor.debug(String.format("Deleting asset %s resulted in %d triples", asset, tupleCount)); + commit(); + return tupleCount; + } + + /** + * access + * + * @return name of the default graph + */ + public Node getDefaultGraph() { + return NodeFactory.createURI(config.getDefaultAsset()); + } + + /** + * access + * + * @return access point to the graph + */ + public DataAccessPoint getDataAccessPoint() { + return api; + } + + /** + * access + * + * @return dataservice shielding the graph + */ + public DataService getDataService() { + return service; + } + + /** + * access + * + * @return the actual graph store + */ + public DatasetGraph getDataSet() { + return dataset; + } + + /** + * starts a write transaction + */ + public void startTx() { + dataset.begin(TxnType.WRITE); + } + + /** + * commits the current transaction + */ + public void commit() { + dataset.commit(); + } + + /** + * rollback the current transaction + */ + public void abort() { + dataset.abort(); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java new file mode 100644 index 00000000..35870363 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java @@ -0,0 +1,156 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.service; + +import org.eclipse.edc.spi.query.QuerySpec; +import org.eclipse.tractusx.agents.edc.model.Asset; +import org.eclipse.tractusx.agents.edc.model.ContractAgreement; +import org.eclipse.tractusx.agents.edc.model.ContractNegotiation; +import org.eclipse.tractusx.agents.edc.model.ContractNegotiationRequest; +import org.eclipse.tractusx.agents.edc.model.DcatCatalog; +import org.eclipse.tractusx.agents.edc.model.IdResponse; +import org.eclipse.tractusx.agents.edc.model.TransferProcess; +import org.eclipse.tractusx.agents.edc.model.TransferRequest; + +import java.io.IOException; +import java.util.List; + + +/** + * DataManagement + * is a service wrapper around the management endpoint + * of the EDC control plane + */ +public interface DataManagement { + + /** + * Search for a dedicated asset + * + * @param remoteControlPlaneIdsUrl url of the remote control plane ids endpoint + * @param assetId (connector-unique) identifier of the asset + * @return a collection of contract options to access the given asset + * @throws IOException in case that the remote call did not succeed + */ + DcatCatalog findContractOffers(String remoteControlPlaneIdsUrl, String assetId) throws IOException; + + /** + * Access the catalogue + * + * @param remoteControlPlaneIdsUrl url of the remote control plane ids endpoint + * @param spec query specification + * @return catalog object + * @throws IOException in case something went wrong + */ + DcatCatalog getCatalog(String remoteControlPlaneIdsUrl, QuerySpec spec) throws IOException; + + /** + * Access the (provider control plane) catalogue + * + * @param spec query specification + * @return catalog object + * @throws IOException in case something went wrong + */ + List listAssets(QuerySpec spec) throws IOException; + + /** + * creates or updates a given skill asset + * + * @param assetId key + * @param name of skill + * @param description of skill + * @param version of skill + * @param contract of skill + * @param ontologies of skill + * @param distributionMode of skill + * @param isFederated whether it should be distributed + * @param query of skill + * @return idresponse + * @throws IOException in case interaction with EDC went wrong + */ + IdResponse createOrUpdateSkill(String assetId, String name, String description, String version, String contract, String ontologies, String distributionMode, boolean isFederated, String query) throws IOException; + + /** + * creates or updates a given graph asset + * + * @param assetId key + * @param name of graph + * @param description of graph + * @param version of graph + * @param contract of graph + * @param ontologies of graph + * @param shape of graph + * @param isFederated whether it should be distributed + * @return idresponse + * @throws IOException in case interaction with EDC went wrong + */ + IdResponse createOrUpdateGraph(String assetId, String name, String description, String version, String contract, String ontologies, String shape, boolean isFederated) throws IOException; + + /** + * deletes an existing aseet + * + * @param assetId key of the asset + * @return idresponse + */ + + IdResponse deleteAsset(String assetId) throws IOException; + + /** + * initiates negotation + * + * @param negotiationRequest outgoing request + * @return negotiation id + * @throws IOException in case something went wronf + */ + String initiateNegotiation(ContractNegotiationRequest negotiationRequest) throws IOException; + + /** + * return state of contract negotiation + * + * @param negotiationId id of the negotation to inbestigate + * @return status of the negotiation + * @throws IOException in case something went wrong + */ + ContractNegotiation getNegotiation(String negotiationId) throws IOException; + + /** + * return the contract agreement + * + * @param agreementId id of the agreement + * @return contract agreement + * @throws IOException something wild happens + */ + ContractAgreement getAgreement(String agreementId) throws IOException; + + /** + * Initiates a transfer + * + * @param transferRequest request + * @return transfer id + * @throws IOException in case something went wrong + */ + String initiateHttpProxyTransferProcess(TransferRequest transferRequest) throws IOException; + + /** + * return state of transfer process + * + * @param transferProcessId id of the transfer process + * @return state of the transfer process + * @throws IOException in case something went wrong + */ + TransferProcess getTransfer(String transferProcessId) throws IOException; + +} \ No newline at end of file diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagementImpl.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagementImpl.java new file mode 100644 index 00000000..2b29f41b --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagementImpl.java @@ -0,0 +1,683 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import jakarta.ws.rs.InternalServerErrorException; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.ResponseBody; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.query.Criterion; +import org.eclipse.edc.spi.query.QuerySpec; +import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.tractusx.agents.conforming.SharedObjectManager; +import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.edc.jsonld.JsonLd; +import org.eclipse.tractusx.agents.edc.model.Asset; +import org.eclipse.tractusx.agents.edc.model.ContractAgreement; +import org.eclipse.tractusx.agents.edc.model.ContractNegotiation; +import org.eclipse.tractusx.agents.edc.model.ContractNegotiationRequest; +import org.eclipse.tractusx.agents.edc.model.DcatCatalog; +import org.eclipse.tractusx.agents.edc.model.IdResponse; +import org.eclipse.tractusx.agents.edc.model.TransferProcess; +import org.eclipse.tractusx.agents.edc.model.TransferRequest; + +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import static java.lang.String.format; + +/** + * DataManagement + * is a service wrapper around the management endpoint + * of the EDC control plane + */ +public class DataManagementImpl implements DataManagement { + /** + * some constants when interacting with control plane + */ + public static final String DSP_PATH = "%s/api/v1/dsp"; + public static final String CATALOG_CALL = "%s/v2/catalog/request"; + public static final String CATALOG_REQUEST_BODY = "{" + + "\"@context\": {}," + + "\"protocol\": \"dataspace-protocol-http\"," + + "\"providerUrl\": \"%1$s\", " + + "\"counterPartyAddress\": \"%1$s\", " + + "\"querySpec\": %2$s }"; + + public static final String ASSET_CREATE_CALL = "%s%s/assets"; + public static final String ASSET_UPDATE_CALL = "%s%s/assets/%s"; + + /** + * template for skill asset creation + */ + public static final String SKILL_ASSET_CREATE_BODY = "{\n" + + " \"@context\": {\n" + + " \"rdf\": \"http://www.w3.org/1999/02/22-rdf-syntax-ns#\",\n" + + " \"rdfs\": \"http://www.w3.org/2000/01/rdf-schema#\",\n" + + " \"cx-common\": \"https://w3id.org/catenax/ontology/common#\",\n" + + " \"xsd\": \"http://www.w3.org/2001/XMLSchema#\",\n" + + " \"sh\": \"http://www.w3.org/ns/shacl#\"\n" + + " },\n" + + " \"asset\": {\n" + + " \"@type\": \"Asset\",\n" + + " \"@id\": \"%1$s\", \n" + + " \"properties\": {\n" + + " \"name\": \"%2$s\",\n" + + " \"description\": \"%3$s\",\n" + + " \"version\": \"%4$s\",\n" + + " \"contenttype\": \"application/json, application/xml\",\n" + + "%5$s" + + " \"rdf:type\": \"cx-common:SkillAsset\",\n" + + " \"rdfs:isDefinedBy\": \"%6$s\",\n" + + " \"cx-common:implementsProtocol\": \"cx-common:Protocol?w3c:http:SKILL\",\n" + + " \"cx-common:distributionMode\": \"%7$s\",\n" + + " \"cx-common:isFederated\": \"%8$b^^xsd:boolean\"\n" + + " },\n" + + " \"privateProperties\": {\n" + + " \"cx-common:query\":%9$s\n" + + " }\n" + + " },\n" + + " \"dataAddress\": {\n" + + " \"id\":\"%1$s\",\n" + + " \"@type\": \"DataAddress\",\n" + + " \"type\": \"cx-common:Protocol?w3c:http:SKILL\",\n" + + " \"baseUrl\":\"https://w3id.org/catenax\",\n" + + " \"proxyPath\": \"false\",\n" + + " \"proxyMethod\": \"true\",\n" + + " \"proxyQueryParams\": \"true\",\n" + + " \"proxyBody\": \"true\"\n" + + " }\n" + + "}\n"; + + public static final String SKILL_ASSET_CREATE_BODY_V3 = "{\n" + + " \"@context\": {\n" + + " \"rdf\": \"http://www.w3.org/1999/02/22-rdf-syntax-ns#\",\n" + + " \"rdfs\": \"http://www.w3.org/2000/01/rdf-schema#\",\n" + + " \"cx-common\": \"https://w3id.org/catenax/ontology/common#\",\n" + + " \"sh\": \"http://www.w3.org/ns/shacl#\"\n" + + " },\n" + + " \"@id\": \"%1$s\", \n" + + " \"properties\": {\n" + + " \"name\": \"%2$s\",\n" + + " \"description\": \"%3$s\",\n" + + " \"version\": \"%4$s\",\n" + + " \"contenttype\": \"application/json, application/xml\",\n" + + "%5$s" + + " \"rdf:type\": \"cx-common:SkillAsset\",\n" + + " \"rdfs:isDefinedBy\": \"%6$s\",\n" + + " \"cx-common:implementsProtocol\": \"cx-common:Protocol?w3c:http:SKILL\",\n" + + " \"cx-common:distributionMode\": \"%7$s\",\n" + + " \"cx-common:isFederated\": \"%8$b^^xsd:boolean\"\n" + + " },\n" + + " \"privateProperties\": {\n" + + " \"cx-common:query\":%9$s\n" + + " },\n" + + " \"dataAddress\": {\n" + + " \"id\":\"%1$s\",\n" + + " \"@type\": \"DataAddress\",\n" + + " \"type\": \"cx-common:Protocol?w3c:http:SKILL\",\n" + + " \"baseUrl\":\"https://w3id.org/catenax\",\n" + + " \"proxyPath\": \"false\",\n" + + " \"proxyMethod\": \"true\",\n" + + " \"proxyQueryParams\": \"true\",\n" + + " \"proxyBody\": \"true\"\n" + + " }\n" + + "}\n"; + + + /** + * template for graph asset creation + */ + public static final String GRAPH_ASSET_CREATE_BODY = "{\n" + + " \"@context\": {\n" + + " \"rdf\": \"http://www.w3.org/1999/02/22-rdf-syntax-ns#\",\n" + + " \"rdfs\": \"http://www.w3.org/2000/01/rdf-schema#\",\n" + + " \"cx-common\": \"https://w3id.org/catenax/ontology/common#\",\n" + + " \"xsd\": \"http://www.w3.org/2001/XMLSchema#\",\n" + + " \"sh\": \"http://www.w3.org/ns/shacl#\"\n" + + " },\n" + + " \"asset\": {\n" + + " \"@type\": \"Asset\",\n" + + " \"@id\": \"%1$s\", \n" + + " \"properties\": {\n" + + " \"name\": \"%2$s\",\n" + + " \"description\": \"%3$s\",\n" + + " \"version\": \"%4$s\",\n" + + " \"contenttype\": \"application/json, application/xml\",\n" + + "%5$s" + + " \"rdf:type\": \"cx-common:GraphAsset\",\n" + + " \"rdfs:isDefinedBy\": \"%6$s\",\n" + + " \"cx-common:implementsProtocol\": \"cx-common:Protocol?w3c:http:SPARQL\",\n" + + " \"sh:shapesGraph\": \"%7$s\",\n" + + " \"cx-common:isFederated\": \"%8$b^^xsd:boolean\"\n" + + " }\n" + + " },\n" + + " \"dataAddress\": {\n" + + " \"id\": \"%1$s\", \n" + + " \"@type\": \"DataAddress\",\n" + + " \"type\": \"cx-common:Protocol?w3c:http:SPARQL\",\n" + + " \"baseUrl\":\"https://w3id.org/catenax\",\n" + + " \"proxyPath\": \"false\",\n" + + " \"proxyMethod\": \"true\",\n" + + " \"proxyQueryParams\": \"true\",\n" + + " \"proxyBody\": \"true\"\n" + + " }\n" + + "}\n"; + + public static final String GRAPH_ASSET_CREATE_BODY_V3 = "{\n" + + " \"@context\": {\n" + + " \"rdf\": \"http://www.w3.org/1999/02/22-rdf-syntax-ns#\",\n" + + " \"rdfs\": \"http://www.w3.org/2000/01/rdf-schema#\",\n" + + " \"cx-common\": \"https://w3id.org/catenax/ontology/common#\",\n" + + " \"xsd\": \"http://www.w3.org/2001/XMLSchema#\",\n" + + " \"sh\": \"http://www.w3.org/ns/shacl#\"\n" + + " },\n" + + " \"@id\": \"%1$s\", \n" + + " \"properties\": {\n" + + " \"name\": \"%2$s\",\n" + + " \"description\": \"%3$s\",\n" + + " \"version\": \"%4$s\",\n" + + " \"contenttype\": \"application/json, application/xml\",\n" + + "%5$s" + + " \"rdf:type\": \"cx-common:GraphAsset\",\n" + + " \"rdfs:isDefinedBy\": \"%6$s\",\n" + + " \"cx-common:implementsProtocol\": \"cx-common:Protocol?w3c:http:SPARQL\",\n" + + " \"sh:shapesGraph\": \"%7$s\",\n" + + " \"cx-common:isFederated\": \"%8$b^^xsd:boolean\"\n" + + " },\n" + + " \"dataAddress\": {\n" + + " \"id\": \"%1$s\", \n" + + " \"@type\": \"DataAddress\",\n" + + " \"type\": \"cx-common:Protocol?w3c:http:SPARQL\",\n" + + " \"baseUrl\":\"https://w3id.org/catenax\",\n" + + " \"proxyPath\": \"false\",\n" + + " \"proxyMethod\": \"true\",\n" + + " \"proxyQueryParams\": \"true\",\n" + + " \"proxyBody\": \"true\"\n" + + " }\n" + + "}\n"; + + public static final String ASSET_CALL = "%s%s/assets/request"; + + // negotiation request 0.5.>=1 + public static final String NEGOTIATION_REQUEST_BODY = "{\n" + + "\"@context\": { \"odrl\": \"http://www.w3.org/ns/odrl/2/\"},\n" + + "\"@type\": \"NegotiationInitiateRequestDto\",\n" + + "\"connectorAddress\": \"%1$s\",\n" + + "\"protocol\": \"dataspace-protocol-http\",\n" + + "\"providerId\": \"%3$s\",\n" + + "\"connectorId\": \"%2$s\",\n" + + "\"offer\": {\n" + + " \"offerId\": \"%4$s\",\n" + + " \"assetId\": \"%5$s\",\n" + + " \"policy\": %6$s\n" + + "}\n" + + "}"; + + // negotiation request 0.5.0 - roles of provider and connector are wrong + public static final String NEGOTIATION_REQUEST_BODY_PRERELEASE = "{\n" + + "\"@context\": { \"odrl\": \"http://www.w3.org/ns/odrl/2/\"},\n" + + "\"@type\": \"NegotiationInitiateRequestDto\",\n" + + "\"connectorAddress\": \"%1$s\",\n" + + "\"protocol\": \"dataspace-protocol-http\",\n" + + "\"providerId\": \"%2$s\",\n" + + "\"connectorId\": \"%3$s\",\n" + + "\"offer\": {\n" + + " \"offerId\": \"%4$s\",\n" + + " \"assetId\": \"%5$s\",\n" + + " \"policy\": %6$s\n" + + "}\n" + + "}"; + + + public static final String NEGOTIATION_INITIATE_CALL = "%s/v2/contractnegotiations"; + public static final String NEGOTIATION_CHECK_CALL = "%s/v2/contractnegotiations/%s"; + public static final String TRANSFER_INITIATE_CALL = "%s/v2/transferprocesses"; + + public static final String TRANSFER_REQUEST_BODY = "{\n" + + " \"@context\": {\n" + + " \"odrl\": \"http://www.w3.org/ns/odrl/2/\"\n" + + " },\n" + + " \"assetId\": \"%1$s\",\n" + + " \"connectorAddress\": \"%2$s\",\n" + + " \"connectorId\": \"%5$s\",\n" + + " \"contractId\": \"%3$s\",\n" + + " \"dataDestination\": {\n" + + " \"type\": \"HttpProxy\"\n" + + " },\n" + + " \"managedResources\": false,\n" + + " \"privateProperties\": {\n" + + " \"receiverHttpEndpoint\": \"%4$s\"\n" + + " },\n" + + " \"protocol\": \"dataspace-protocol-http\",\n" + + " \"transferType\": {\n" + + " \"contentType\": \"application/octet-stream\",\n" + + " \"isFinite\": true\n" + + " }\n" + + "}"; + public static final String TRANSFER_CHECK_CALL = "%s/v2/transferprocesses/%s"; + public static final String AGREEMENT_CHECK_CALL = "%s/v2/contractagreements/%s"; + + /** + * references to EDC services + */ + private final Monitor monitor; + private final ObjectMapper objectMapper; + private final OkHttpClient httpClient; + private final AgentConfig config; + + /** + * creates a service wrapper + * + * @param monitor logger + * @param typeManager serialization + * @param httpClient remoting + * @param config typed config + */ + public DataManagementImpl(Monitor monitor, TypeManager typeManager, OkHttpClient httpClient, AgentConfig config) { + this.monitor = monitor; + this.objectMapper = typeManager.getMapper(); + this.httpClient = httpClient; + this.config = config; + } + + /** + * Search for a dedicated asset + * TODO imperformant + * TODO replace by accessing the federated data catalogue + * + * @param remoteControlPlaneIdsUrl url of the remote control plane ids endpoint + * @param assetId (connector-unique) identifier of the asset + * @return a collection of contract options to access the given asset + * @throws IOException in case that the remote call did not succeed + */ + public DcatCatalog findContractOffers(String remoteControlPlaneIdsUrl, String assetId) throws IOException { + QuerySpec findAsset = QuerySpec.Builder.newInstance().filter( + List.of(new Criterion("https://w3id.org/edc/v0.0.1/ns/id", "=", assetId)) + ).build(); + return getCatalog(remoteControlPlaneIdsUrl, findAsset); + } + + /** + * Access the catalogue + * + * @param remoteControlPlaneIdsUrl url of the remote control plane ids endpoint + * @param spec query specification + * @return catalog object + * @throws IOException in case something went wrong + */ + public DcatCatalog getCatalog(String remoteControlPlaneIdsUrl, QuerySpec spec) throws IOException { + + var url = String.format(CATALOG_CALL, config.getControlPlaneManagementUrl()); + var catalogSpec = String.format(CATALOG_REQUEST_BODY, String.format(DSP_PATH, remoteControlPlaneIdsUrl), objectMapper.writeValueAsString(spec)); + + var request = new Request.Builder().url(url).post(RequestBody.create(catalogSpec, MediaType.parse("application/json"))); + config.getControlPlaneManagementHeaders().forEach(request::addHeader); + //request.addHeader("x-api-key", "foo"); + monitor.debug("sending " + "http://oem-control-plane2:8181", null); + monitor.debug(SharedObjectManager.getInstance().convertToCurl(request.build())); + try (var response = httpClient.newCall(request.build()).execute()) { + var body = response.body(); + + if (!response.isSuccessful() || body == null) { + throw new InternalServerErrorException(format("Control plane responded with: %s %s", response.code(), body != null ? body.string() : "")); + } + + return JsonLd.processCatalog(body.string()); + } catch (Exception e) { + monitor.severe(format("Error in calling the control plane at %s", url), e); + throw e; + } + } + + /** + * Access the (provider control plane) catalogue + * + * @param spec query specification + * @return catalog object + * @throws IOException in case something went wrong + */ + public List listAssets(QuerySpec spec) throws IOException { + + String version = config.isPrerelease() ? "/v2" : "/v3"; + var url = String.format(ASSET_CALL, config.getControlPlaneManagementProviderUrl(), version); + var assetObject = (ObjectNode) objectMapper.readTree(objectMapper.writeValueAsString(spec)); + assetObject.set("@context", objectMapper.createObjectNode()); + var assetSpec = objectMapper.writeValueAsString(assetObject); + + var request = new Request.Builder().url(url).post(RequestBody.create(assetSpec, MediaType.parse("application/json"))); + config.getControlPlaneManagementHeaders().forEach(request::addHeader); + + try (var response = httpClient.newCall(request.build()).execute()) { + var body = response.body(); + + if (!response.isSuccessful() || body == null) { + throw new InternalServerErrorException(format("Control plane responded with: %s %s", response.code(), body != null ? body.string() : "")); + } + + return JsonLd.processAssetList(body.string()); + } catch (Exception e) { + monitor.severe(format("Error in calling the control plane at %s", url), e); + throw e; + } + } + + /** + * helper to create or update assets + * + * @param assetSpec json text of the asset description + * @return a response listing the id of the created/updated asset + * @throws IOException in case something goes wrong + */ + protected IdResponse createOrUpdateAsset(String assetId, String assetSpec) throws IOException { + String version = config.isPrerelease() ? "/v2" : "/v3"; + var url = String.format(ASSET_CREATE_CALL, config.getControlPlaneManagementProviderUrl(), version); + var request = new Request.Builder().url(url).post(RequestBody.create(assetSpec, MediaType.parse("application/json"))); + config.getControlPlaneManagementHeaders().forEach(request::addHeader); + + try (var response = httpClient.newCall(request.build()).execute()) { + ResponseBody body = response.body(); + + if (!response.isSuccessful() || body == null) { + + if (response.code() != 409 || body == null) { + throw new InternalServerErrorException(format("Control plane responded with: %s %s", response.code(), body != null ? body.string() : "")); + } + + url = String.format(ASSET_UPDATE_CALL, config.getControlPlaneManagementProviderUrl(), version, assetId); + var patchRequest = new Request.Builder().url(url).patch(RequestBody.create(assetSpec, MediaType.parse("application/json"))); + config.getControlPlaneManagementHeaders().forEach(patchRequest::addHeader); + + try (var patchResponse = httpClient.newCall(patchRequest.build()).execute()) { + body = patchResponse.body(); + if (!patchResponse.isSuccessful() || body == null) { + monitor.warning(format("Failure in updating the resource at %s. Ignoring", url)); + return null; + } + } + } + return JsonLd.processIdResponse(body.string()); + } catch (Exception e) { + monitor.severe(format("Error in calling the control plane at %s", url), e); + throw e; + } + } + + /** + * creates or updates a given skill asset + * + * @param assetId key + * @param name of skill + * @param description of skill + * @param version of skill + * @param contract of skill + * @param ontologies of skill + * @param distributionMode of skill + * @param isFederated whether it should be distributed + * @param query of skill + * @return idresponse + * @throws IOException in case interaction with EDC went wrong + */ + public IdResponse createOrUpdateSkill(String assetId, String name, String description, String version, String contract, String ontologies, String distributionMode, boolean isFederated, String query) throws IOException { + if (contract != null) { + contract = String.format(" \"cx-common:publishedUnderContract\": \"%1$s\",\n", contract); + } else { + contract = ""; + } + String body = config.isPrerelease() ? SKILL_ASSET_CREATE_BODY : SKILL_ASSET_CREATE_BODY_V3; + var assetSpec = String.format(body, assetId, name, description, version, contract, ontologies, distributionMode, isFederated, query); + return createOrUpdateAsset(assetId, assetSpec); + } + + /** + * creates or updates a given graph asset + * + * @param assetId key + * @param name of graph + * @param description of graph + * @param version of graph + * @param contract of graph + * @param ontologies of graph + * @param shape of graph + * @param isFederated whether it should be distributed + * @return idresponse + * @throws IOException in case interaction with EDC went wrong + */ + public IdResponse createOrUpdateGraph(String assetId, String name, String description, String version, String contract, String ontologies, String shape, boolean isFederated) throws IOException { + if (contract != null) { + contract = String.format(" \"cx-common:publishedUnderContract\": \"%1$s\",\n", contract); + } else { + contract = ""; + } + String body = config.isPrerelease() ? GRAPH_ASSET_CREATE_BODY : GRAPH_ASSET_CREATE_BODY_V3; + var assetSpec = String.format(body, assetId, name, description, version, contract, ontologies, shape, isFederated); + return createOrUpdateAsset(assetId, assetSpec); + } + + /** + * deletes an existing aseet + * + * @param assetId key of the asset + * @return idresponse + */ + + public IdResponse deleteAsset(String assetId) throws IOException { + String version = config.isPrerelease() ? "/v2" : "/v3"; + var url = String.format(ASSET_UPDATE_CALL, config.getControlPlaneManagementProviderUrl(), version, assetId); + var request = new Request.Builder().url(url).delete(); + config.getControlPlaneManagementHeaders().forEach(request::addHeader); + try (var response = httpClient.newCall(request.build()).execute()) { + ResponseBody body = response.body(); + if (response.isSuccessful() && body != null) { + return JsonLd.processIdResponse(body.string()); + } else { + monitor.warning(format("Failure in calling the control plane at %s. Ignoring", url)); + return null; + } + } catch (Exception e) { + monitor.severe(format("Error in calling the control plane at %s", url), e); + throw e; + } + } + + /** + * initiates negotation + * + * @param negotiationRequest outgoing request + * @return negotiation id + * @throws IOException in case something went wronf + */ + public String initiateNegotiation(ContractNegotiationRequest negotiationRequest) throws IOException { + var url = String.format(NEGOTIATION_INITIATE_CALL, config.getControlPlaneManagementUrl()); + + String template = config.isPrerelease() ? NEGOTIATION_REQUEST_BODY_PRERELEASE : NEGOTIATION_REQUEST_BODY; + var negotiateSpec = String.format(template, + negotiationRequest.getConnectorAddress(), + negotiationRequest.getLocalBusinessPartnerNumber(), + negotiationRequest.getRemoteBusinessPartnerNumber(), + negotiationRequest.getOffer().getOfferId(), + negotiationRequest.getOffer().getAssetId(), + negotiationRequest.getOffer().getPolicy().asString()); + + var requestBody = RequestBody.create(negotiateSpec, MediaType.parse("application/json")); + + var request = new Request.Builder() + .url(url) + .post(requestBody); + config.getControlPlaneManagementHeaders().forEach(request::addHeader); + + try (var response = httpClient.newCall(request.build()).execute()) { + var body = response.body(); + + if (!response.isSuccessful() || body == null) { + throw new InternalServerErrorException(format("Control plane responded with: %s %s", response.code(), body != null ? body.string() : "")); + } + + + var negotiationId = JsonLd.processIdResponse(body.string()).getId(); + + monitor.debug("Started negotiation with ID: " + negotiationId); + + return negotiationId; + } catch (Exception e) { + monitor.severe(format("Error in calling the control plane at %s", url), e); + throw e; + } + } + + /** + * return state of contract negotiation + * + * @param negotiationId id of the negotation to inbestigate + * @return status of the negotiation + * @throws IOException in case something went wrong + */ + public ContractNegotiation getNegotiation(String negotiationId) throws IOException { + var url = String.format(NEGOTIATION_CHECK_CALL, config.getControlPlaneManagementUrl(), negotiationId); + var request = new Request.Builder() + .url(url); + config.getControlPlaneManagementHeaders().forEach(request::addHeader); + + try (var response = httpClient.newCall(request.build()).execute()) { + var body = response.body(); + + if (!response.isSuccessful() || body == null) { + throw new InternalServerErrorException(format("Control plane responded with: %s %s", response.code(), body != null ? body.string() : "")); + } + + var negotiation = JsonLd.processContractNegotiation(body.string()); + monitor.debug(format("Negotiation %s is in state '%s' (agreementId: %s)", negotiationId, negotiation.getState(), negotiation.getContractAgreementId())); + + return negotiation; + } catch (Exception e) { + monitor.severe(format("Error in calling the Control plane at %s", url), e); + throw e; + } + } + + /** + * get a contract agreement by its id + * + * @param agreementId id of the agreement + * @return contract agreement + * @throws IOException something wild happens + */ + public ContractAgreement getAgreement(String agreementId) throws IOException { + var url = String.format(AGREEMENT_CHECK_CALL, config.getControlPlaneManagementUrl(), URLEncoder.encode(agreementId, StandardCharsets.UTF_8)); + var request = new Request.Builder() + .url(url); + config.getControlPlaneManagementHeaders().forEach(request::addHeader); + + try (var response = httpClient.newCall(request.build()).execute()) { + var body = response.body(); + + if (!response.isSuccessful() || body == null) { + throw new InternalServerErrorException(format("Control plane responded with: %s %s", response.code(), body != null ? body.string() : "")); + } + + var agreement = JsonLd.processContractAgreement(body.string()); + monitor.debug(format("Agreement %s found for asset %s", agreementId, agreement.getAssetId())); + + return agreement; + } catch (Exception e) { + monitor.severe(format("Error in calling the Control plane at %s", url), e); + throw e; + } + } + + /** + * Initiates a transfer + * + * @param transferRequest request + * @return transfer id + * @throws IOException in case something went wrong + */ + public String initiateHttpProxyTransferProcess(TransferRequest transferRequest) throws IOException { + var url = String.format(TRANSFER_INITIATE_CALL, config.getControlPlaneManagementUrl()); + + var transferSpec = String.format(TRANSFER_REQUEST_BODY, + transferRequest.getAssetId(), + transferRequest.getConnectorAddress(), + transferRequest.getContractId(), + transferRequest.getCallbackAddresses().get(0).getUri(), + transferRequest.getConnectorAddress()); + + var requestBody = RequestBody.create(transferSpec, MediaType.parse("application/json")); + + var request = new Request.Builder() + .url(url) + .post(requestBody); + config.getControlPlaneManagementHeaders().forEach(request::addHeader); + + try (var response = httpClient.newCall(request.build()).execute()) { + var body = response.body(); + + if (!response.isSuccessful() || body == null) { + throw new InternalServerErrorException(format("Control plane responded with: %s %s", response.code(), body != null ? body.string() : "")); + } + + // For debugging purposes: + // var transferProcessId = TransferId.Builder.newInstance().id(body.string()).build(); + var transferProcessId = JsonLd.processIdResponse(body.string()).getId(); + + monitor.debug(format("Transfer process (%s) initiated", transferProcessId)); + + return transferProcessId; + } catch (Exception e) { + monitor.severe(format("Error in calling the control plane at %s", url), e); + throw e; + } + } + + /** + * return state of transfer process + * + * @param transferProcessId id of the transfer process + * @return state of the transfer process + * @throws IOException in case something went wrong + */ + public TransferProcess getTransfer(String transferProcessId) throws IOException { + var url = String.format(TRANSFER_CHECK_CALL, config.getControlPlaneManagementUrl(), transferProcessId); + var request = new Request.Builder() + .url(url); + config.getControlPlaneManagementHeaders().forEach(request::addHeader); + + try (var response = httpClient.newCall(request.build()).execute()) { + var body = response.body(); + + if (!response.isSuccessful() || body == null) { + throw new InternalServerErrorException(format("Control plane responded with: %s %s", response.code(), body != null ? body.string() : "")); + } + + var process = JsonLd.processTransferProcess(body.string()); + monitor.info(format("Transfer %s is in state '%s'", transferProcessId, process.getState())); + + return process; + } catch (Exception e) { + monitor.severe(format("Error in calling the Control plane at %s", url), e); + throw e; + } + } + +} \ No newline at end of file diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataspaceSynchronizer.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataspaceSynchronizer.java new file mode 100644 index 00000000..f631b3f8 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataspaceSynchronizer.java @@ -0,0 +1,337 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.service; + +import jakarta.json.Json; +import jakarta.json.JsonValue; +import org.apache.jena.atlas.lib.Sink; +import org.apache.jena.graph.Node; +import org.apache.jena.graph.NodeFactory; +import org.apache.jena.riot.Lang; +import org.apache.jena.riot.RDFParser; +import org.apache.jena.riot.lang.StreamRDFCounting; +import org.apache.jena.riot.system.ErrorHandler; +import org.apache.jena.riot.system.ErrorHandlerFactory; +import org.apache.jena.riot.system.StreamRDF; +import org.apache.jena.riot.system.StreamRDFLib; +import org.apache.jena.sparql.core.Quad; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.query.Criterion; +import org.eclipse.edc.spi.query.QuerySpec; +import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.edc.MonitorWrapper; +import org.eclipse.tractusx.agents.edc.jsonld.JsonLd; +import org.eclipse.tractusx.agents.edc.model.DcatCatalog; +import org.eclipse.tractusx.agents.edc.model.DcatDataset; +import org.eclipse.tractusx.agents.edc.rdf.RdfStore; + +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * A service which keeps a triple store and + * the associated dataspace in sync + */ +public class DataspaceSynchronizer implements Runnable { + + /** + * constants + */ + protected static final Node CX_ASSET = NodeFactory.createURI("https://w3id.org/catenax/ontology/common#offers"); + protected static final Map ASSET_PROPERTY_MAP = new HashMap<>(); + protected static final QuerySpec FEDERATED_ASSET_QUERY = QuerySpec.Builder.newInstance() + .filter(List.of(new Criterion("https://w3id.org/catenax/ontology/common#isFederated", "=", "true^^xsd:boolean"))).build(); + + protected MonitorWrapper monitorWrapper; + + static { + ASSET_PROPERTY_MAP.put("https://w3id.org/edc/v0.0.1/ns/id", NodeFactory.createURI("https://w3id.org/catenax/ontology/common#id")); + ASSET_PROPERTY_MAP.put("https://w3id.org/edc/v0.0.1/ns/name", NodeFactory.createURI("https://w3id.org/catenax/ontology/common#name")); + ASSET_PROPERTY_MAP.put("https://w3id.org/edc/v0.0.1/ns/description", NodeFactory.createURI("https://w3id.org/catenax/ontology/common#description")); + ASSET_PROPERTY_MAP.put("https://w3id.org/edc/v0.0.1/ns/version", NodeFactory.createURI("https://w3id.org/catenax/ontology/common#version")); + ASSET_PROPERTY_MAP.put("https://w3id.org/edc/v0.0.1/ns/contenttype", NodeFactory.createURI("https://w3id.org/catenax/ontology/common#contentType")); + ASSET_PROPERTY_MAP.put("http://www.w3.org/1999/02/22-rdf-syntax-ns#type", NodeFactory.createURI("http://www.w3.org/1999/02/22-rdf-syntax-ns#type")); + ASSET_PROPERTY_MAP.put("http://www.w3.org/2000/01/rdf-schema#isDefinedBy", NodeFactory.createURI("http://www.w3.org/2000/01/rdf-schema#isDefinedBy")); + ASSET_PROPERTY_MAP.put("https://w3id.org/catenax/ontology/common#implementsProtocol", NodeFactory.createURI("https://w3id.org/catenax/ontology/common#implementsProtocol")); + ASSET_PROPERTY_MAP.put("http://www.w3.org/ns/shacl#shapesGraph", NodeFactory.createURI("http://www.w3.org/ns/shacl#shapesGraph")); + ASSET_PROPERTY_MAP.put("https://w3id.org/catenax/ontology/common#isFederated", NodeFactory.createURI("https://w3id.org/catenax/ontology/common#isFederated")); + ASSET_PROPERTY_MAP.put("https://w3id.org/catenax/ontology/common#publishedUnderContract", NodeFactory.createURI("https://w3id.org/catenax/ontology/common#publishedUnderContract")); + ASSET_PROPERTY_MAP.put("https://w3id.org/catenax/ontology/common#satisfiesRole", NodeFactory.createURI("https://w3id.org/catenax/ontology/common#satisfiesRole")); + } + + /** + * service links + */ + protected final ScheduledExecutorService service; + protected final AgentConfig config; + protected final DataManagement dataManagement; + protected final RdfStore rdfStore; + protected final Monitor monitor; + + /** + * internal state + */ + protected boolean isStarted = false; + + /** + * creates the synchronizer + * + * @param service scheduler + * @param config edc config + * @param dataManagement data management service remoting + * @param rdfStore a triple store for persistance + * @param monitor logging subsystem + */ + public DataspaceSynchronizer(ScheduledExecutorService service, AgentConfig config, DataManagement dataManagement, RdfStore rdfStore, Monitor monitor) { + this.service = service; + this.config = config; + this.dataManagement = dataManagement; + this.rdfStore = rdfStore; + this.monitor = monitor; + this.monitorWrapper = new MonitorWrapper(getClass().getName(), monitor); + } + + /** + * starts the synchronizer + */ + public synchronized void start() { + if (!isStarted) { + isStarted = true; + long interval = config.getDataspaceSynchronizationInterval(); + String[] connectors = config.getDataspaceSynchronizationConnectors(); + if (interval > 0 && connectors != null && connectors.length > 0) { + monitor.info(String.format("Starting dataspace synchronization on %d connectors with interval %d milliseconds", connectors.length, interval)); + service.schedule(this, interval, TimeUnit.MILLISECONDS); + } + } + } + + /** + * stops the synchronizer + */ + public synchronized void shutdown() { + if (isStarted) { + monitor.info("Shutting down dataspace synchronization"); + isStarted = false; + service.shutdown(); + } + } + + /** + * runs the synchronizer when scheduled + */ + @Override + public void run() { + monitor.debug("Synchronization run has been started"); + if (isStarted) { + for (String remote : config.getDataspaceSynchronizationConnectors()) { + if (isStarted) { + monitor.debug(String.format("About to synchronize remote connector %s", remote)); + rdfStore.startTx(); + try { + DcatCatalog catalog = dataManagement.getCatalog(remote, FEDERATED_ASSET_QUERY); + Node graph = rdfStore.getDefaultGraph(); + Node connector = NodeFactory.createURI(remote.replace("https", "edcs").replace("http", "edc")); + Quad findAssets = Quad.create(graph, connector, CX_ASSET, Node.ANY); + Iterator assetQuads = rdfStore.getDataSet().find(findAssets); + int tupleCount = 0; + while (assetQuads.hasNext()) { + Quad quadAsset = assetQuads.next(); + Quad findAssetProps = Quad.create(graph, quadAsset.getObject(), Node.ANY, Node.ANY); + Iterator propQuads = rdfStore.getDataSet().find(findAssetProps); + while (propQuads.hasNext()) { + Quad quadProp = propQuads.next(); + if (quadProp.getPredicate().isURI() && quadProp.getPredicate().getURI().equals("http://www.w3.org/ns/shacl#shapesGraph") && quadProp.getObject().isURI()) { + Quad findSubGraphsProps = Quad.create(quadProp.getObject(), Node.ANY, Node.ANY, Node.ANY); + Iterator subGraphQuads = rdfStore.getDataSet().find(findSubGraphsProps); + while (subGraphQuads.hasNext()) { + rdfStore.getDataSet().delete(subGraphQuads.next()); + tupleCount++; + } + } + rdfStore.getDataSet().delete(quadProp); + tupleCount++; + } + rdfStore.getDataSet().delete(quadAsset); + tupleCount++; + } + monitor.debug(String.format("About to delete %d old tuples.", tupleCount)); + List offers = catalog.getDatasets(); + tupleCount = 0; + if (offers != null) { + monitor.debug(String.format("Found a catalog with %d entries for remote connector %s", offers.size(), remote)); + for (DcatDataset offer : catalog.getDatasets()) { + for (Quad quad : convertToQuads(graph, connector, offer)) { + tupleCount++; + rdfStore.getDataSet().add(quad); + } + } + } else { + monitor.warning(String.format("Found an empty catalog for remote connector %s", remote)); + } + monitor.debug(String.format("About to add %d new tuples.", tupleCount)); + rdfStore.commit(); + } catch (Throwable io) { + monitor.warning(String.format("Could not synchronize remote connector %s because of %s. Going ahead.", remote, io)); + rdfStore.abort(); + } + } else { + monitor.debug(String.format("Synchronization is no more active. Skipping all connectors starting from %s.", remote)); + break; + } + } // for + if (isStarted) { + monitor.debug("Schedule next synchronization run"); + service.schedule(this, config.getDataspaceSynchronizationInterval(), TimeUnit.MILLISECONDS); + } else { + monitor.debug("Synchronization is no more active. Disable next run."); + } + } + } + + /** + * Workaround the castration of the IDS catalogue + * + * @param offer being made + * @return default props + */ + public static Map getProperties(DcatDataset offer) { + Map assetProperties = new HashMap<>(offer.getProperties()); + if (!assetProperties.containsKey("http://www.w3.org/1999/02/22-rdf-syntax-ns#type")) { + String assetType = JsonLd.asString(assetProperties.getOrDefault("@id", Json.createValue("cx-common:Asset"))); + int indexOfQuestion = assetType.indexOf("?"); + if (indexOfQuestion > 0) { + assetType = assetType.substring(0, indexOfQuestion - 1); + } + assetProperties.put("http://www.w3.org/1999/02/22-rdf-syntax-ns#type", Json.createValue(assetType)); + } + if (!assetProperties.containsKey("@id")) { + assetProperties.put("@id", Json.createValue(UUID.randomUUID().toString())); + } + return assetProperties; + } + + /** + * convert a given contract offer into quads + * + * @param graph default graph + * @param connector parent connector hosting the offer + * @param offer the contract offer + * @return a collection of quads + */ + public Collection convertToQuads(Node graph, Node connector, DcatDataset offer) { + Map assetProperties = getProperties(offer); + + List quads = new ArrayList<>(); + String offerId = assetProperties.get("@id").toString(); + Node assetNode = NodeFactory.createURI(offerId); + quads.add(Quad.create(graph, + connector, + CX_ASSET, + assetNode)); + for (Map.Entry assetProp : assetProperties.entrySet()) { + String key = assetProp.getKey(); + Node node = ASSET_PROPERTY_MAP.get(key); + while (node == null && key.indexOf('.') >= 0) { + key = key.substring(key.lastIndexOf(".") + 1); + node = ASSET_PROPERTY_MAP.get(key); + } + if (node != null) { + String pureProperty = JsonLd.asString(assetProp.getValue()); + if (pureProperty != null) { + try { + switch (key) { + case "https://w3id.org/catenax/ontology/common#publishedUnderContract": + case "http://www.w3.org/2000/01/rdf-schema#isDefinedBy": + case "http://www.w3.org/1999/02/22-rdf-syntax-ns#type": + case "https://w3id.org/catenax/ontology/common#isFederated": + case "https://w3id.org/catenax/ontology/common#satisfiesRole": + case "https://w3id.org/catenax/ontology/common#implementsProtocol": + String[] urls = pureProperty.split(","); + for (String url : urls) { + Node o; + url = url.trim(); + if (url.startsWith("<") && url.endsWith(">")) { + url = url.substring(1, url.length() - 1); + o = NodeFactory.createURI(url); + } else if (url.startsWith("\"") && url.endsWith("\"")) { + url = url.substring(1, url.length() - 1); + o = NodeFactory.createLiteral(url); + } else if (url.startsWith("cx-common:")) { + url = url.substring(10); + o = NodeFactory.createURI("https://w3id.org/catenax/ontology/common#" + url); + } else if (url.contains("^^")) { + int typeAnnotation = url.indexOf("^^"); + String type = url.substring(typeAnnotation + 2); + url = url.substring(0, typeAnnotation); + o = NodeFactory.createLiteral(url, NodeFactory.getType(type)); + } else { + o = NodeFactory.createLiteral(url); + } + quads.add(Quad.create(graph, assetNode, node, o)); + } + break; + case "http://www.w3.org/ns/shacl#shapesGraph": + Node newGraph = NodeFactory.createURI("https://w3id.org/catenax/ontology/common#GraphShape?id=" + offerId.hashCode()); + quads.add(Quad.create(graph, assetNode, node, newGraph)); + Sink quadSink = new Sink<>() { + + @Override + public void close() { + } + + @Override + public void send(Quad quad) { + quads.add(quad); + } + + @Override + public void flush() { + } + }; + StreamRDF dest = StreamRDFLib.sinkQuads(quadSink); + StreamRDF graphDest = StreamRDFLib.extendTriplesToQuads(newGraph, dest); + StreamRDFCounting countingDest = StreamRDFLib.count(graphDest); + ErrorHandler errorHandler = ErrorHandlerFactory.errorHandlerStd(monitorWrapper); + RDFParser.create() + .errorHandler(errorHandler) + .source(new StringReader(pureProperty)) + .lang(Lang.TTL) + .parse(countingDest); + monitor.debug(String.format("Added shapes subgraph %s with %d triples", newGraph, countingDest.countTriples())); + break; + default: + quads.add(Quad.create(graph, assetNode, node, NodeFactory.createLiteral(pureProperty))); + } //switch + } catch (Throwable t) { + monitor.debug(String.format("Could not correctly add asset triples for predicate %s with original value %s because of %s", node, pureProperty, t.getMessage())); + } + } // if property!=null + } // if node!=null + } // for + return quads; + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/EdcSkillStore.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/EdcSkillStore.java new file mode 100644 index 00000000..13fe5e96 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/EdcSkillStore.java @@ -0,0 +1,114 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.service; + +import com.fasterxml.jackson.databind.node.TextNode; +import org.eclipse.edc.spi.query.Criterion; +import org.eclipse.edc.spi.query.QuerySpec; +import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.edc.SkillDistribution; +import org.eclipse.tractusx.agents.edc.SkillStore; +import org.eclipse.tractusx.agents.edc.jsonld.JsonLd; +import org.eclipse.tractusx.agents.edc.model.Asset; + +import java.io.IOException; +import java.util.List; +import java.util.Optional; + +/** + * Implements a skill store based on EDC assets + */ +public class EdcSkillStore implements SkillStore { + + DataManagement management; + TypeManager typeManager; + AgentConfig config; + + public EdcSkillStore(DataManagement management, TypeManager typeManager, AgentConfig config) { + this.management = management; + this.typeManager = typeManager; + this.config = config; + } + + @Override + public boolean isSkill(String key) { + return SkillStore.matchSkill(key).matches(); + } + + @Override + public String put(String key, String skill, String name, String description, String version, String contract, SkillDistribution dist, boolean isFederated, String... ontologies) { + if (name == null) { + name = "No name given"; + } + if (description == null) { + description = "No description given"; + } + if (version == null) { + version = "unknown version"; + } + if (contract == null) { + contract = config.getDefaultSkillContract(); + } + String ontologiesString = String.join(",", ontologies); + try { + return management.createOrUpdateSkill( + key, + name, + description, + version, + contract, + ontologiesString, + dist.getDistributionMode(), + isFederated, + typeManager.getMapper().writeValueAsString(TextNode.valueOf(skill)) + ).getId(); + } catch (IOException e) { + return null; + } + } + + @Override + public SkillDistribution getDistribution(String key) { + return findAsset(key).map(asset -> SkillDistribution.valueOfMode(JsonLd.asString(asset.getPublicProperties() + .get("https://w3id.org/catenax/ontology/common#distributionMode")))).orElse(SkillDistribution.ALL); + } + + /** + * finds an asset + */ + protected Optional findAsset(String key) { + QuerySpec findAsset = QuerySpec.Builder.newInstance().filter( + List.of(new Criterion("https://w3id.org/edc/v0.0.1/ns/id", "=", key), + new Criterion("http://www.w3.org/1999/02/22-rdf-syntax-ns#type", "=", "cx-common:SkillAsset"))).build(); + try { + // we need to filter until the criterion really works + return management + .listAssets(findAsset).stream() + .findFirst(); + } catch (IOException e) { + return Optional.empty(); + } + } + + @Override + public Optional get(String key) { + return findAsset(key).map(asset -> + JsonLd.asString(asset.getPrivateProperties().get("https://w3id.org/catenax/ontology/common#query")) + ); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/InMemorySkillStore.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/InMemorySkillStore.java new file mode 100644 index 00000000..744be30c --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/InMemorySkillStore.java @@ -0,0 +1,64 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.service; + +import org.eclipse.tractusx.agents.edc.SkillDistribution; +import org.eclipse.tractusx.agents.edc.SkillStore; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +/** + * An in-memory store for local skills + */ +public class InMemorySkillStore implements SkillStore { + + // temporary local skill store + protected final Map skills = new HashMap<>(); + + /** + * create the store + */ + public InMemorySkillStore() { + } + + @Override + public boolean isSkill(String key) { + return SkillStore.matchSkill(key).matches(); + } + + @Override + public String put(String key, String skill, String name, String description, String version, String contract, SkillDistribution dist, boolean isFederated, String... ontologies) { + skills.put(key, skill); + return key; + } + + @Override + public SkillDistribution getDistribution(String key) { + return SkillDistribution.ALL; + } + + @Override + public Optional get(String key) { + if (!skills.containsKey(key)) { + return Optional.empty(); + } else { + return Optional.of(skills.get(key)); + } + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/CatenaxWarning.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/CatenaxWarning.java new file mode 100644 index 00000000..c27a3fbf --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/CatenaxWarning.java @@ -0,0 +1,247 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.sparql; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.jena.sparql.util.Context; +import org.apache.jena.sparql.util.Symbol; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * a warning + */ +public class CatenaxWarning { + public static Symbol cxWarnings = Symbol.create("cx:warnings"); + + /** + * access the thread local + * + * @return current warnings + */ + public static List getWarnings(Context context) { + return context.get(cxWarnings, null); + } + + /** + * access the thread local + * + * @return current warnings or empty list + */ + public static List getOrSetWarnings(Context context) { + List result = getWarnings(context); + if (result == null) { + result = new ArrayList<>(); + setWarnings(context, result); + } + return result; + } + + /** + * set current warnings + * + * @param context to set into + * @param warnings the warning list + */ + public static void setWarnings(Context context, List warnings) { + context.put(cxWarnings, warnings); + } + + @JsonProperty("source-tenant") + private String sourceTenant = null; + + @JsonProperty("source-asset") + private String sourceAsset = null; + + @JsonProperty("target-tenant") + private String targetTenant = null; + + @JsonProperty("target-asset") + private String targetAsset = null; + + @JsonProperty("problem") + private String problem = null; + + @JsonProperty("context") + private String context = null; + + public CatenaxWarning sourceTenant(String sourceTenant) { + this.sourceTenant = sourceTenant; + return this; + } + + /** + * Get sourceTenant + * + * @return sourceTenant + **/ + @JsonProperty("source-tenant") + public String getSourceTenant() { + return sourceTenant; + } + + public void setSourceTenant(String sourceTenant) { + this.sourceTenant = sourceTenant; + } + + public CatenaxWarning sourceAsset(String sourceAsset) { + this.sourceAsset = sourceAsset; + return this; + } + + /** + * Get sourceAsset + * + * @return sourceAsset + **/ + @JsonProperty("source-asset") + public String getSourceAsset() { + return sourceAsset; + } + + public void setSourceAsset(String sourceAsset) { + this.sourceAsset = sourceAsset; + } + + public CatenaxWarning targetTenant(String targetTenant) { + this.targetTenant = targetTenant; + return this; + } + + /** + * Get targetTenant + * + * @return targetTenant + **/ + @JsonProperty("target-tenant") + public String getTargetTenant() { + return targetTenant; + } + + public void setTargetTenant(String targetTenant) { + this.targetTenant = targetTenant; + } + + public CatenaxWarning targetAsset(String targetAsset) { + this.targetAsset = targetAsset; + return this; + } + + /** + * Get targetAsset + * + * @return targetAsset + **/ + @JsonProperty("target-asset") + public String getTargetAsset() { + return targetAsset; + } + + public void setTargetAsset(String targetAsset) { + this.targetAsset = targetAsset; + } + + public CatenaxWarning problem(String problem) { + this.problem = problem; + return this; + } + + /** + * Get problem + * + * @return problem + **/ + @JsonProperty("problem") + public String getProblem() { + return problem; + } + + public void setProblem(String problem) { + this.problem = problem; + } + + public CatenaxWarning context(String context) { + this.context = context; + return this; + } + + /** + * Get context + * + * @return context + **/ + @JsonProperty("context") + public String getContext() { + return context; + } + + public void setContext(String context) { + this.context = context; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CatenaxWarning cxWarning = (CatenaxWarning) o; + return Objects.equals(this.sourceTenant, cxWarning.sourceTenant) && + Objects.equals(this.sourceAsset, cxWarning.sourceAsset) && + Objects.equals(this.targetTenant, cxWarning.targetTenant) && + Objects.equals(this.targetAsset, cxWarning.targetAsset) && + Objects.equals(this.problem, cxWarning.problem) && + Objects.equals(this.context, cxWarning.context); + } + + @Override + public int hashCode() { + return Objects.hash(sourceTenant, sourceAsset, targetTenant, targetAsset, problem, context); + } + + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class CatenaxWarning {\n"); + + sb.append(" sourceTenant: ").append(toIndentedString(sourceTenant)).append("\n"); + sb.append(" sourceAsset: ").append(toIndentedString(sourceAsset)).append("\n"); + sb.append(" targetTenant: ").append(toIndentedString(targetTenant)).append("\n"); + sb.append(" targetAsset: ").append(toIndentedString(targetAsset)).append("\n"); + sb.append(" problem: ").append(toIndentedString(problem)).append("\n"); + sb.append(" context: ").append(toIndentedString(context)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/DataspaceServiceExecutor.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/DataspaceServiceExecutor.java new file mode 100644 index 00000000..88415b35 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/DataspaceServiceExecutor.java @@ -0,0 +1,652 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.sparql; + +import com.fasterxml.jackson.databind.ObjectMapper; +import okhttp3.OkHttpClient; +import org.apache.jena.atlas.logging.Log; +import org.apache.jena.graph.Node; +import org.apache.jena.graph.NodeFactory; +import org.apache.jena.query.Query; +import org.apache.jena.query.QueryExecException; +import org.apache.jena.query.ResultSet; +import org.apache.jena.riot.ResultSetMgr; +import org.apache.jena.riot.WebContent; +import org.apache.jena.riot.resultset.ResultSetLang; +import org.apache.jena.sparql.algebra.Op; +import org.apache.jena.sparql.algebra.OpAsQuery; +import org.apache.jena.sparql.algebra.Transformer; +import org.apache.jena.sparql.algebra.op.OpProject; +import org.apache.jena.sparql.algebra.op.OpSequence; +import org.apache.jena.sparql.algebra.op.OpService; +import org.apache.jena.sparql.algebra.op.OpTable; +import org.apache.jena.sparql.algebra.table.TableData; +import org.apache.jena.sparql.core.Var; +import org.apache.jena.sparql.engine.ExecutionContext; +import org.apache.jena.sparql.engine.QueryIterator; +import org.apache.jena.sparql.engine.binding.Binding; +import org.apache.jena.sparql.engine.binding.BindingBuilder; +import org.apache.jena.sparql.engine.http.HttpParams; +import org.apache.jena.sparql.engine.iterator.QueryIter; +import org.apache.jena.sparql.engine.iterator.QueryIter1; +import org.apache.jena.sparql.engine.iterator.QueryIterPlainWrapper; +import org.apache.jena.sparql.exec.RowSet; +import org.apache.jena.sparql.exec.RowSetAdapter; +import org.apache.jena.sparql.exec.http.Params; +import org.apache.jena.sparql.exec.http.QuerySendMode; +import org.apache.jena.sparql.exec.http.Service; +import org.apache.jena.sparql.graph.NodeTransformLib; +import org.apache.jena.sparql.resultset.ResultSetMem; +import org.apache.jena.sparql.service.bulk.ChainingServiceExecutorBulk; +import org.apache.jena.sparql.service.bulk.ServiceExecutorBulk; +import org.apache.jena.sparql.service.single.ServiceExecutor; +import org.apache.jena.sparql.util.Context; +import org.apache.jena.sparql.util.Symbol; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; +import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.edc.AgreementController; +import org.eclipse.tractusx.agents.edc.http.HttpClientAdapter; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * A service executor (single and bulk mode) which replaces outgoing http calls + * by appropriate dataspace agreements/calls. + * Register in the ServiceExecutorRegistry via + * - add(...) for single execution + * - addBulkLink(...) for multiple execution + */ +public class DataspaceServiceExecutor implements ServiceExecutor, ChainingServiceExecutorBulk { + + /** + * EDC services + */ + final Monitor monitor; + final AgreementController agreementController; + final AgentConfig config; + final HttpClient client; + final ExecutorService executor; + final ObjectMapper objectMapper; + + /** + * some constants + */ + public static final Symbol AUTH_KEY_SYMBOL = Symbol.create("https://w3id.org/edc/v0.0.1/ns/authKey"); + public static final Symbol AUTH_CODE_SYMBOL = Symbol.create("https://w3id.org/edc/v0.0.1/ns/authCode"); + public static final Pattern EDC_TARGET_ADDRESS_PATTERN = Pattern.compile("((?edc|edcs)://(?[^#?]*))?(#(?[^/?]*))?(\\?(?.*))?"); + public static final Symbol TARGET_URL_SYMBOL = Symbol.create("https://w3id.org/edc/v0.0.1/ns/baseUrl"); + public static final Symbol ASSET_SYMBOL = Symbol.create("https://w3id.org/edc/v0.0.1/ns/id"); + public static final Symbol ALLOW_SYMBOL = Symbol.create("https://w3id.org/catenax/ontology/common#allowServicePattern"); + public static final Symbol DENY_SYMBOL = Symbol.create("https://w3id.org/catenax/ontology/common#denyServicePattern"); + + /** + * create a new executor + * + * @param monitor logging subsystem + * @param controller dataspace agreement + */ + public DataspaceServiceExecutor(Monitor monitor, AgreementController controller, AgentConfig config, OkHttpClient client, ExecutorService executor, TypeManager typeManager) { + this.monitor = monitor; + this.agreementController = controller; + this.config = config; + this.client = new HttpClientAdapter(client); + this.executor = executor; + this.objectMapper = typeManager.getMapper(); + } + + /** + * bulk execution call - this is the default + * TODO implement batch size per service and not globally + * + * @param opService bound operator + * @param queryIterator incoming bindings (may set service uri and input params) + * @param executionContext context + * @param serviceExecutorBulk bulk executor + * @return binding generating iterator + */ + @Override + public QueryIterator createExecution(OpService opService, QueryIterator queryIterator, ExecutionContext executionContext, ServiceExecutorBulk serviceExecutorBulk) { + Node serviceNode = opService.getService(); + Set boundVars = new HashSet<>(); + long batchSize = config.getFederationServiceBatchSize(); + + // + // returns an iterator over batches + // + return new QueryIter1(queryIterator, executionContext) { + + // the active iterator over the current batch + private QueryIterator batchIterator; + + /** + * check whether we still have something left in the current iterator + * or switch to the next batch + */ + @Override + protected boolean hasNextBinding() { + return (batchIterator != null && batchIterator.hasNext()) || hasNextResultBinding(); + } + + /** + * switch to the next batch + * + * @return whether next batch exists + */ + public boolean hasNextResultBinding() { + // do we have additional input bindings + if (this.getInput().hasNext()) { + // yes then read the next batch + Map> bindings = new HashMap<>(); + long batchLength = 0; + while (this.getInput().hasNext() && batchLength++ < batchSize) { + Binding binding = this.getInput().next(); + Iterator vars = binding.vars(); + while (vars.hasNext()) { + boundVars.add(vars.next().getVarName()); + } + // detect the service uri under the current binding + Node keyNode = serviceNode; + if (keyNode.isVariable()) { + keyNode = binding.get((Var) keyNode); + } + if (keyNode.isURI()) { + String key = keyNode.getURI(); + if (!bindings.containsKey(key)) { + bindings.put(key, new ArrayList<>()); + } + bindings.get(key).add(binding); + } else { + monitor.warning("Omitting a call because of lacking service binding"); + } + } + ExecutionContext ctx = this.getExecContext(); + + List> futureBindings = bindings.entrySet().stream().map(serviceSpec -> executor.submit(() -> + createExecution(opService, serviceSpec.getKey(), boundVars, serviceSpec.getValue(), ctx))).collect(Collectors.toList()); + + batchIterator = new QueryIterFutures(config, monitor, config.getControlPlaneManagementUrl(), config.getDefaultAsset(), serviceNode, ctx.getContext(), futureBindings); + return hasNextBinding(); + } else { + return false; + } + } + + /** + * the hasNextBinding call has already been done, so we simply call next + * on the current iterator - it should be there, otherwise it behaves as an orinary + * iterator who has no next binding + */ + @Override + protected Binding moveToNextBinding() { + return batchIterator.next(); + } + + /** + * no explicit sub canceling implemented, http is stateless in this respect + */ + @Override + protected void requestSubCancel() { + + } + + /** + * no explicit closing implemented, http is stateless in this respect + */ + @Override + protected void closeSubIterator() { + } + + }; + } + + /** + * single execution mode - this is not used anymore - batch mode is default + * + * @param opExecute the bound operator (if variable is used in service description) + * @param opOriginal the unbound operator + * @param binding the current binding + * @param execCxt the execution context + * @return a set of query results + */ + @Override + public QueryIterator createExecution(OpService opExecute, OpService opOriginal, Binding binding, ExecutionContext execCxt) { + // it maybe that a subselect has "masked" some input variables + Node serviceNode = opExecute.getService(); + if (serviceNode.isVariable()) { + serviceNode = binding.get((Var) serviceNode); + } + if (!serviceNode.isURI()) { + throw new QueryExecException("Service URI not bound: " + opExecute.getService()); + } + // check whether we need to route over EDC + String target = serviceNode.getURI(); + Set allowedVars = new HashSet<>(); + Iterator allAllowedVars = binding.vars(); + while (allAllowedVars.hasNext()) { + allowedVars.add(allAllowedVars.next().getVarName()); + } + return createExecution(opOriginal, target, allowedVars, List.of(binding), execCxt); + } + + /** + * (re-) implements the remote http service execution + * + * @param opOriginal the unbound operator + * @param serviceUrl uri of the target service + * @param boundVars a set of all bound variables + * @param bindings the current bindings + * @param execCxt the execution context + * @return a set of query results + */ + public QueryIterator createExecution(OpService opOriginal, String serviceUrl, Set boundVars, List bindings, ExecutionContext execCxt) { + Context context = execCxt.getContext(); + + // we have to only check outgoing URLs which have not already been checked + String targetUrl = context.get(DataspaceServiceExecutor.TARGET_URL_SYMBOL); + if (!serviceUrl.equalsIgnoreCase(targetUrl)) { + // check whether the service url is allowed (in the context, in the default) + Pattern allowPattern = context.get(ALLOW_SYMBOL, config.getServiceAllowPattern()); + if (!allowPattern.matcher(serviceUrl).matches()) { + throw new QueryExecException(String.format("The service %s does not match the allowed pattern %s. Aborted execution.", serviceUrl, allowPattern.pattern())); + } + + // check whether the service url is denied (in the context, in the default) + Pattern denyPattern = context.get(DENY_SYMBOL, config.getServiceDenyPattern()); + if (denyPattern.matcher(serviceUrl).matches()) { + throw new QueryExecException(String.format("The service %s matches the denied pattern %s. Aborted execution.", serviceUrl, denyPattern.pattern())); + } + } + + boolean silent = opOriginal.getSilent(); + + // derive the asset type from the service URL, if possible + // otherwise we will get it from the endpoint address after a ngotiation + String assetType = serviceUrl.contains("Skill") ? "cx-common:SkillAsset" : serviceUrl.contains("Graph") ? "cx-common:GraphAsset" : "cx-common:Asset"; + + // in case we have an EDC target, we need to negotiate/proxy the transfer + Matcher edcMatcher = EDC_TARGET_ADDRESS_PATTERN.matcher(serviceUrl); + if (edcMatcher.matches()) { + + // + // EDC case: negotiate and proxy the transfer + // + + monitor.info(String.format("About to execute edc target %s via dataspace", serviceUrl)); + String remoteUrl = edcMatcher.group("connector"); + if (remoteUrl == null || remoteUrl.length() == 0) { + remoteUrl = config.getControlPlaneIdsUrl(); + } else { + if ("edcs".equals(edcMatcher.group("protocol"))) { + remoteUrl = "https://" + remoteUrl; + } else { + remoteUrl = "http://" + remoteUrl; + } + } + String asset = edcMatcher.group("asset"); + if (asset == null || asset.length() == 0) { + GraphRewriteVisitor grv = new GraphRewriteVisitor(); + GraphRewrite gr = new GraphRewrite(monitor, bindings, grv); + Op transformed = Transformer.transform(gr, opOriginal.getSubOp(), grv, null); + opOriginal = new OpService(opOriginal.getService(), transformed, opOriginal.getSilent()); + Set graphNames = gr.getGraphNames(); + if (graphNames.size() > 1) { + throw new QueryExecException("There are several graph assets (currently not supported due to negotiation strategy, please rewrite your query) under EDC-based service: " + serviceUrl); + } else { + Optional graphName = graphNames.stream().findAny(); + if (graphName.isEmpty()) { + throw new QueryExecException("There is no graph asset under EDC-based service: " + serviceUrl); + } else { + asset = graphName.get(); + } + } + } + EndpointDataReference endpoint = agreementController.get(asset); + if (endpoint == null) { + endpoint = agreementController.createAgreement(remoteUrl, asset); + if (endpoint == null) { + throw new QueryExecException(String.format("Could not get an endpoint calback from connector %s to asset %s - Most likely this was a recursive call and you forgot to setup two control planes.", remoteUrl, asset)); + } + } + // the asset type should be annotated in the rdf type property + assetType = String.valueOf(endpoint.getProperties().getOrDefault("http://www.w3.org/1999/02/22-rdf-syntax-ns#type", assetType)); + + // put the endpoint information into a new service operator + // and cater for the EDC public api slash problem + serviceUrl = endpoint.getEndpoint(); + if (!serviceUrl.endsWith("/")) { + serviceUrl = serviceUrl + "/"; + } + if (edcMatcher.group("params") != null) { + serviceUrl = serviceUrl + "?" + edcMatcher.group("params"); + } + Map>> allServiceParams = context.get(Service.serviceParams); + if (allServiceParams == null) { + allServiceParams = new HashMap<>(); + context.put(Service.serviceParams, allServiceParams); + } + Map> serviceParams = allServiceParams.computeIfAbsent(serviceUrl, k -> new HashMap<>()); + serviceParams.put("cx_accept", List.of("application/json")); + execCxt.getContext().put(AUTH_KEY_SYMBOL, endpoint.getAuthKey()); + execCxt.getContext().put(AUTH_CODE_SYMBOL, endpoint.getAuthCode()); + } else { + monitor.info(String.format("About to execute http target %s without dataspace", serviceUrl)); + } + + // Next case distinction: we could either have a query or + // a direct skill call + if (!assetType.contains("Skill")) { + // http execute with headers and such + try { + Op opRemote = opOriginal.getSubOp(); + int hashCode = Math.abs(opRemote.hashCode()); + String bindingVarName = "binding" + hashCode; + Var idVar = Var.alloc(bindingVarName); + VariableDetector vd = new VariableDetector(boundVars); + opRemote = NodeTransformLib.transform(vd, opRemote); + List neededVars = vd.getVariables(); + Map resultingBindings = new HashMap<>(); + Map> newBindings = new HashMap<>(); + for (Binding originalBinding : bindings) { + StringBuilder keyBuilder = new StringBuilder(); + BindingBuilder bb = BindingBuilder.create(); + for (Var neededVar : neededVars) { + Node node = originalBinding.get(neededVar); + keyBuilder.append(neededVar.getVarName()); + keyBuilder.append("#"); + keyBuilder.append(node.toString()); + bb.add(neededVar, node); + } + String key = keyBuilder.toString(); + Node keyNode; + if (resultingBindings.containsKey(key)) { + Binding existingBinding = resultingBindings.get(key); + keyNode = existingBinding.get(idVar); + } else { + keyNode = NodeFactory.createLiteral(String.valueOf(resultingBindings.size())); + bb.add(idVar, keyNode); + newBindings.put(keyNode, new ArrayList<>()); + Binding newBinding = bb.build(); + //bb = BindingBuilder.create(newBinding); + resultingBindings.put(key, newBinding); + } + final BindingBuilder bb2 = BindingBuilder.create(originalBinding); + bb2.set(idVar, keyNode); + newBindings.get(keyNode).add(bb2.build()); + } + neededVars.add(idVar); + TableData table = new TableData(neededVars, new ArrayList<>(resultingBindings.values())); + OpTable opTable = OpTable.create(table); + + Query query; + + // do we have a "sub-select", then we smuggle our binding into it + if (opRemote instanceof OpProject) { + OpProject opRemoteProject = (OpProject) opRemote; + Op join = OpSequence.create(opTable, opRemoteProject.getSubOp()); + List resultVars = opRemoteProject.getVars(); + resultVars.add(idVar); + query = OpAsQuery.asQuery(new OpProject(join, resultVars)); + } else { + Op join = OpSequence.create(opTable, opRemote); + query = OpAsQuery.asQuery(join); + } + + monitor.debug(String.format("Prepared target %s for query %s", serviceUrl, query)); + + // -- Setup + //boolean withCompression = context.isTrueOrUndef(httpQueryCompression); + long timeoutMillis = config.getReadTimeout(); + + // RegistryServiceModifier is applied by QueryExecHTTP + Params serviceParams = getServiceParamsFromContext(serviceUrl, context); + HttpClient httpClient = chooseHttpClient(serviceUrl, context); + + QuerySendMode querySendMode = chooseQuerySendMode(serviceUrl, context, QuerySendMode.asGetWithLimitBody); + // -- End setup + + // Build the execution + QueryExecutorBuilder queryExecutorBuilder = QueryExecutor.newBuilder() + .endpoint(serviceUrl) + .timeout(timeoutMillis, TimeUnit.MILLISECONDS) + .query(query) + .params(serviceParams) + .context(context) + .httpClient(httpClient) + .objectMapper(objectMapper) + .agentConfig(config) + .sendMode(querySendMode); + + if (context.isDefined(AUTH_KEY_SYMBOL)) { + String authKeyProp = context.get(AUTH_KEY_SYMBOL); + monitor.debug(String.format("About to use authentication header %s on http target %s", authKeyProp, serviceUrl)); + String authCodeProp = context.get(AUTH_CODE_SYMBOL); + queryExecutorBuilder = queryExecutorBuilder.httpHeader(authKeyProp, authCodeProp); + } + + try (QueryExecutor qExec = queryExecutorBuilder.build()) { + // Detach from the network stream. + RowSet rowSet = qExec.select().materialize(); + QueryIterator queryIterator = QueryIterPlainWrapper.create(rowSet); + queryIterator = QueryIter.makeTracked(queryIterator, execCxt); + return new QueryIterJoin(queryIterator, newBindings, idVar, execCxt); + } + } catch (RuntimeException ex) { + if (silent) { + Log.warn(this, "SERVICE " + serviceUrl + " : " + ex.getMessage()); + // Return the input + return QueryIterPlainWrapper.create(bindings.iterator(), execCxt); + } + throw ex; + } + } else { + // Skill call + try { + // [QExec] Add getSubOpUnmodified(); + Op opRemote = opOriginal.getSubOp(); + String bindingVarName = "binding"; + Var idVar = Var.alloc(bindingVarName); + SkillVariableDetector vd = new SkillVariableDetector(boundVars); + opRemote = Transformer.transform(vd, opRemote); + Map neededVars = vd.getVariables(); + var parameterSet = new ResultSetMem() { + public void setVarNames(List vars) { + this.varNames = vars; + } + + public List getRows() { + return this.rows; + } + + }; + List vars = new ArrayList<>(); + vars.add(bindingVarName); + neededVars.forEach((key1, value) -> vars.add(key1)); + parameterSet.setVarNames(vars); + Map resultingBindings = new HashMap<>(); + Map> newBindings = new HashMap<>(); + for (Binding originalBinding : bindings) { + StringBuilder keyBuilder = new StringBuilder(); + BindingBuilder bb = BindingBuilder.create(); + for (Map.Entry neededVar : neededVars.entrySet()) { + Node node = neededVar.getValue(); + if (node.isVariable()) { + node = originalBinding.get((Var) node); + } + if (node != null) { + keyBuilder.append(neededVar.getKey()); + keyBuilder.append("#"); + keyBuilder.append(node); + bb.add(Var.alloc(neededVar.getKey()), node); + } + } + String key = keyBuilder.toString(); + Node keyNode; + if (resultingBindings.containsKey(key)) { + Binding existingBinding = resultingBindings.get(key); + keyNode = existingBinding.get(idVar); + } else { + keyNode = NodeFactory.createLiteral(String.valueOf(resultingBindings.size())); + bb.add(idVar, keyNode); + newBindings.put(keyNode, new ArrayList<>()); + Binding newBinding = bb.build(); + //bb=BindingBuilder.create(newBinding); + resultingBindings.put(key, newBinding); + } + final BindingBuilder bb2 = BindingBuilder.create(originalBinding); + bb2.set(idVar, keyNode); + newBindings.get(keyNode).add(bb2.build()); + } + parameterSet.getRows().addAll(resultingBindings.values()); + parameterSet.reset(); + long timeoutMillis = config.getReadTimeout(); + HttpClient httpClient = chooseHttpClient(serviceUrl, context); + + String bindingSet = ResultSetMgr.asString(parameterSet, ResultSetLang.RS_JSON); + HttpRequest.Builder skillRequest = HttpRequest.newBuilder() + .uri(new URI(serviceUrl)) + .header("Content-Type", WebContent.contentTypeResultsJSON) + .timeout(Duration.ofMillis(timeoutMillis)) + .header("Accept", WebContent.contentTypeResultsJSON) + .POST(HttpRequest.BodyPublishers.ofString(bindingSet)); + + if (context.isDefined(AUTH_KEY_SYMBOL)) { + String authKeyProp = context.get(AUTH_KEY_SYMBOL); + monitor.debug(String.format("About to use authentication header %s on http target %s", authKeyProp, serviceUrl)); + String authCodeProp = context.get(AUTH_CODE_SYMBOL); + skillRequest = skillRequest.header(authKeyProp, authCodeProp); + } + + HttpResponse remoteCall = httpClient.send(skillRequest.build(), HttpResponse.BodyHandlers.ofInputStream()); + if (remoteCall.statusCode() >= 200 && remoteCall.statusCode() < 300) { + ResultSet result = ResultSetMgr.read(remoteCall.body(), ResultSetLang.RS_JSON); + RowSet rowSet = new RowSetAdapter(result); + QueryIterator queryIterator = QueryIterPlainWrapper.create(rowSet); + queryIterator = QueryIter.makeTracked(queryIterator, execCxt); + return new QueryIterJoin(queryIterator, newBindings, idVar, execCxt); + } else { + Log.warn(this, "SERVICE " + serviceUrl + " resulted in status code " + remoteCall.statusCode()); + remoteCall.body().close(); + // Return the input + return QueryIterPlainWrapper.create(bindings.iterator(), execCxt); + } + } catch (URISyntaxException | IOException | InterruptedException | RuntimeException ex) { + if (silent) { + Log.warn(this, "SERVICE " + serviceUrl + " : " + ex.getMessage()); + // Return the input + return QueryIterPlainWrapper.create(bindings.iterator(), execCxt); + } + throw new RuntimeException("Could not invoke remote skill", ex); + } + } + } + + /** + * choose an appropriate client + * + * @param serviceUrl target url + * @param context query context + * @return http client + */ + protected HttpClient chooseHttpClient(String serviceUrl, Context context) { + if (context == null) { + monitor.warning(String.format("Context is null when obtaining http client for %s", serviceUrl)); + } + return client; + } + + /** + * choose an appropriate send mode + * + * @param serviceUrl target url + * @param context query content + * @param dftValue default send mode of dft + * @return decided send mode + */ + protected QuerySendMode chooseQuerySendMode(String serviceUrl, Context context, QuerySendMode dftValue) { + if (dftValue != QuerySendMode.asPost) { + monitor.warning(String.format("Default send mode %s for %s is not post", dftValue, serviceUrl)); + } + if (context == null) { + monitor.warning(String.format("Context is null when obtaining send mode for %s", serviceUrl)); + } + return QuerySendMode.asPost; + } + + /** + * extract http params from query + * + * @param serviceUrl target url + * @param context query context + * @return query params + * @throws QueryExecException in case there is something wrong + */ + protected Params getServiceParamsFromContext(String serviceUrl, Context context) throws QueryExecException { + Params params = Params.create(); + + Object obj = context.get(Service.serviceParams); + + if (obj == null) { + return params; + } + + // Old style. + try { + @SuppressWarnings("unchecked") + Map>> serviceParams = (Map>>) obj; + Map> paramsMap = serviceParams.get(serviceUrl); + if (paramsMap != null) { + for (String param : paramsMap.keySet()) { + if (HttpParams.pQuery.equals(param)) { + throw new QueryExecException("ARQ serviceParams overrides the 'query' SPARQL protocol parameter"); + } + List values = paramsMap.get(param); + for (String value : values) { + params.add(param, value); + } + } + } + return params; + } catch (Throwable ex) { + monitor.warning("Failed to process " + obj + " : context value of ARQ.serviceParams"); + return null; + } + } + +} \ No newline at end of file diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewrite.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewrite.java new file mode 100644 index 00000000..0b1af61f --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewrite.java @@ -0,0 +1,125 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.sparql; + +import org.apache.jena.graph.Node; +import org.apache.jena.graph.NodeFactory; +import org.apache.jena.sparql.algebra.Op; +import org.apache.jena.sparql.algebra.TransformCopy; +import org.apache.jena.sparql.algebra.op.OpGraph; +import org.apache.jena.sparql.core.Var; +import org.apache.jena.sparql.engine.binding.Binding; +import org.eclipse.edc.spi.monitor.Monitor; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +/** + * A rewriter which replaces graphs by their bindings + * and collects the unique names. Is used for EDC calls + * in order to deduce the necessary assets to negotiate + * and replace variables for later exchange with the + * backend service. + */ +public class GraphRewrite extends TransformCopy { + + protected final List bindings; + protected final Set graphNames = new HashSet<>(); + + protected final Monitor monitor; + + protected final GraphRewriteVisitor visitor; + + public GraphRewrite(Monitor monitor, List bindings, GraphRewriteVisitor visitor) { + this.bindings = bindings; + this.monitor = monitor; + this.visitor = visitor; + } + + + @Override + public OpGraph transform(OpGraph op, Op subOp) { + if (!visitor.inService) { + Node graphNode = op.getNode(); + if (graphNode.isURI()) { + String graphString = graphNode.getURI(); + if (graphString.startsWith(SparqlQueryProcessor.UNSET_BASE)) { + graphString = graphString.substring(SparqlQueryProcessor.UNSET_BASE.length()); + op = new OpGraph(NodeFactory.createURI(graphString), subOp); + } + graphNames.add(graphString); + } else if (graphNode.isLiteral()) { + String graphString = String.valueOf(graphNode.getLiteralValue()); + if (graphString.startsWith(SparqlQueryProcessor.UNSET_BASE)) { + graphString = graphString.substring(SparqlQueryProcessor.UNSET_BASE.length()); + op = new OpGraph(NodeFactory.createURI(graphString), subOp); + } + graphNames.add(graphString); + } else if (graphNode.isVariable()) { + Var graphVar = (Var) graphNode; + if (bindings == null || bindings.isEmpty()) { + monitor.warning(String.format("Found a graph node %s which is a variable but no binding. Ignoring.", graphVar)); + } else { + Iterator allBindings = bindings.iterator(); + Node bound = null; + while (bound == null && allBindings.hasNext()) { + Binding binding = allBindings.next(); + if (binding.contains(graphVar)) { + bound = binding.get(graphVar); + } + } + if (bound != null) { + if (bound.isURI()) { + String graphString = bound.getURI(); + if (graphString.startsWith(SparqlQueryProcessor.UNSET_BASE)) { + graphString = graphString.substring(SparqlQueryProcessor.UNSET_BASE.length()); + } + graphNames.add(graphString); + op = new OpGraph(NodeFactory.createURI(graphString), subOp); + } else if (bound.isLiteral()) { + String graphString = String.valueOf(bound.getLiteralValue()); + if (graphString.startsWith(SparqlQueryProcessor.UNSET_BASE)) { + graphString = graphString.substring(SparqlQueryProcessor.UNSET_BASE.length()); + } + graphNames.add(graphString); + op = new OpGraph(NodeFactory.createURI(graphString), subOp); + } else { + monitor.warning(String.format("Found a graph node binding %s which is no uri or literal. Ignoring.", bound)); + } + } else { + monitor.warning(String.format("Found a graph node %s that is not bound. Ignoring.", bound)); + } + } + } else { + monitor.warning(String.format("Found a graph node %s which is neither uri, literal or variable. Ignoring.", graphNode)); + } + } + return op; + } + + /** + * access + * + * @return set of graph names/assets found + */ + public Set getGraphNames() { + return graphNames; + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewriteVisitor.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewriteVisitor.java new file mode 100644 index 00000000..b86c8e89 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewriteVisitor.java @@ -0,0 +1,33 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.sparql; + +import org.apache.jena.sparql.algebra.OpVisitorBase; +import org.apache.jena.sparql.algebra.op.OpService; + +/** + * A visitor that indicates stop when inside a service + */ +public class GraphRewriteVisitor extends OpVisitorBase { + protected boolean inService = false; + + @Override + public void visit(OpService opService) { + super.visit(opService); + inService = true; + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/HttpServletRequestToOkHttpRequestConverter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/HttpServletRequestToOkHttpRequestConverter.java new file mode 100644 index 00000000..dedc9b07 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/HttpServletRequestToOkHttpRequestConverter.java @@ -0,0 +1,94 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.edc.sparql; + +import com.google.gson.Gson; +import jakarta.servlet.http.HttpServletRequest; +import okhttp3.Headers; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + + +/** + * Converter to convert a HttpServletRequest to a OkHttpRequest for + * a application/json media type + */ + +public class HttpServletRequestToOkHttpRequestConverter { + + public Request convert(HttpServletRequest httpServletRequest) throws IOException { + // Extracting request method, URL, and headers + String method = httpServletRequest.getMethod(); + String url = buildUrl(httpServletRequest); + Headers headers = buildHeaders(httpServletRequest); + RequestBody requestBody = buildRequestBody(httpServletRequest); + + // Building okhttp3.Request + return new Request.Builder() + .method(method, requestBody) + .url(url) + .headers(headers) + .build(); + } + + private String buildUrl(HttpServletRequest httpServletRequest) { + StringBuffer url = httpServletRequest.getRequestURL(); + String queryString = httpServletRequest.getQueryString(); + if (queryString != null) { + url.append("?").append(queryString); + } + return url.toString(); + } + + // Copying headers from HttpServletRequest to okhttp3.Headers + private Headers buildHeaders(HttpServletRequest httpServletRequest) { + Headers.Builder headersBuilder = new Headers.Builder(); + Enumeration headerNames = httpServletRequest.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String headerName = headerNames.nextElement(); + String headerValue = httpServletRequest.getHeader(headerName); + headersBuilder.add(headerName, headerValue); + } + + return headersBuilder.build(); + } + + // Extracting request body of application/json; + private RequestBody buildRequestBody(HttpServletRequest httpServletRequest) throws IOException { + if ("POST".equalsIgnoreCase(httpServletRequest.getMethod())) { + Enumeration parameterNames = httpServletRequest.getParameterNames(); + Map jsonPayload = new HashMap<>(); + while (parameterNames.hasMoreElements()) { + String paramName = parameterNames.nextElement(); + String paramValue = httpServletRequest.getParameter(paramName); + jsonPayload.put(paramName, paramValue); + } + + MediaType mediaType = MediaType.get("application/json; charset=utf-8"); + return RequestBody.create(new Gson().toJson(jsonPayload), mediaType); + } + + return null; + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/OptimizeJoinStrategy.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/OptimizeJoinStrategy.java new file mode 100644 index 00000000..3e87fc3c --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/OptimizeJoinStrategy.java @@ -0,0 +1,64 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.sparql; + +import org.apache.jena.sparql.algebra.Op; +import org.apache.jena.sparql.algebra.op.OpGraph; +import org.apache.jena.sparql.algebra.op.OpJoin; +import org.apache.jena.sparql.algebra.op.OpSequence; +import org.apache.jena.sparql.algebra.op.OpService; +import org.apache.jena.sparql.algebra.op.OpUnion; +import org.apache.jena.sparql.algebra.optimize.TransformJoinStrategy; +import org.apache.jena.sparql.engine.main.JoinClassifier; + +/** + * a modified default join strategy which will always linearize right-hand + * service and union calls in order to obtain bindings from the + * left part. + * TODO improve to find independent/asynchronous calls which should be parallelized (cross-join case) + */ +public class OptimizeJoinStrategy extends TransformJoinStrategy { + + /** + * implement the federated join strategy + * + * @param opJoin operator to optimize + * @param left left-part of join + * @param right right-part of join + * @return transformed join operator + */ + @Override + public Op transform(OpJoin opJoin, Op left, Op right) { + boolean canDoLinear = JoinClassifier.isLinear(opJoin); + if (!canDoLinear) { + if (right instanceof OpService || right instanceof OpUnion) { + // join no-matter what with a service or a union + return OpSequence.create(left, right); + } + if (left instanceof OpService || left instanceof OpGraph) { + // join no matter after service and graph calls + return OpSequence.create(left, right); + } + if (left instanceof OpSequence && right instanceof OpSequence) { + // join two sequences + return OpSequence.create(left, right); + } + } + // default transform + return super.transform(opJoin, left, right); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/Optimizer.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/Optimizer.java new file mode 100644 index 00000000..9b62778d --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/Optimizer.java @@ -0,0 +1,48 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.sparql; + +import org.apache.jena.sparql.algebra.Op; +import org.apache.jena.sparql.algebra.optimize.OptimizerStd; +import org.apache.jena.sparql.util.Context; + +/** + * an modified standard optimization strategy which deals with federation and binding + * of federation-important sparql constructs better at the level of joins + */ +public class Optimizer extends OptimizerStd { + /** + * Create a new optimizer + * + * @param context query context + */ + public Optimizer(Context context) { + super(context); + } + + /** + * override to choose the improved join straregy + * + * @param op operator to transform + * @return transformed operator + */ + @Override + protected Op transformJoinStrategy(Op op) { + return apply("Federated Index Join strategy", new OptimizeJoinStrategy(), op); + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/OptimizerFactory.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/OptimizerFactory.java new file mode 100644 index 00000000..ea107741 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/OptimizerFactory.java @@ -0,0 +1,31 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.sparql; + +import org.apache.jena.sparql.algebra.optimize.Rewrite; +import org.apache.jena.sparql.algebra.optimize.RewriteFactory; +import org.apache.jena.sparql.util.Context; + +/** + * a factory for a federation-improved optimization strategy + */ +public class OptimizerFactory implements RewriteFactory { + @Override + public Rewrite create(Context context) { + return new Optimizer(context); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutor.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutor.java new file mode 100644 index 00000000..5ab861bb --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutor.java @@ -0,0 +1,693 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.sparql; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.nimbusds.jose.util.IOUtils; +import org.apache.jena.atlas.RuntimeIOException; +import org.apache.jena.atlas.iterator.Iter; +import org.apache.jena.atlas.json.JSON; +import org.apache.jena.atlas.json.JsonArray; +import org.apache.jena.atlas.json.JsonObject; +import org.apache.jena.atlas.lib.InternalErrorException; +import org.apache.jena.atlas.lib.Pair; +import org.apache.jena.atlas.logging.Log; +import org.apache.jena.graph.Graph; +import org.apache.jena.graph.Triple; +import org.apache.jena.http.HttpEnv; +import org.apache.jena.http.HttpLib; +import org.apache.jena.query.Query; +import org.apache.jena.query.QueryException; +import org.apache.jena.query.QueryExecException; +import org.apache.jena.query.QueryFactory; +import org.apache.jena.query.QueryParseException; +import org.apache.jena.query.QueryType; +import org.apache.jena.query.ResultSet; +import org.apache.jena.query.Syntax; +import org.apache.jena.riot.Lang; +import org.apache.jena.riot.RDFDataMgr; +import org.apache.jena.riot.RDFLanguages; +import org.apache.jena.riot.ResultSetMgr; +import org.apache.jena.riot.RiotException; +import org.apache.jena.riot.WebContent; +import org.apache.jena.riot.resultset.ResultSetLang; +import org.apache.jena.riot.resultset.ResultSetReaderRegistry; +import org.apache.jena.riot.web.HttpNames; +import org.apache.jena.sparql.ARQException; +import org.apache.jena.sparql.core.DatasetGraph; +import org.apache.jena.sparql.core.DatasetGraphFactory; +import org.apache.jena.sparql.core.Quad; +import org.apache.jena.sparql.engine.http.HttpParams; +import org.apache.jena.sparql.engine.http.QueryExceptionHTTP; +import org.apache.jena.sparql.exec.QueryExec; +import org.apache.jena.sparql.exec.RowSet; +import org.apache.jena.sparql.exec.http.Params; +import org.apache.jena.sparql.exec.http.QuerySendMode; +import org.apache.jena.sparql.util.Context; +import org.eclipse.tractusx.agents.edc.AgentConfig; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublishers; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +import static org.apache.jena.http.HttpLib.acceptHeader; +import static org.apache.jena.http.HttpLib.contentTypeHeader; +import static org.apache.jena.http.HttpLib.dft; +import static org.apache.jena.http.HttpLib.execute; +import static org.apache.jena.http.HttpLib.finish; +import static org.apache.jena.http.HttpLib.requestURL; +import static org.apache.jena.http.HttpLib.responseHeader; + +/** + * An Exec implementation which understands KA-MATCH and KA-TRANSFER remote + * services over HTTP. + */ +public class QueryExecutor implements QueryExec { + + /** + * creates a builder + * + * @deprecated Use {@link #newBuilder} + */ + @Deprecated + public static QueryExecutorBuilder create() { + return newBuilder(); + } + + public static QueryExecutorBuilder newBuilder() { + return QueryExecutorBuilder.create(); + } + + public static QueryExecutorBuilder service(String serviceUrl) { + return newBuilder().endpoint(serviceUrl); + } + + // Blazegraph has a bug : it impacts wikidata. + // Unless the charset is set, wikidata interprets a POST as ISO-8859-??? (c.f. POST as form). + // https://github.com/blazegraph/database/issues/224 + // Only applies to SendMode.asPost of a SPARQL query. + public static final String QUERY_MIME_TYPE = WebContent.contentTypeSPARQLQuery + ";charset=" + WebContent.charsetUTF8; + private final Query query; + private final String queryString; + private final String service; + private final Context context; + private final ObjectMapper objectMapper; + private final AgentConfig agentConfig; + + // Params + private final Params params; + + private final QuerySendMode sendMode; + private final int urlLimit; + + // Protocol + private final List defaultGraphUris; + private final List namedGraphUris; + + private boolean closed = false; + + // Timeout of query execution. + private final long readTimeout; + private final TimeUnit readTimeoutUnit; + + // Content Types: these list the standard formats and also include */*. + private final String selectAcceptheader = WebContent.defaultSparqlResultsHeader; + private final String askAcceptHeader = WebContent.defaultSparqlAskHeader; + private final String datasetAcceptHeader = WebContent.defaultDatasetAcceptHeader; + + // If this is non-null, it overrides the use of any Content-Type above. + private String appProvidedAcceptHeader; + + // Releasing HTTP input streams is important. We remember this for SELECT result + // set streaming, and will close it when the execution is closed + private InputStream retainedConnection = null; + + private final HttpClient httpClient; + private Map httpHeaders; + + public QueryExecutor(String serviceUrl, Query query, String queryString, int urlLimit, + HttpClient httpClient, Map httpHeaders, Params params, Context context, + List defaultGraphUris, List namedGraphUris, + QuerySendMode sendMode, String explicitAcceptHeader, + long timeout, TimeUnit timeoutUnit, ObjectMapper objectMapper, AgentConfig agentConfig) { + this.context = context; + this.service = serviceUrl; + this.query = query; + this.queryString = queryString; + this.urlLimit = urlLimit; + this.httpHeaders = httpHeaders; + this.defaultGraphUris = defaultGraphUris; + this.namedGraphUris = namedGraphUris; + this.sendMode = Objects.requireNonNull(sendMode); + this.appProvidedAcceptHeader = explicitAcceptHeader; + // Important - handled as special case because the defaults vary by query type. + if (httpHeaders.containsKey(HttpNames.hAccept)) { + if (this.appProvidedAcceptHeader != null) { + this.appProvidedAcceptHeader = httpHeaders.get(HttpNames.hAccept); + } + this.httpHeaders.remove(HttpNames.hAccept); + } + this.httpHeaders = httpHeaders; + this.params = params; + this.readTimeout = timeout; + this.readTimeoutUnit = timeoutUnit; + this.httpClient = HttpLib.dft(httpClient, HttpEnv.getDftHttpClient()); + this.objectMapper = objectMapper; + this.agentConfig = agentConfig; + } + + @Override + public RowSet select() { + checkNotClosed(); + check(QueryType.SELECT); + return execRowSet(); + } + + private RowSet execRowSet() { + // Use the explicitly given header or the default selectAcceptheader + String thisAcceptHeader = dft(appProvidedAcceptHeader, selectAcceptheader); + + Map.Entry response = performQuery(thisAcceptHeader); + InputStream in = response.getValue(); + // Don't assume the endpoint actually gives back the content type we asked for + String actualContentType = response.getKey(); + + // More reliable to use the format-defined charsets e.g. JSON -> UTF-8 + actualContentType = removeCharset(actualContentType); + + retainedConnection = in; // This will be closed on close() + + // Map to lang, with pragmatic alternatives. + Lang lang = WebContent.contentTypeToLangResultSet(actualContentType); + if (lang == null) { + throw new QueryException("Endpoint returned Content-Type: " + actualContentType + " which is not recognized for SELECT queries"); + } + if (!ResultSetReaderRegistry.isRegistered(lang)) { + throw new QueryException("Endpoint returned Content-Type: " + actualContentType + " which is not supported for SELECT queries"); + } + // This returns a streaming result set for some formats. + // Do not close the InputStream at this point. + ResultSet result = ResultSetMgr.read(in, lang); + return RowSet.adapt(result); + } + + @Override + public boolean ask() { + checkNotClosed(); + check(QueryType.ASK); + String thisAcceptHeader = dft(appProvidedAcceptHeader, askAcceptHeader); + Map.Entry response = performQuery(thisAcceptHeader); + InputStream in = response.getValue(); + + String actualContentType = response.getKey(); + actualContentType = removeCharset(actualContentType); + + Lang lang = RDFLanguages.contentTypeToLang(actualContentType); + if (lang == null) { + // Any specials : + // application/xml for application/sparql-results+xml + // application/json for application/sparql-results+json + if (actualContentType.equals(WebContent.contentTypeXML)) { + lang = ResultSetLang.RS_XML; + } else if (actualContentType.equals(WebContent.contentTypeJSON)) { + lang = ResultSetLang.RS_JSON; + } + } + if (lang == null) { + throw new QueryException("Endpoint returned Content-Type: " + actualContentType + " which is not supported for ASK queries"); + } + boolean result = ResultSetMgr.readBoolean(in, lang); + finish(in); + return result; + } + + private String removeCharset(String contentType) { + int idx = contentType.indexOf(';'); + if (idx < 0) { + return contentType; + } + return contentType.substring(0, idx); + } + + @Override + public Graph construct(Graph graph) { + checkNotClosed(); + check(QueryType.CONSTRUCT); + return execGraph(graph); + } + + @Override + public Iterator constructTriples() { + checkNotClosed(); + check(QueryType.CONSTRUCT); + return execTriples(); + } + + @Override + public Iterator constructQuads() { + checkNotClosed(); + return execQuads(); + } + + @Override + public DatasetGraph constructDataset() { + checkNotClosed(); + return constructDataset(DatasetGraphFactory.createTxnMem()); + } + + @Override + public DatasetGraph constructDataset(DatasetGraph dataset) { + checkNotClosed(); + check(QueryType.CONSTRUCT); + return execDataset(dataset); + } + + @Override + public Graph describe(Graph graph) { + checkNotClosed(); + check(QueryType.DESCRIBE); + return execGraph(graph); + } + + @Override + public Iterator describeTriples() { + checkNotClosed(); + return execTriples(); + } + + private Graph execGraph(Graph graph) { + Pair p = execRdfWorker(WebContent.defaultRDFAcceptHeader); + InputStream in = p.getLeft(); + Lang lang = p.getRight(); + try { + RDFDataMgr.read(graph, in, lang); + } catch (RiotException ex) { + HttpLib.finish(in); + throw ex; + } + return graph; + } + + private DatasetGraph execDataset(DatasetGraph dataset) { + Pair p = execRdfWorker(datasetAcceptHeader); + InputStream in = p.getLeft(); + Lang lang = p.getRight(); + try { + RDFDataMgr.read(dataset, in, lang); + } catch (RiotException ex) { + finish(in); + throw ex; + } + return dataset; + } + + @SuppressWarnings("deprecation") + private Iterator execTriples() { + Pair p = execRdfWorker(WebContent.defaultGraphAcceptHeader); + InputStream input = p.getLeft(); + Lang lang = p.getRight(); + // Base URI? + // Unless N-Triples, this creates a thread. + Iterator iter = RDFDataMgr.createIteratorTriples(input, lang, null); + return Iter.onCloseIO(iter, input); + } + + @SuppressWarnings("deprecation") + private Iterator execQuads() { + checkNotClosed(); + Pair p = execRdfWorker(datasetAcceptHeader); + InputStream input = p.getLeft(); + Lang lang = p.getRight(); + // Unless N-Quads, this creates a thread. + Iterator iter = RDFDataMgr.createIteratorQuads(input, lang, null); + return Iter.onCloseIO(iter, input); + } + + // Any RDF data back (CONSTRUCT, DESCRIBE, QUADS) + // ifNoContentType - some wild guess at the content type. + private Pair execRdfWorker(String contentType) { + checkNotClosed(); + String thisAcceptHeader = dft(appProvidedAcceptHeader, contentType); + Map.Entry response = performQuery(thisAcceptHeader); + InputStream in = response.getValue(); + + // Don't assume the endpoint actually gives back the content type we asked for + String actualContentType = response.getKey(); + actualContentType = removeCharset(actualContentType); + + Lang lang = RDFLanguages.contentTypeToLang(actualContentType); + if (!RDFLanguages.isQuads(lang) && !RDFLanguages.isTriples(lang)) { + throw new QueryException("Endpoint returned Content Type: " + + actualContentType + + " which is not a valid RDF syntax"); + } + return Pair.create(in, lang); + } + + @Override + public JsonArray execJson() { + checkNotClosed(); + check(QueryType.CONSTRUCT_JSON); + String thisAcceptHeader = dft(appProvidedAcceptHeader, WebContent.contentTypeJSON); + Map.Entry response = performQuery(thisAcceptHeader); + InputStream in = response.getValue(); + try { + return JSON.parseAny(in).getAsArray(); + } finally { + finish(in); + } + } + + @Override + public Iterator execJsonItems() { + JsonArray array = execJson().getAsArray(); + List x = new ArrayList<>(array.size()); + array.forEach(elt -> { + if (!elt.isObject()) { + throw new QueryExecException("Item in an array from a JSON query isn't an object"); + } + x.add(elt.getAsObject()); + }); + return x.iterator(); + } + + private void checkNotClosed() { + if (closed) { + throw new QueryExecException("HTTP QueryExecHTTP has been closed"); + } + } + + private void check(QueryType queryType) { + if (query == null) { + // Pass through the queryString. + return; + } + if (query.queryType() != queryType) { + throw new QueryExecException("Not the right form of query. Expected " + queryType + " but got " + query.queryType()); + } + } + + @Override + public Context getContext() { + return context; + } + + @Override + public DatasetGraph getDataset() { + return null; + } + + // This may be null - if we were created form a query string, + // we don't guarantee to parse it so we let through non-SPARQL + // extensions to the far end. + @Override + public Query getQuery() { + if (query != null) { + return query; + } + if (queryString != null) { + // Object not created with a Query object, may be because there is foreign + // syntax in the query or may be because the query string was available and the app + // didn't want the overhead of parsing it every time. + // Try to parse it else return null; + try { + return QueryFactory.create(queryString, Syntax.syntaxARQ); + } catch (QueryParseException ex) { + return null; + } + } + return null; + } + + /** + * Return the query string. If this was supplied as a string, + * there is no guarantee this is legal SPARQL syntax. + */ + @Override + public String getQueryString() { + return queryString; + } + + /** + * Make a query over HTTP. + * The response is returned after status code processing so the caller can assume the + * query execution was successful and return 200. + * Use {@link HttpLib#getInputStream} to access the body. + */ + private Map.Entry performQuery(String reqAcceptHeader) { + if (closed) { + throw new ARQException("HTTP execution already closed"); + } + + // SERVICE specials. + Params thisParams = Params.create(params); + + if (defaultGraphUris != null) { + for (String dft : defaultGraphUris) { + thisParams.add(HttpParams.pDefaultGraph, dft); + } + } + if (namedGraphUris != null) { + for (String name : namedGraphUris) { + thisParams.add(HttpParams.pNamedGraph, name); + } + } + + HttpLib.modifyByService(service, context, thisParams, httpHeaders); + + HttpRequest request = makeRequest(thisParams, reqAcceptHeader); + + return executeQuery(request); + } + + private HttpRequest makeRequest(Params thisParams, String reqAcceptHeader) { + QuerySendMode actualSendMode = actualSendMode(); + HttpRequest.Builder requestBuilder; + switch (actualSendMode) { + case asGetAlways: + requestBuilder = executeQueryGet(thisParams, reqAcceptHeader); + break; + case asPostForm: + requestBuilder = executeQueryPostForm(thisParams, reqAcceptHeader); + break; + case asPost: + requestBuilder = executeQueryPostBody(thisParams, reqAcceptHeader); + break; + default: + // Should not happen! + throw new InternalErrorException("Invalid value for 'actualSendMode' " + actualSendMode); + } + return requestBuilder.build(); + } + + private Map.Entry executeQuery(HttpRequest request) { + try { + HttpResponse response = execute(httpClient, request); + String contentType = responseHeader(response, HttpNames.hContentType); + InputStream inputStream = new BufferedInputStream(HttpLib.getInputStream(response)); + inputStream.mark(2); + byte[] boundaryBytes = new byte[2]; + int all = inputStream.read(boundaryBytes); + String boundary = new String(boundaryBytes); + inputStream.reset(); + Optional warnings = response.headers().firstValue("cx_warnings"); + if (all == boundaryBytes.length && contentType.startsWith("multipart/form-data") || "--".equals(boundary)) { + int boundaryIndex = contentType.indexOf(";boundary="); + if (boundaryIndex >= 0) { + boundary = boundary + contentType.substring(boundaryIndex + 10); + } + StringBuilder nextPart = null; + String embeddedContentType = null; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + for (String line = reader.readLine(); line != null; line = reader.readLine()) { + if (boundary.equals(line)) { + if (nextPart != null && embeddedContentType != null) { + if (embeddedContentType.equals("application/cx-warnings+json")) { + warnings = Optional.of(nextPart.toString()); + } else { + inputStream = new ByteArrayInputStream(nextPart.toString().getBytes()); + contentType = embeddedContentType; + } + } + nextPart = new StringBuilder(); + String contentLine = reader.readLine(); + if (contentLine != null && contentLine.startsWith("Content-Type: ")) { + embeddedContentType = contentLine.substring(14); + } else { + embeddedContentType = null; + } + } else if (nextPart != null) { + nextPart.append(line); + nextPart.append("\n"); + } + } + } + if (nextPart != null && embeddedContentType != null) { + if (embeddedContentType.equals("application/cx-warnings+json")) { + warnings = Optional.of(nextPart.toString()); + } else { + inputStream = new ByteArrayInputStream(nextPart.toString().getBytes()); + contentType = embeddedContentType; + } + } + } + if (warnings.isPresent()) { + List yetWarnings = CatenaxWarning.getOrSetWarnings(context); + try { + List newWarnings = objectMapper.readValue(warnings.get(), new TypeReference<>() { + }); + yetWarnings.addAll(newWarnings); + } catch (JsonProcessingException e) { + CatenaxWarning newWarning = new CatenaxWarning(); + newWarning.setSourceTenant(agentConfig.getControlPlaneIdsUrl()); + newWarning.setSourceAsset(agentConfig.getDefaultAsset()); + newWarning.setTargetTenant(request.uri().toString()); + newWarning.setTargetAsset(request.uri().toString()); + newWarning.setContext(String.valueOf(context.hashCode())); + newWarning.setProblem("Could not deserialize embedded warnings."); + yetWarnings.add(newWarning); + } + } + int httpStatusCode = response.statusCode(); + if (httpStatusCode < 200 || httpStatusCode > 299) { + String msg = IOUtils.readInputStreamToString(inputStream); + throw new QueryExceptionHTTP(httpStatusCode, msg); + } + return new AbstractMap.SimpleEntry<>(contentType, inputStream); + } catch (IOException e) { + throw new QueryException(e); + } + } + + private QuerySendMode actualSendMode() { + switch (sendMode) { + case asGetAlways: + case asPostForm: + case asPost: + return sendMode; + case asGetWithLimitBody: + case asGetWithLimitForm: + default: + break; + } + + // Other params (query= has not been added at this point) + int paramsLength = params.httpString().length(); + int encodeStringLength = calcEncodeStringLength(queryString); + + // URL Length, including service (for safety) + int length = service.length() + + /* ?query= */ 1 + HttpParams.pQuery.length() + + /* encoded query */ encodeStringLength + + /* &other params*/ 1 + paramsLength; + if (length <= urlLimit) { + return QuerySendMode.asGetAlways; + } + return (sendMode == QuerySendMode.asGetWithLimitBody) ? QuerySendMode.asPost : QuerySendMode.asPostForm; + } + + private static int calcEncodeStringLength(String str) { + // Could approximate by counting non-queryString character and adding that *2 to the length of the string. + String qs = HttpLib.urlEncodeQueryString(str); + return qs.length(); + } + + private HttpRequest.Builder executeQueryGet(Params thisParams, String acceptHeader) { + thisParams.add(HttpParams.pQuery, queryString); + String requestUrl = requestURL(service, thisParams.httpString()); + HttpRequest.Builder builder = HttpLib.requestBuilder(requestUrl, httpHeaders, readTimeout, readTimeoutUnit); + acceptHeader(builder, acceptHeader); + return builder.GET(); + } + + private HttpRequest.Builder executeQueryPostForm(Params thisParams, String acceptHeader) { + thisParams.add(HttpParams.pQuery, queryString); + String formBody = thisParams.httpString(); + HttpRequest.Builder builder = HttpLib.requestBuilder(service, httpHeaders, readTimeout, readTimeoutUnit); + acceptHeader(builder, acceptHeader); + // Use an HTML form. + contentTypeHeader(builder, WebContent.contentTypeHTMLForm); + // Already UTF-8 encoded to ASCII. + return builder.POST(BodyPublishers.ofString(formBody, StandardCharsets.US_ASCII)); + } + + // Use SPARQL query body and MIME type. + private HttpRequest.Builder executeQueryPostBody(Params thisParams, String acceptHeader) { + // Use thisParams (for default-graph-uri etc) + String requestUrl = requestURL(service, thisParams.httpString()); + HttpRequest.Builder builder = HttpLib.requestBuilder(requestUrl, httpHeaders, readTimeout, readTimeoutUnit); + contentTypeHeader(builder, QUERY_MIME_TYPE); + acceptHeader(builder, acceptHeader); + return builder.POST(BodyPublishers.ofString(queryString)); + } + + @Override + public void abort() { + try { + close(); + } catch (Exception ex) { + Log.warn(this, "Error during abort", ex); + } + } + + @Override + public void close() { + closed = true; + if (retainedConnection != null) { + try { + // This call may take a long time if the response has not been consumed + // as HTTP client will consume the remaining response so it can re-use the + // connection. If we're closing when we're not at the end of the stream then + // issue a warning to the logs + if (retainedConnection.read() != -1) { + Log.warn(this, "HTTP response not fully consumed, if HTTP Client is reusing connections (its default behaviour)" + + "then it will consume the remaining response data which may take a long time and cause this application to become unresponsive"); + } + retainedConnection.close(); + } catch (RuntimeIOException | java.io.IOException e) { + // If we are closing early and the underlying stream is chunk encoded + // the close() can result in a IOException. TypedInputStream catches + // and re-wraps that and we want to suppress both forms. + } finally { + retainedConnection = null; + } + } + } + + @Override + public boolean isClosed() { + return closed; + } +} \ No newline at end of file diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutorBuilder.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutorBuilder.java new file mode 100644 index 00000000..fc900e78 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutorBuilder.java @@ -0,0 +1,93 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.sparql; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.jena.http.sys.ExecHTTPBuilder; +import org.apache.jena.query.Query; +import org.apache.jena.sparql.exec.QueryExecBuilder; +import org.apache.jena.sparql.exec.QueryExecMod; +import org.apache.jena.sparql.exec.http.Params; +import org.apache.jena.sparql.util.Context; +import org.eclipse.tractusx.agents.edc.AgentConfig; + +import java.net.http.HttpClient; +import java.util.HashMap; +import java.util.concurrent.TimeUnit; + +import static org.apache.jena.http.HttpLib.copyArray; + +/** + * A builder for KA Remote Query Execs + */ +public class QueryExecutorBuilder extends ExecHTTPBuilder implements QueryExecMod, QueryExecBuilder { + + public static QueryExecutorBuilder create() { + return new QueryExecutorBuilder(); + } + + public static QueryExecutorBuilder service(String serviceUrl) { + return create().endpoint(serviceUrl); + } + + private QueryExecutorBuilder() { + } + + @Override + protected QueryExecutorBuilder thisBuilder() { + return this; + } + + protected ObjectMapper objectMapper; + protected AgentConfig agentConfig; + + @Override + protected QueryExecutor buildX(HttpClient httpClient, Query queryActual, String queryStringActual, Context cxt) { + return new QueryExecutor(serviceURL, queryActual, queryStringActual, urlLimit, + httpClient, new HashMap<>(httpHeaders), Params.create(params), cxt, + copyArray(defaultGraphURIs), + copyArray(namedGraphURIs), + sendMode, appAcceptHeader, + timeout, timeoutUnit, objectMapper, agentConfig); + } + + @Override + public QueryExecutorBuilder initialTimeout(long timeout, TimeUnit timeUnit) { + throw new UnsupportedOperationException(); + } + + public QueryExecutorBuilder objectMapper(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + return this; + } + + public QueryExecutorBuilder agentConfig(AgentConfig agentConfig) { + this.agentConfig = agentConfig; + return this; + } + + @Override + public QueryExecutorBuilder overallTimeout(long timeout, TimeUnit timeUnit) { + super.timeout(timeout, timeUnit); + return thisBuilder(); + } + + @Override + public Context getContext() { + return null; + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterFutures.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterFutures.java new file mode 100644 index 00000000..efe1fcde --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterFutures.java @@ -0,0 +1,177 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.sparql; + +import org.apache.jena.atlas.io.IndentedWriter; +import org.apache.jena.graph.Node; +import org.apache.jena.sparql.core.Var; +import org.apache.jena.sparql.engine.QueryIterator; +import org.apache.jena.sparql.engine.binding.Binding; +import org.apache.jena.sparql.engine.iterator.QueryIteratorBase; +import org.apache.jena.sparql.serializer.SerializationContext; +import org.apache.jena.sparql.util.Context; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.tractusx.agents.edc.AgentConfig; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +/** + * A query iterator sitting on a set of future query iterators + * It will get and produce contextual information in order to collect any + * errors appearing. + */ +public class QueryIterFutures extends QueryIteratorBase { + + final List> futures; + QueryIterator current; + Binding lastBinding; + final Monitor monitor; + final AgentConfig config; + + final String sourceTenant; + final String sourceAsset; + final Node targetNode; + final Context executionContext; + + /** + * creates a new future iterator + * + * @param config agent config + * @param monitor logging subsystem + * @param sourceTenant the name/uri of the source tenant + * @param targetNode a node (var, the name/uri of the remote tenant + * @param sourceAsset the name of the calling/consuming graph + * @param executionContext description of the execution context + * @param futures list of futures to synchronize on + */ + public QueryIterFutures(AgentConfig config, Monitor monitor, String sourceTenant, String sourceAsset, Node targetNode, Context executionContext, List> futures) { + this.futures = futures; + this.monitor = monitor; + this.config = config; + this.sourceAsset = sourceAsset; + this.sourceTenant = sourceTenant; + this.targetNode = targetNode; + this.executionContext = executionContext; + } + + /** + * access + * + * @return whether any service has/will produce any binding + */ + @Override + protected boolean hasNextBinding() { + return (current != null && current.hasNext()) || hasNextInternalBinding(); + } + + /** + * access + * + * @return the last service node bindings uri + */ + protected String getTargetTenant() { + Node resolvedNode = targetNode; + if (targetNode.isVariable() && lastBinding != null) { + resolvedNode = lastBinding.get((Var) targetNode); + } + if (resolvedNode != null) { + return resolvedNode.toString(false); + } + return ""; + } + + /** + * access + * + * @return the last service node bindings asset + */ + protected String getTargetAsset() { + return getTargetTenant(); + } + + /** + * move to the next ready-made future (or sync/poll for the next ready-made one in a recursion) + * + * @return whether any service has/will produce any binding + */ + boolean hasNextInternalBinding() { + if (!futures.isEmpty()) { + Optional> boundFuture = futures.stream().filter(Future::isDone).findFirst(); + try { + if (boundFuture.isPresent()) { + Future currentFuture = boundFuture.get(); + futures.remove(currentFuture); + current = currentFuture.get(); + } else { + Thread.sleep(config.getNegotiationPollInterval()); + } + } catch (InterruptedException e) { + List warnings = CatenaxWarning.getOrSetWarnings(executionContext); + CatenaxWarning newWarning = new CatenaxWarning(); + newWarning.setSourceAsset(sourceAsset); + newWarning.setSourceTenant(sourceTenant); + newWarning.setTargetAsset(getTargetAsset()); + newWarning.setTargetTenant(getTargetTenant()); + newWarning.setContext(String.valueOf(executionContext.hashCode())); + newWarning.setProblem("Timeout/Interruption invoking a remote batch: Result may be partial."); + warnings.add(newWarning); + monitor.warning(String.format("Produced warning %s for context %s", newWarning, executionContext), e); + } catch (ExecutionException e) { + List warnings = CatenaxWarning.getOrSetWarnings(executionContext); + CatenaxWarning newWarning = new CatenaxWarning(); + newWarning.setSourceAsset(sourceAsset); + newWarning.setSourceTenant(sourceTenant); + newWarning.setTargetAsset(getTargetAsset()); + newWarning.setTargetTenant(getTargetTenant()); + newWarning.setContext(String.valueOf(executionContext.hashCode())); + newWarning.setProblem("Failure invoking a remote batch: Result may be partial."); + warnings.add(newWarning); + monitor.warning(String.format("Produced warning %s for context %s", newWarning, executionContext), e); + } + return hasNextBinding(); + } + return false; + } + + @Override + protected Binding moveToNextBinding() { + lastBinding = current.next(); + return lastBinding; + } + + @Override + protected void closeIterator() { + requestCancel(); + if (current != null) { + current.close(); + current = null; + } + } + + @Override + protected void requestCancel() { + futures.forEach(future -> future.cancel(true)); + futures.clear(); + } + + @Override + public void output(IndentedWriter indentedWriter, SerializationContext serializationContext) { + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterJoin.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterJoin.java new file mode 100644 index 00000000..7ad26690 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterJoin.java @@ -0,0 +1,100 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.sparql; + +import org.apache.jena.atlas.io.IndentedWriter; +import org.apache.jena.atlas.lib.Lib; +import org.apache.jena.graph.Node; +import org.apache.jena.sparql.core.Var; +import org.apache.jena.sparql.engine.ExecutionContext; +import org.apache.jena.sparql.engine.QueryIterator; +import org.apache.jena.sparql.engine.binding.Binding; +import org.apache.jena.sparql.engine.binding.BindingBuilder; +import org.apache.jena.sparql.engine.iterator.QueryIter1; +import org.apache.jena.sparql.serializer.SerializationContext; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * Query join iterator + * Prepares the given bindings with a hidden variable which is then projected + */ +public class QueryIterJoin extends QueryIter1 { + protected final Map> joinBindings; + protected final Var idVar; + protected Iterator leftBindings; + + public QueryIterJoin(QueryIterator input, Map> joinBindings, Var idVar, ExecutionContext execCxt) { + super(input, execCxt); + this.joinBindings = joinBindings; + this.idVar = idVar; + } + + @Override + protected void closeSubIterator() { + } + + @Override + protected void requestSubCancel() { + } + + @Override + public boolean hasNextBinding() { + return (leftBindings != null && leftBindings.hasNext()) || hasNextInputBinding(); + } + + protected boolean hasNextInputBinding() { + if (this.getInput().hasNext()) { + Binding nextBinding = this.getInput().next(); + Node idNode = nextBinding.get(idVar); + List resultBindings = joinBindings.get(idNode); + if (resultBindings != null) { + leftBindings = resultBindings.stream().map(resultBinding -> { + BindingBuilder bb = BindingBuilder.create(resultBinding); + nextBinding.forEach((v, n) -> { + if (!resultBinding.contains(v)) { + bb.set(v, n); + } + }); + return bb.build(); + }).iterator(); + } else { + leftBindings = null; + } + return hasNextBinding(); + } else { + return false; + } + } + + @Override + public Binding moveToNextBinding() { + if (leftBindings != null && leftBindings.hasNext()) { + return leftBindings.next(); + } else { + return null; + } + } + + @Override + protected void details(IndentedWriter out, SerializationContext cxt) { + out.println(Lib.className(this)); + } +} + diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SkillVariableDetector.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SkillVariableDetector.java new file mode 100644 index 00000000..bbc6b966 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SkillVariableDetector.java @@ -0,0 +1,68 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.sparql; + +import org.apache.jena.graph.Node; +import org.apache.jena.sparql.algebra.Op; +import org.apache.jena.sparql.algebra.TransformSingle; +import org.apache.jena.sparql.algebra.op.OpExtend; +import org.apache.jena.sparql.core.Var; +import org.apache.jena.sparql.expr.ExprVar; +import org.apache.jena.sparql.expr.NodeValue; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * a pseudo transform which visits every graph node + * to list all variables. helps us to + * only serialize the needed portion from + * consumer to producer + */ +public class SkillVariableDetector extends TransformSingle { + + HashMap variables = new HashMap<>(); + Set allowed; + + public SkillVariableDetector(Set allowed) { + this.allowed = allowed; + } + + @Override + public Op transform(OpExtend opExtend, Op subOp) { + opExtend.getVarExprList().forEachExpr((assignment, expr) -> { + String varName = assignment.getVarName(); + if (!variables.containsKey(varName)) { + if (expr.isVariable()) { + Var var = (Var) ((ExprVar) expr).getAsNode(); + if (allowed.contains(var.getVarName())) { + variables.put(varName, var); + } + } else if (expr.isConstant()) { + Node node = ((NodeValue) expr).getNode(); + variables.put(varName, node); + } + } + }); + return opExtend; + } + + public Map getVariables() { + return variables; + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQueryProcessor.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQueryProcessor.java new file mode 100644 index 00000000..19700196 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQueryProcessor.java @@ -0,0 +1,498 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.sparql; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.ws.rs.BadRequestException; +import jakarta.ws.rs.InternalServerErrorException; +import okhttp3.Request; +import okhttp3.Response; +import org.apache.http.HttpStatus; +import org.apache.jena.atlas.lib.Pair; +import org.apache.jena.fuseki.Fuseki; +import org.apache.jena.fuseki.server.DataAccessPointRegistry; +import org.apache.jena.fuseki.server.OperationRegistry; +import org.apache.jena.fuseki.servlets.ActionErrorException; +import org.apache.jena.fuseki.servlets.HttpAction; +import org.apache.jena.fuseki.servlets.SPARQL_QueryGeneral; +import org.apache.jena.query.Query; +import org.apache.jena.query.QueryExecException; +import org.apache.jena.sparql.ARQConstants; +import org.apache.jena.sparql.algebra.optimize.RewriteFactory; +import org.apache.jena.sparql.core.DatasetGraph; +import org.apache.jena.sparql.engine.http.QueryExceptionHTTP; +import org.apache.jena.sparql.service.ServiceExecutorRegistry; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.edc.MonitorWrapper; +import org.eclipse.tractusx.agents.edc.Tuple; +import org.eclipse.tractusx.agents.edc.TupleSet; +import org.eclipse.tractusx.agents.edc.http.AgentHttpAction; +import org.eclipse.tractusx.agents.edc.http.HttpServletContextAdapter; +import org.eclipse.tractusx.agents.edc.http.HttpServletRequestAdapter; +import org.eclipse.tractusx.agents.edc.http.HttpServletResponseAdapter; +import org.eclipse.tractusx.agents.edc.http.HttpUtils; +import org.eclipse.tractusx.agents.edc.http.JakartaAdapter; +import org.eclipse.tractusx.agents.edc.http.transfer.AgentSourceHttpParamsDecorator; +import org.eclipse.tractusx.agents.edc.rdf.RdfStore; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * dedicated SparQL query processor which is skill-enabled and open for edc-based services: + * Execute predefined queries and parameterize the queries with an additional layer + * of URL parameterization. + */ +public class SparqlQueryProcessor extends SPARQL_QueryGeneral.SPARQL_QueryProc { + + /** + * other services + */ + protected final Monitor monitor; + protected final ServiceExecutorRegistry registry; + protected final AgentConfig config; + protected final ObjectMapper objectMapper; + + /** + * state + */ + protected final OperationRegistry operationRegistry = OperationRegistry.createEmpty(); + protected final DataAccessPointRegistry dataAccessPointRegistry = new DataAccessPointRegistry(); + protected final RewriteFactory optimizerFactory = new OptimizerFactory(); + + // map EDC monitor to SLF4J (better than the builtin MonitorProvider) + private final MonitorWrapper monitorWrapper; + // some state to set when interacting with Fuseki + protected final RdfStore rdfStore; + private long count = -1; + + public static final String UNSET_BASE = "http://server/unset-base/"; + + /** + * create a new sparql processor + * + * @param registry service execution registry + * @param monitor EDC logging + */ + public SparqlQueryProcessor(ServiceExecutorRegistry registry, Monitor monitor, AgentConfig config, RdfStore rdfStore, TypeManager typeManager) { + this.monitor = monitor; + this.registry = registry; + this.config = config; + this.monitorWrapper = new MonitorWrapper(getClass().getName(), monitor); + this.rdfStore = rdfStore; + this.objectMapper = typeManager.getMapper(); + dataAccessPointRegistry.register(rdfStore.getDataAccessPoint()); + } + + /** + * access + * + * @return the operation registry + */ + public OperationRegistry getOperationRegistry() { + return operationRegistry; + } + + /** + * access + * + * @return the data access point registry + */ + public DataAccessPointRegistry getDataAccessPointRegistry() { + return dataAccessPointRegistry; + } + + /** + * wraps a response to a previous servlet API + * + * @param jakartaResponse new servlet object + * @return wrapped/adapted response + */ + public javax.servlet.http.HttpServletResponse getJavaxResponse(HttpServletResponse jakartaResponse) { + return JakartaAdapter.javaxify(jakartaResponse, javax.servlet.http.HttpServletResponse.class, monitor); + } + + /** + * wraps a request to a previous servlet API + * + * @param jakartaRequest new servlet object + * @return wrapped/adapted request + */ + public javax.servlet.http.HttpServletRequest getJavaxRequest(HttpServletRequest jakartaRequest) { + return JakartaAdapter.javaxify(jakartaRequest, javax.servlet.http.HttpServletRequest.class, monitor); + } + + /** + * execute sparql based on the given request and response + * + * @param request jakarta request + * @param response jakarta response + * @param skill skill ref + * @param graph graph ref + */ + public void execute(HttpServletRequest request, HttpServletResponse response, String skill, String graph) { + request.getServletContext().setAttribute(Fuseki.attrVerbose, config.isSparqlVerbose()); + request.getServletContext().setAttribute(Fuseki.attrOperationRegistry, operationRegistry); + request.getServletContext().setAttribute(Fuseki.attrNameRegistry, dataAccessPointRegistry); + AgentHttpAction action = new AgentHttpAction(++count, monitorWrapper, getJavaxRequest(request), getJavaxResponse(response), skill, graph); + // Should we check whether this already has been done? the context should be quite static + action.setRequest(rdfStore.getDataAccessPoint(), rdfStore.getDataService()); + ServiceExecutorRegistry.set(action.getContext(), registry); + action.getContext().set(ARQConstants.sysOptimizerFactory, optimizerFactory); + List previous = CatenaxWarning.getWarnings(action.getContext()); + CatenaxWarning.setWarnings(action.getContext(), null); + try { + executeAction(action); + List newWarnings = CatenaxWarning.getWarnings(action.getContext()); + if (newWarnings != null) { + response.addHeader("cx_warnings", objectMapper.writeValueAsString(newWarnings)); + response.addHeader("Access-Control-Expose-Headers", "cx_warnings, content-length, content-type"); + if (response.getStatus() == 200) { + response.setStatus(203); + } + } + } catch (ActionErrorException e) { + throw new BadRequestException(e.getMessage(), e.getCause()); + } catch (QueryExecException | JsonProcessingException e) { + throw new InternalServerErrorException(e.getMessage(), e.getCause()); + } finally { + CatenaxWarning.setWarnings(action.getContext(), previous); + } + } + + /** + * execute sparql based on the given request and response and address properties + * + * @param request jakarta request + * @param response jakarta response + * @param skill skill ref + * @param graph graph ref + * @param targetProperties a set of address properties of the asset to invoke + */ + public void execute(HttpServletRequest request, HttpServletResponse response, String skill, String graph, Map targetProperties) { + + request.setAttribute(Fuseki.attrVerbose, config.isSparqlVerbose()); + request.setAttribute(Fuseki.attrOperationRegistry, operationRegistry); + request.setAttribute(Fuseki.attrNameRegistry, dataAccessPointRegistry); + + // build and populate a SPARQL action from the wrappers + AgentHttpAction action = new AgentHttpAction(++count, monitorWrapper, getJavaxRequest(request), getJavaxResponse(response), skill, graph); + action.setRequest(rdfStore.getDataAccessPoint(), rdfStore.getDataService()); + ServiceExecutorRegistry.set(action.getContext(), registry); + action.getContext().set(DataspaceServiceExecutor.TARGET_URL_SYMBOL, targetProperties.getOrDefault(DataspaceServiceExecutor.TARGET_URL_SYMBOL.getSymbol(), null)); + action.getContext().set(DataspaceServiceExecutor.AUTH_KEY_SYMBOL, targetProperties.getOrDefault(DataspaceServiceExecutor.AUTH_KEY_SYMBOL.getSymbol(), null)); + action.getContext().set(DataspaceServiceExecutor.AUTH_CODE_SYMBOL, targetProperties.getOrDefault(DataspaceServiceExecutor.AUTH_CODE_SYMBOL.getSymbol(), null)); + action.getContext().set(ARQConstants.sysOptimizerFactory, optimizerFactory); + if (targetProperties.containsKey(DataspaceServiceExecutor.ALLOW_SYMBOL.getSymbol())) { + action.getContext().set(DataspaceServiceExecutor.ALLOW_SYMBOL, + Pattern.compile(String.valueOf(targetProperties.get(DataspaceServiceExecutor.ALLOW_SYMBOL.getSymbol())))); + } else { + action.getContext().set(DataspaceServiceExecutor.ALLOW_SYMBOL, config.getServiceAssetAllowPattern()); + } + if (targetProperties.containsKey(DataspaceServiceExecutor.DENY_SYMBOL.getSymbol())) { + action.getContext().set(DataspaceServiceExecutor.DENY_SYMBOL, + Pattern.compile(String.valueOf(targetProperties.get(DataspaceServiceExecutor.DENY_SYMBOL.getSymbol())))); + } else { + action.getContext().set(DataspaceServiceExecutor.DENY_SYMBOL, config.getServiceAssetDenyPattern()); + } + if (graph != null) { + action.getContext().set(DataspaceServiceExecutor.ASSET_SYMBOL, graph); + } + List previous = CatenaxWarning.getWarnings(action.getContext()); + CatenaxWarning.setWarnings(action.getContext(), null); + + // and finally execute the SPARQL action + try { + executeAction(action); + List newWarnings = CatenaxWarning.getWarnings(action.getContext()); + if (newWarnings != null) { + response.addHeader("cx_warnings", objectMapper.writeValueAsString(newWarnings)); + response.addHeader("Access-Control-Expose-Headers", "cx_warnings, content-length, content-type"); + } + if (response.getStatus() == 200) { + response.setStatus(203); + } + } catch (ActionErrorException e) { + try { + response.sendError(HttpStatus.SC_BAD_REQUEST, e.getMessage()); + } catch (Exception e1) { + monitor.debug(e1.getMessage()); + } + } catch (QueryExecException | JsonProcessingException | QueryExceptionHTTP e) { + try { + response.sendError(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + } catch (Exception e1) { + monitor.debug(e1.getMessage()); + } + } finally { + CatenaxWarning.setWarnings(action.getContext(), previous); + } + return; + } + + + /** + * execute the given action. Circumvents + * too strict SPARQL requirements in favor + * to KA-MATCH semantics. + * + * @param action a jena http action + */ + protected void executeAction(AgentHttpAction action) { + if (action.getRequestMethod().equals("GET")) { + this.executeWithParameter(action); + } else { + this.executeBody(action); + } + } + + /** + * execute sparql based on the given internal okhttp request and response + * + * @param request ok request + * @param skill skill ref + * @param graph graph ref + * @param targetProperties a set of address properties of the asset to invoke + * @return simulated ok response + */ + public Response execute(Request request, String skill, String graph, Map targetProperties) { + + // wrap jakarta into java.servlet + HttpServletContextAdapter contextAdapter = new HttpServletContextAdapter(request); + HttpServletRequestAdapter requestAdapter = new HttpServletRequestAdapter(request, contextAdapter); + HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(request); + contextAdapter.setAttribute(Fuseki.attrVerbose, config.isSparqlVerbose()); + contextAdapter.setAttribute(Fuseki.attrOperationRegistry, operationRegistry); + contextAdapter.setAttribute(Fuseki.attrNameRegistry, dataAccessPointRegistry); + + // build and populate a SPARQL action from the wrappers + AgentHttpAction action = new AgentHttpAction(++count, monitorWrapper, requestAdapter, responseAdapter, skill, graph); + action.setRequest(rdfStore.getDataAccessPoint(), rdfStore.getDataService()); + ServiceExecutorRegistry.set(action.getContext(), registry); + action.getContext().set(DataspaceServiceExecutor.TARGET_URL_SYMBOL, request.header(DataspaceServiceExecutor.TARGET_URL_SYMBOL.getSymbol())); + action.getContext().set(DataspaceServiceExecutor.AUTH_KEY_SYMBOL, targetProperties.getOrDefault(DataspaceServiceExecutor.AUTH_KEY_SYMBOL.getSymbol(), null)); + action.getContext().set(DataspaceServiceExecutor.AUTH_CODE_SYMBOL, targetProperties.getOrDefault(DataspaceServiceExecutor.AUTH_CODE_SYMBOL.getSymbol(), null)); + action.getContext().set(ARQConstants.sysOptimizerFactory, optimizerFactory); + if (targetProperties.containsKey(DataspaceServiceExecutor.ALLOW_SYMBOL.getSymbol())) { + action.getContext().set(DataspaceServiceExecutor.ALLOW_SYMBOL, + Pattern.compile(String.valueOf(targetProperties.get(DataspaceServiceExecutor.ALLOW_SYMBOL.getSymbol())))); + } else { + action.getContext().set(DataspaceServiceExecutor.ALLOW_SYMBOL, config.getServiceAssetAllowPattern()); + } + if (targetProperties.containsKey(DataspaceServiceExecutor.DENY_SYMBOL.getSymbol())) { + action.getContext().set(DataspaceServiceExecutor.DENY_SYMBOL, + Pattern.compile(String.valueOf(targetProperties.get(DataspaceServiceExecutor.DENY_SYMBOL.getSymbol())))); + } else { + action.getContext().set(DataspaceServiceExecutor.DENY_SYMBOL, config.getServiceAssetDenyPattern()); + } + if (graph != null) { + action.getContext().set(DataspaceServiceExecutor.ASSET_SYMBOL, graph); + } + List previous = CatenaxWarning.getWarnings(action.getContext()); + CatenaxWarning.setWarnings(action.getContext(), null); + + // and finally execute the SPARQL action + try { + executeAction(action); + List newWarnings = CatenaxWarning.getWarnings(action.getContext()); + if (newWarnings != null) { + responseAdapter.addHeader("cx_warnings", objectMapper.writeValueAsString(newWarnings)); + responseAdapter.addHeader("Access-Control-Expose-Headers", "cx_warnings, content-length, content-type"); + } + if (responseAdapter.getStatus() == 200) { + responseAdapter.setStatus(203); + } + } catch (ActionErrorException e) { + responseAdapter.setStatus(HttpStatus.SC_BAD_REQUEST, e.getMessage()); + } catch (QueryExecException | JsonProcessingException | QueryExceptionHTTP e) { + responseAdapter.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + } finally { + CatenaxWarning.setWarnings(action.getContext(), previous); + } + return responseAdapter.toResponse(); + } + + /** + * execute GET-style with possibility of asset=local skill + * + * @param action typically a GET request + */ + @Override + protected void executeWithParameter(HttpAction action) { + String queryString = ((AgentHttpAction) action).getSkill(); + if (queryString == null) { + super.executeWithParameter(action); + } else { + execute(queryString, action); + } + } + + /** + * execute POST-style with possiblity of asset=local skill + * + * @param action typically a POST request + */ + @Override + protected void executeBody(HttpAction action) { + String queryString = ((AgentHttpAction) action).getSkill(); + if (queryString == null) { + super.executeBody(action); + } else { + execute(queryString, action); + } + } + + /** + * general (URL-parameterized) query execution + * + * @param queryString the resolved query + * @param action the http action containing the parameters + * TODO error handling + */ + @Override + protected void execute(String queryString, HttpAction action) { + // make sure the query param is decoded (which Fuseki sometimes forgets) + queryString = HttpUtils.urlDecodeParameter(queryString); + // support for the special www-forms form + if (action.getRequestContentType() != null && action.getRequestContentType().contains("application/x-www-form-urlencoded")) { + Map> parts = AgentSourceHttpParamsDecorator.parseParams(queryString); + Optional query = parts.getOrDefault("query", List.of()).stream().findFirst(); + if (query.isEmpty()) { + action.getResponse().setStatus(HttpStatus.SC_BAD_REQUEST); + return; + } else { + queryString = HttpUtils.urlDecodeParameter(query.get()); + } + } + TupleSet ts = ((AgentHttpAction) action).getInputBindings(); + Pattern tuplePattern = Pattern.compile("\\([^()]*\\)"); + Pattern variablePattern = Pattern.compile("@(?[a-zA-Z0-9]+)"); + Matcher tupleMatcher = tuplePattern.matcher(queryString); + StringBuilder replaceQuery = new StringBuilder(); + int lastStart = 0; + while (tupleMatcher.find()) { + replaceQuery.append(queryString.substring(lastStart, tupleMatcher.start())); + String otuple = tupleMatcher.group(0); + Matcher variableMatcher = variablePattern.matcher(otuple); + List variables = new java.util.ArrayList<>(); + while (variableMatcher.find()) { + variables.add(variableMatcher.group("name")); + } + if (variables.size() > 0) { + try { + boolean isFirst = true; + Collection tuples = ts.getTuples(variables.toArray(new String[0])); + for (Tuple rtuple : tuples) { + if (isFirst) { + isFirst = false; + } else { + replaceQuery.append(" "); + } + String newTuple = otuple; + for (String key : rtuple.getVariables()) { + newTuple = newTuple.replace("@" + key, rtuple.get(key)); + } + replaceQuery.append(newTuple); + } + } catch (Exception e) { + System.err.println(e.getMessage()); + action.getResponse().setStatus(HttpStatus.SC_BAD_REQUEST); + return; + } + } else { + replaceQuery.append(otuple); + } + lastStart = tupleMatcher.end(); + } + replaceQuery.append(queryString.substring(lastStart)); + + queryString = replaceQuery.toString(); + Matcher variableMatcher = variablePattern.matcher(queryString); + List variables = new java.util.ArrayList<>(); + while (variableMatcher.find()) { + variables.add(variableMatcher.group("name")); + } + try { + Collection tuples = ts.getTuples(variables.toArray(new String[0])); + if (tuples.size() == 0 && variables.size() > 0) { + throw new BadRequestException(String.format("Error: Got variables %s on top-level but no bindings.", Arrays.toString(variables.toArray()))); + } else if (tuples.size() > 1) { + System.err.println(String.format("Warning: Got %s tuples for top-level bindings of variables %s. Using only the first one.", tuples.size(), Arrays.toString(variables.toArray()))); + } + if (tuples.size() > 0) { + Tuple rtuple = tuples.iterator().next(); + for (String key : rtuple.getVariables()) { + queryString = queryString.replace("@" + key, rtuple.get(key)); + } + } + } catch (Exception e) { + throw new BadRequestException(String.format("Error: Could not bind variables"), e); + } + + // + // Matchmaking Agent As Proxy: + // Replace any Graph occurrence by SERVICE + // as long as the DataAddress does not point to a local graph + // + if (action.getContext().isDefined(DataspaceServiceExecutor.ASSET_SYMBOL)) { + String targetUrl = action.getContext().get(DataspaceServiceExecutor.TARGET_URL_SYMBOL); + // local graphs have this fixed base url + if (!targetUrl.equals("https://w3id.org/catenax")) { + String asset = action.getContext().get(DataspaceServiceExecutor.ASSET_SYMBOL); + asset = asset.replace("?", "\\?"); + String graphPattern = String.format("GRAPH\\s*\\?", UNSET_BASE, asset); + Matcher graphMatcher = Pattern.compile(graphPattern).matcher(queryString); + replaceQuery = new StringBuilder(); + lastStart = 0; + while (graphMatcher.find()) { + replaceQuery.append(queryString.substring(lastStart, graphMatcher.start() - 1)); + replaceQuery.append(String.format("SERVICE <%s>", targetUrl)); + lastStart = graphMatcher.end(); + } + replaceQuery.append(queryString.substring(lastStart)); + queryString = replaceQuery.toString(); + } + + } + super.execute(queryString, action); + } + + /** + * deal with predefined assets=local graphs + */ + @Override + protected Pair decideDataset(HttpAction action, Query query, String queryStringLog) { + // These will have been taken care of by the "getDatasetDescription" + if (query.hasDatasetDescription()) { + // Don't modify input. + query = query.cloneQuery(); + query.getNamedGraphURIs().clear(); + query.getGraphURIs().clear(); + } + return Pair.create(rdfStore.getDataSet(), query); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializer.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializer.java new file mode 100644 index 00000000..58dd9aee --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializer.java @@ -0,0 +1,415 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.sparql; + +import org.apache.jena.atlas.io.IndentedWriter; +import org.apache.jena.graph.Node; +import org.apache.jena.query.Query; +import org.apache.jena.query.QueryVisitor; +import org.apache.jena.query.SortCondition; +import org.apache.jena.sparql.core.Prologue; +import org.apache.jena.sparql.core.Var; +import org.apache.jena.sparql.core.VarExprList; +import org.apache.jena.sparql.engine.binding.Binding; +import org.apache.jena.sparql.expr.Expr; +import org.apache.jena.sparql.serializer.FmtExprSPARQL; +import org.apache.jena.sparql.serializer.FormatterTemplate; +import org.apache.jena.sparql.serializer.PrologueSerializer; +import org.apache.jena.sparql.serializer.SerializationContext; +import org.apache.jena.sparql.syntax.Element; +import org.apache.jena.sparql.syntax.Template; +import org.apache.jena.sparql.util.FmtUtils; + +import java.io.OutputStream; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * we need to reimplement QuerySerializer just because of hidden constructors + * All we want to reach is to put a different formatter element into + * the call. + * TODO try to remove this by another solution (reflection?) + */ +public class SparqlQuerySerializer implements QueryVisitor { + protected FormatterTemplate fmtTemplate; + protected StratifiedFormatterElement fmtElement; + protected FmtExprSPARQL fmtExpr; + protected IndentedWriter out; + protected Prologue prologue; + + public SparqlQuerySerializer(OutputStream outStream, StratifiedFormatterElement formatterElement, FmtExprSPARQL formatterExpr, FormatterTemplate formatterTemplate) { + this(new IndentedWriter(outStream), formatterElement, formatterExpr, formatterTemplate); + } + + public SparqlQuerySerializer(IndentedWriter iwriter, StratifiedFormatterElement formatterElement, FmtExprSPARQL formatterExpr, FormatterTemplate formatterTemplate) { + this.prologue = null; + this.out = iwriter; + this.fmtTemplate = formatterTemplate; + this.fmtElement = formatterElement; + this.fmtExpr = formatterExpr; + } + + @Override + public void startVisit(Query query) { + } + + @Override + public void visitResultForm(Query query) { + } + + @Override + public void visitPrologue(Prologue prologue) { + this.prologue = prologue; + int row1 = this.out.getRow(); + PrologueSerializer.output(this.out, prologue); + int row2 = this.out.getRow(); + if (row1 != row2) { + this.out.newline(); + } + } + + @Override + public void visitSelectResultForm(Query query) { + this.out.print("SELECT "); + if (query.isDistinct()) { + this.out.print("DISTINCT "); + } + + if (query.isReduced()) { + this.out.print("REDUCED "); + } + + this.out.print(" "); + if (query.isQueryResultStar()) { + this.out.print("*"); + } else { + this.appendNamedExprList(this.out, query.getProject()); + } + + this.out.newline(); + } + + @Override + public void visitConstructResultForm(Query query) { + this.out.print("CONSTRUCT "); + this.out.incIndent(2); + this.out.newline(); + Template t = query.getConstructTemplate(); + this.fmtTemplate.format(t); + this.out.decIndent(2); + } + + @Override + public void visitDescribeResultForm(Query query) { + this.out.print("DESCRIBE "); + if (query.isQueryResultStar()) { + this.out.print("*"); + } else { + this.appendVarList(this.out, query.getResultVars()); + if (query.getResultVars().size() > 0 && query.getResultURIs().size() > 0) { + this.out.print(" "); + } + + appendUriList(query, this.out, query.getResultURIs()); + } + + this.out.newline(); + } + + @Override + public void visitAskResultForm(Query query) { + this.out.print("ASK"); + this.out.newline(); + } + + @Override + public void visitJsonResultForm(Query query) { + this.out.println("JSON {"); + this.out.incIndent(2); + this.out.incIndent(2); + boolean first = true; + + for (Map.Entry entry : query.getJsonMapping().entrySet()) { + String field = entry.getKey(); + Node value = entry.getValue(); + if (!first) { + this.out.println(" ,"); + } + + first = false; + this.out.print('"'); + this.out.print(field); + this.out.print('"'); + this.out.print(" : "); + this.out.pad(15); + this.out.print(FmtUtils.stringForNode(value, this.prologue)); + } + + this.out.decIndent(2); + this.out.decIndent(2); + this.out.print(" }"); + this.out.newline(); + } + + @Override + public void visitDatasetDecl(Query query) { + Iterator var2; + String uri; + if (query.getGraphURIs() != null && query.getGraphURIs().size() != 0) { + var2 = query.getGraphURIs().iterator(); + + while (var2.hasNext()) { + uri = var2.next(); + this.out.print("FROM "); + this.out.print(FmtUtils.stringForURI(uri, query)); + this.out.newline(); + } + } + + if (query.getNamedGraphURIs() != null && query.getNamedGraphURIs().size() != 0) { + var2 = query.getNamedGraphURIs().iterator(); + + while (var2.hasNext()) { + uri = var2.next(); + this.out.print("FROM NAMED "); + this.out.print(FmtUtils.stringForURI(uri, query)); + this.out.newline(); + } + } + + } + + @Override + public void visitQueryPattern(Query query) { + if (query.getQueryPattern() != null) { + this.out.print("WHERE"); + this.out.incIndent(2); + this.out.newline(); + Element el = query.getQueryPattern(); + this.fmtElement.visitAsGroup(el); + this.out.decIndent(2); + this.out.newline(); + } + + } + + @Override + public void visitGroupBy(Query query) { + if (query.hasGroupBy() && !query.getGroupBy().isEmpty()) { + this.out.print("GROUP BY "); + this.appendNamedExprList(this.out, query.getGroupBy()); + this.out.println(); + } + + } + + @Override + public void visitHaving(Query query) { + if (query.hasHaving()) { + this.out.print("HAVING"); + + for (Expr expr : query.getHavingExprs()) { + this.out.print(" "); + this.fmtExpr.format(expr); + } + + this.out.println(); + } + + } + + @Override + public void visitOrderBy(Query query) { + if (query.hasOrderBy()) { + this.out.print("ORDER BY "); + boolean first = true; + + for (Iterator var3 = query.getOrderBy().iterator(); var3.hasNext(); first = false) { + SortCondition sc = var3.next(); + if (!first) { + this.out.print(" "); + } + + sc.format(this.fmtExpr, this.out); + } + + this.out.println(); + } + + } + + @Override + public void visitLimit(Query query) { + if (query.hasLimit()) { + this.out.print("LIMIT " + query.getLimit()); + this.out.newline(); + } + + } + + @Override + public void visitOffset(Query query) { + if (query.hasOffset()) { + this.out.print("OFFSET " + query.getOffset()); + this.out.newline(); + } + + } + + @Override + public void visitValues(Query query) { + if (query.hasValues()) { + outputDataBlock(this.out, query.getValuesVariables(), query.getValuesData(), this.fmtElement.sc); + this.out.newline(); + } + + } + + public static void outputDataBlock(IndentedWriter out, List variables, List values, SerializationContext cxt) { + out.print("VALUES "); + Binding valueRow; + if (variables.size() == 1) { + out.print("?"); + out.print(variables.get(0).getVarName()); + out.print(" {"); + out.incIndent(); + + for (Binding value : values) { + valueRow = value; + outputValuesOneRow(out, variables, valueRow, cxt); + } + + out.decIndent(); + out.print(" }"); + } else { + out.print("("); + + for (Var v : variables) { + out.print(" "); + out.print(v.toString()); + } + + out.print(" )"); + out.print(" {"); + out.incIndent(); + + for (Binding value : values) { + valueRow = value; + out.println(); + out.print("("); + outputValuesOneRow(out, variables, valueRow, cxt); + out.print(" )"); + } + + out.decIndent(); + out.ensureStartOfLine(); + out.print("}"); + } + } + + private static void outputValuesOneRow(IndentedWriter out, List variables, Binding row, SerializationContext cxt) { + + for (Var var : variables) { + out.print(" "); + Node value = row.get(var); + if (value == null) { + out.print("UNDEF"); + } else { + out.print(FmtUtils.stringForNode(value, cxt)); + } + } + + } + + @Override + public void finishVisit(Query query) { + this.out.flush(); + } + + void appendVarList(IndentedWriter sb, List vars) { + boolean first = true; + + for (Iterator var5 = vars.iterator(); var5.hasNext(); first = false) { + String varName = var5.next(); + Var var = Var.alloc(varName); + if (!first) { + sb.print(" "); + } + + sb.print(var.toString()); + } + + } + + void appendNamedExprList(IndentedWriter sb, VarExprList namedExprs) { + boolean first = true; + + for (Iterator var5 = namedExprs.getVars().iterator(); var5.hasNext(); first = false) { + Var var = var5.next(); + Expr expr = namedExprs.getExpr(var); + if (!first) { + sb.print(" "); + } + + if (expr != null) { + boolean needParens = true; + if (expr.isFunction()) { + needParens = false; + } else if (expr.isVariable()) { + needParens = false; + } + + if (!Var.isAllocVar(var)) { + needParens = true; + } + + if (needParens) { + this.out.print("("); + } + + this.fmtExpr.format(expr); + if (!Var.isAllocVar(var)) { + sb.print(" AS "); + sb.print(var.toString()); + } + + if (needParens) { + this.out.print(")"); + } + } else { + sb.print(var.toString()); + } + } + + } + + static void appendUriList(Query query, IndentedWriter sb, List vars) { + SerializationContext cxt = new SerializationContext(query); + boolean first = true; + + for (Iterator var5 = vars.iterator(); var5.hasNext(); first = false) { + Node node = var5.next(); + if (!first) { + sb.print(" "); + } + + sb.print(FmtUtils.stringForNode(node, cxt)); + } + + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializerFactory.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializerFactory.java new file mode 100644 index 00000000..7ecc1b75 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializerFactory.java @@ -0,0 +1,53 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.sparql; + +import org.apache.jena.atlas.io.IndentedWriter; +import org.apache.jena.query.QueryVisitor; +import org.apache.jena.query.Syntax; +import org.apache.jena.sparql.core.Prologue; +import org.apache.jena.sparql.serializer.FmtExprSPARQL; +import org.apache.jena.sparql.serializer.FmtTemplate; +import org.apache.jena.sparql.serializer.QuerySerializerFactory; +import org.apache.jena.sparql.serializer.SerializationContext; +import org.apache.jena.sparql.util.NodeToLabelMapBNode; + +/** + * A serializer factory for sparql queries which + * stratifies the resulting groups (joins) because not + * all SparQL endpoints (such as ONTOP) can deal with the + * level of nesting that fuseki syntax graphs represent with + * their max-2 child operators. + */ +public class SparqlQuerySerializerFactory implements QuerySerializerFactory { + @Override + public QueryVisitor create(Syntax syntax, Prologue prologue, IndentedWriter writer) { + SerializationContext cxt1 = new SerializationContext(prologue, new NodeToLabelMapBNode("b", false)); + SerializationContext cxt2 = new SerializationContext(prologue, new NodeToLabelMapBNode("c", false)); + return new SparqlQuerySerializer(writer, new StratifiedFormatterElement(writer, cxt1), new FmtExprSPARQL(writer, cxt1), new FmtTemplate(writer, cxt2)); + } + + @Override + public QueryVisitor create(Syntax syntax, SerializationContext context, IndentedWriter writer) { + return new SparqlQuerySerializer(writer, new StratifiedFormatterElement(writer, context), new FmtExprSPARQL(writer, context), new FmtTemplate(writer, context)); + } + + @Override + public boolean accept(Syntax syntax) { + return Syntax.syntaxARQ.equals(syntax) || Syntax.syntaxSPARQL_10.equals(syntax) || Syntax.syntaxSPARQL_11.equals(syntax); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/StratifiedFormatterElement.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/StratifiedFormatterElement.java new file mode 100644 index 00000000..824beb2c --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/StratifiedFormatterElement.java @@ -0,0 +1,120 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.sparql; + +import org.apache.jena.atlas.io.IndentedWriter; +import org.apache.jena.sparql.serializer.FormatterElement; +import org.apache.jena.sparql.serializer.SerializationContext; +import org.apache.jena.sparql.syntax.Element; +import org.apache.jena.sparql.syntax.ElementGroup; +import org.apache.jena.sparql.syntax.ElementPathBlock; +import org.apache.jena.sparql.syntax.ElementTriplesBlock; + +import java.util.Iterator; +import java.util.Stack; + +/** + * a formatter element which stratifies nested groups + * such that SparQL endpoints have less work optimizing the + * resulting (depp) trees. + */ +public class StratifiedFormatterElement extends FormatterElement { + + /** + * access the context by the serializer + */ + SerializationContext sc; + /** + * keep some state about the depth of the tree + */ + Stack mute = new Stack<>(); + + public StratifiedFormatterElement(IndentedWriter out, SerializationContext context) { + super(out, context); + this.sc = context; + } + + /** + * visit a join, only produce parenthesis if we are on the top level + * + * @param el group element + */ + + @Override + public void visit(ElementGroup el) { + if (mute.empty() || !mute.peek()) { + this.out.print("{"); + } + int initialRowNumber = this.out.getRow(); + this.out.incIndent(2); + int row1 = this.out.getRow(); + this.out.pad(); + boolean first = true; + Element lastElt = null; + + Element subElement; + for (Iterator var6 = el.getElements().iterator(); var6.hasNext(); lastElt = subElement) { + subElement = var6.next(); + if (!first) { + if (needsDotSeparator(lastElt, subElement)) { + this.out.print(" . "); + } + + this.out.newline(); + } + + if (subElement instanceof ElementGroup) { + mute.push(true); + } else { + mute.push(false); + } + subElement.visit(this); + mute.pop(); + first = false; + } + + this.out.decIndent(2); + int row2 = this.out.getRow(); + if (row1 != row2) { + this.out.newline(); + } + + if (this.out.getRow() == initialRowNumber) { + this.out.print(" "); + } + + if (mute.empty() || !mute.peek()) { + this.out.print("}"); + } + } + + + /** + * check whether two elements need a separator + * + * @param el1 first element + * @param el2 second element + * @return decide whether a dot is required between el1 and el2 + */ + private static boolean needsDotSeparator(Element el1, Element el2) { + return needsDotSeparator(el1) && needsDotSeparator(el2); + } + + private static boolean needsDotSeparator(Element el) { + return el instanceof ElementTriplesBlock || el instanceof ElementPathBlock; + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/VariableDetector.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/VariableDetector.java new file mode 100644 index 00000000..b85b64d9 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/VariableDetector.java @@ -0,0 +1,63 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.sparql; + +import org.apache.jena.graph.Node; +import org.apache.jena.sparql.core.Var; +import org.apache.jena.sparql.graph.NodeTransform; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Set; + +/** + * a pseudo transform which visits every graph node + * to list all variables. helps us to + * only serialize the needed portion from + * consumer to producer + */ +public class VariableDetector implements NodeTransform { + + HashMap variables = new HashMap<>(); + Set allowed; + + public VariableDetector(Set allowed) { + this.allowed = allowed; + } + + @Override + public Node apply(Node node) { + if (node.isVariable()) { + Var var = (Var) node; + String varName = var.getVarName(); + while (Var.isRenamedVar(varName)) { + varName = varName.substring(1); + var = Var.alloc(varName); + } + if (allowed.contains(varName) && !variables.containsKey(varName)) { + variables.put(varName, var); + } + return var; + } + return node; + } + + public List getVariables() { + return new ArrayList<>(variables.values()); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/validation/DataPlaneTokenValidationApi.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/validation/DataPlaneTokenValidationApi.java new file mode 100644 index 00000000..ba974e26 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/validation/DataPlaneTokenValidationApi.java @@ -0,0 +1,26 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.validation; + +import jakarta.ws.rs.core.Response; + +/** + * Rest interface to the token validator + */ +public interface DataPlaneTokenValidationApi { + Response validate(String token); +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/validation/SwitchingDataPlaneTokenValidatorController.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/validation/SwitchingDataPlaneTokenValidatorController.java new file mode 100644 index 00000000..be6599a3 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/validation/SwitchingDataPlaneTokenValidatorController.java @@ -0,0 +1,98 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.edc.validation; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.HeaderParam; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.tractusx.agents.edc.AgentConfig; + +import java.io.IOException; + +/** + * a token validator that may delegate to several control plane validators + */ +@Path("/validation") +public class SwitchingDataPlaneTokenValidatorController implements DataPlaneTokenValidationApi { + + protected final OkHttpClient httpClient; + protected final Monitor monitor; + protected final AgentConfig config; + protected final String[] endpoints; + + /** + * creates a new controller + * + * @param httpClient to use + * @param config to obey + * @param monitor to log + */ + public SwitchingDataPlaneTokenValidatorController(OkHttpClient httpClient, AgentConfig config, Monitor monitor) { + this.httpClient = httpClient; + this.config = config; + this.monitor = monitor; + this.endpoints = config.getValidatorEndpoints(); + } + + /** + * access + * + * @return a flag indicating whether this endpoint is enabled + */ + public boolean isEnabled() { + return endpoints != null && endpoints.length > 0; + } + + /** + * Validate the token provided in input by delegating to the multiple endpoints + * + * @param token Input token. + * @return Decrypted DataAddress contained in the input token claims. + */ + @GET + @Produces({ MediaType.APPLICATION_JSON }) + @Override + public Response validate(@HeaderParam(HttpHeaders.AUTHORIZATION) String token) { + Response result = Response.status(400, "No validation endpoint could be found to switch to.").build(); + if (isEnabled()) { + for (String endpoint : endpoints) { + var request = new Request.Builder().url(endpoint).header(HttpHeaders.AUTHORIZATION, token).get().build(); + try (var response = httpClient.newCall(request).execute()) { + var body = response.body(); + var stringBody = body != null ? body.string() : null; + if (stringBody == null) { + result = Response.status(400, "Token validation server returned null body").build(); + } else if (response.isSuccessful()) { + return Response.ok(stringBody).build(); + } else { + result = Response.status(response.code(), String.format("Call to token validation sever failed: %s - %s. %s", response.code(), response.message(), stringBody)).build(); + } + } catch (IOException e) { + result = Response.status(500, "Unhandled exception occurred during call to token validation server: " + e.getMessage()).build(); + } + } + } + return result; + } +} diff --git a/matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/ConformingAgentTest.java b/matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/ConformingAgentTest.java new file mode 100644 index 00000000..2a7675cb --- /dev/null +++ b/matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/ConformingAgentTest.java @@ -0,0 +1,158 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.eclipse.tractusx.agents.conforming.api.JsonProvider; +import org.eclipse.tractusx.agents.conforming.api.SparqlProvider; +import org.eclipse.tractusx.agents.conforming.api.XmlProvider; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.media.multipart.MultiPartFeature; +import org.glassfish.jersey.media.multipart.internal.MultiPartReaderClientSide; +import org.glassfish.jersey.test.DeploymentContext; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.jupiter.api.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import java.io.IOException; +import java.io.StringReader; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.Response; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Tests the conforming agents themselves + * common test setup and tests shared by KA-MATCH and KA-BIND profiles + */ +public abstract class ConformingAgentTest extends JerseyTest { + + protected ObjectMapper objectMapper = new ObjectMapper(); + + /** + * you cannot invoke without query or skill asset definition + */ + @Test + public void testUnderspecifiedGet() { + final Response response = target(getPath()).request().get(); + assertTrue(response.getStatus() >= 400 && response.getStatus() < 500, "KA-BIND/KA-MATCH: Should not be possible to get information without query or skill asset"); + } + + /** + * you cannot invoke without query or skill asset definition + */ + @Test + public void testUnderspecifiedPost() { + final Response response = target(getPath()).request().post(Entity.entity("", "application/sparql-results+json")); + assertTrue(response.getStatus() >= 400 && response.getStatus() < 500, "KA-BIND/KA-MATCH: Should not be possible to post information without query or skill asset"); + } + + /** + * you can always get with a simple sparql + */ + @Test + public void testBindGet() throws IOException { + Response response = target(getPath()) + .queryParam("query", "SELECT%20%3Fsubject%20%3Fpredicate%20%3Fobject%20WHERE%20%7B%20%3Fsubject%20%20%3Fobject.%7D") + .request() + .get(); + assertTrue(response.getStatus() >= 200 && response.getStatus() < 300, "Successful get json request"); + testJsonResultSet(response); + } + + /** + * you can always get with a simple sparql + */ + @Test + public void testBindGetXml() throws IOException, ParserConfigurationException, SAXException { + Response response = target(getPath()) + .queryParam("query", "SELECT%20%3Fsubject%20%3Fpredicate%20%3Fobject%20WHERE%20%7B%20%3Fsubject%20%20%3Fobject.%7D") + .request() + .accept("application/sparql-results+xml") + .get(); + assertTrue(response.getStatus() >= 200 && response.getStatus() < 300, "Successful get xml request"); + testXmlResultSet(response); + } + + protected abstract String getPath(); + + @Override + protected DeploymentContext configureDeployment() { + DeploymentContext context = super.configureDeployment(); + context.getResourceConfig().register(JsonProvider.class); + context.getResourceConfig().register(XmlProvider.class); + context.getResourceConfig().register(SparqlProvider.class); + context.getResourceConfig().packages("org.glassfish.jersey.examples.multipart") + .register(MultiPartFeature.class); + return context; + } + + @Override + protected void configureClient(ClientConfig config) { + super.configureClient(config); + config.register(MultiPartReaderClientSide.class); + } + + protected String getEntity(Response response) { + return response.readEntity(String.class); + } + + protected int getNumberVars() { + return 3; + } + + protected void testJsonResultSet(Response response) throws IOException { + String content = getEntity(response); + JsonNode node = objectMapper.readTree(content); + assertEquals(getNumberVars(), node.get("head").get("vars").size(), "Got three variables"); + assertEquals(1, node.get("results").get("bindings").size(), "got one result"); + assertEquals(getNumberVars(), node.get("results").get("bindings").get(0).size(), "got 3 bindings"); + } + + protected void testXmlResultSet(Response response) throws IOException { + DocumentBuilder builder = null; + try { + builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + } catch (ParserConfigurationException e) { + throw new IOException("Could not get Xml parser", e); + } + String content = getEntity(response); + Document document = null; + try { + document = builder.parse(new InputSource(new StringReader(content))); + } catch (SAXException e) { + throw new IOException("Cannot parse XML", e); + } + assertEquals(getNumberVars(), ((Element) document.getDocumentElement().getElementsByTagName("head").item(0)).getElementsByTagName("variable").getLength(), "Got three variables"); + assertEquals(1, ((Element) document.getDocumentElement().getElementsByTagName("results").item(0)).getElementsByTagName("result").getLength(), "got one result"); + assertEquals(getNumberVars(), ((Element) ((Element) document.getDocumentElement().getElementsByTagName("results").item(0)).getElementsByTagName("result").item(0)).getElementsByTagName("binding").getLength(), "got 3 bindings"); + } + + /** + * you can always get with a simple sparql + */ + + +} \ No newline at end of file diff --git a/matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/MatchmakingAgentTest.java b/matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/MatchmakingAgentTest.java new file mode 100644 index 00000000..2d47535a --- /dev/null +++ b/matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/MatchmakingAgentTest.java @@ -0,0 +1,94 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming; + +import org.glassfish.jersey.server.ResourceConfig; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Response; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Tests the standard matchmaking agent. this is not a test for conformance! + + * It is rather a test for "exactness" such that the implementation tested can serve + * as a conformance tool. + */ + +public class MatchmakingAgentTest extends ConformingAgentTest { + + @Test + public void testMatchSkillGet() throws IOException { + Response response = target(getPath()).queryParam("asset", "urn:cx:SkillAsset#Test").request().get(); + assertTrue(response.getStatus() >= 200 && response.getStatus() < 300, "Successful get json request"); + testJsonResultSet(response); + } + + @Test + public void testMatchSkillPost() throws IOException { + Response response = target(getPath()).queryParam("asset", "urn:cx:SkillAsset#Test").request(). + post(Entity.entity(ConformingAgent.emptyJson, "application/sparql-results+json")); + assertTrue(response.getStatus() >= 200 && response.getStatus() < 300, "Successful post skill request"); + testJsonResultSet(response); + } + + @Test + public void testMatchSkillPostXml() throws IOException { + Response response = target(getPath()).queryParam("asset", "urn:cx:SkillAsset#Test").request() + .accept("application/sparql-results+xml") + .post(Entity.entity(ConformingAgent.emptyXml, "application/sparql-results+xml")); + assertTrue(response.getStatus() >= 200 && response.getStatus() < 300, "Successful post skill xml request"); + testXmlResultSet(response); + } + + @Test + public void testMatchSkillPostJsonXml() throws IOException { + Response response = target(getPath()).queryParam("asset", "urn:cx:SkillAsset#Test").request() + .accept("application/sparql-results+json") + .post(Entity.entity(ConformingAgent.emptyXml, "application/sparql-results+xml")); + assertTrue(response.getStatus() >= 200 && response.getStatus() < 300, "Successful post skill json request"); + testJsonResultSet(response); + } + + @Test + public void testMatchSkillPostXmlJson() throws IOException { + Response response = target(getPath()).queryParam("asset", "urn:cx:SkillAsset#Test").request() + .accept("application/sparql-results+xml") + .post(Entity.entity(ConformingAgent.emptyJson, "application/sparql-results+json")); + assertTrue(response.getStatus() >= 200 && response.getStatus() < 300, "Successful post skill xml request"); + testXmlResultSet(response); + } + + @Override + protected String getPath() { + return "/match"; + } + + @Override + protected int getNumberVars() { + return 3; + } + + @Override + protected Application configure() { + return new ResourceConfig(MatchmakingAgent.class); + } + +} diff --git a/matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/TransferAgentTest.java b/matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/TransferAgentTest.java new file mode 100644 index 00000000..76224616 --- /dev/null +++ b/matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/TransferAgentTest.java @@ -0,0 +1,48 @@ +// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0. +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// SPDX-License-Identifier: Apache-2.0 +package org.eclipse.tractusx.agents.conforming; + +import org.glassfish.jersey.media.multipart.FormDataMultiPart; +import org.glassfish.jersey.server.ResourceConfig; + +import jakarta.ws.rs.core.Application; +import jakarta.ws.rs.core.Response; + +/** + * Tests the standard transfer agent. this is not a test for conformance! + + * It is rather a test for "exactness" such that the implementation tested can serve + * as a conformance tool. + */ + +public class TransferAgentTest extends MatchmakingAgentTest { + + @Override + protected String getEntity(Response response) { + return response.readEntity(FormDataMultiPart.class).getBodyParts().get(0).getEntityAs(String.class); + } + + @Override + protected String getPath() { + return "/transfer"; + } + + @Override + protected Application configure() { + return new ResourceConfig(TransferAgent.class); + } + +} diff --git a/pom.xml b/pom.xml index 11a444e5..2aa8f0df 100644 --- a/pom.xml +++ b/pom.xml @@ -37,6 +37,7 @@ 11 false + 0.2.1 5.9.0 4.6.1 3.2.4 @@ -49,7 +50,11 @@ 2.15.2 2.13.5 2.3.0 + 3.1.0 + 9.31 + 5.0.2 5.1.0 + 4.0.1 UTF-8 3.1.0 @@ -71,6 +76,7 @@ provisioning remoting conforming + matchmaking From 2464e3ce7baea668671c426d477ef89f5595660e Mon Sep 17 00:00:00 2001 From: Martin Date: Fri, 15 Mar 2024 13:00:14 +0100 Subject: [PATCH 02/15] Files for feature 97 Matchmaking Agent Api --- .gitignore | 8 + .../docs/MatchmakingAgentDiagram.drawio.svg | 2 +- .../docs/MatchmakingAgentTeststellung.drawio | 379 ++++++++++++++++++ matchmaking/pom.xml | 52 +-- matchmaking/resources/dataspace.ttl | 366 +++++++++++++++++ ...lane.properties => matchmaking.properties} | 8 +- .../resources/opentelemetry.properties | 19 + .../agents/conforming/api/AgentApi.java | 147 ------- .../agents/conforming/api/ApiException.java | 27 -- .../conforming/api/ApiOriginFilter.java | 46 --- .../agents/conforming/api/JsonProvider.java | 58 --- .../conforming/api/NotFoundException.java | 27 -- .../conforming/api/Rfc3339DateFormat.java | 35 -- .../agents/conforming/api/SparqlProvider.java | 64 --- .../agents/conforming/api/StringUtil.java | 58 --- .../agents/conforming/api/XmlProvider.java | 85 ---- .../agents/conforming/model/CxWarning.java | 214 ---------- .../conforming/model/JsonResultset.java | 117 ------ .../conforming/model/JsonResultsetHead.java | 99 ----- .../model/JsonResultsetResults.java | 99 ----- .../agents/conforming/model/XmlResultset.java | 117 ------ .../conforming/model/XmlResultsetHead.java | 84 ---- .../model/XmlResultsetHeadVariable.java | 89 ---- .../conforming/model/XmlResultsetResults.java | 84 ---- .../model/XmlResultsetResultsResult.java | 84 ---- .../XmlResultsetResultsResultBinding.java | 139 ------- ...lResultsetResultsResultBindingLiteral.java | 142 ------- matchmaking/src/main/docker/Dockerfile | 6 +- .../agents/{edc => }/AgentConfig.java | 39 +- .../agents/{edc => }/AgentProtocol.java | 2 +- .../agents/{edc => }/AgreementController.java | 4 +- .../{edc => }/AgreementControllerImpl.java | 36 +- .../agents/{edc => }/MonitorWrapper.java | 4 +- .../agents/{edc => }/SkillDistribution.java | 2 +- .../tractusx/agents/{edc => }/SkillStore.java | 7 +- .../tractusx/agents/{edc => }/Tuple.java | 2 +- .../tractusx/agents/{edc => }/TupleSet.java | 2 +- .../agents/annotation/ExtensionPoint.java | 32 ++ .../agents/conforming/BindingAgent.java | 66 --- .../conforming/BindingProfileChecker.java | 38 -- .../agents/conforming/ConformingAgent.java | 295 -------------- .../agents/conforming/MatchmakingAgent.java | 57 --- .../agents/conforming/TransferAgent.java | 109 ----- .../tractusx/agents/edc/AgentExtension.java | 195 --------- .../agents/edc/http/HttpClientFactory.java | 134 ------- .../AgentSourceHttpParamsDecorator.java | 230 ----------- .../AgentSourceRequestParamsSupplier.java | 98 ----- .../{edc => }/http/AgentController.java | 20 +- .../{edc => }/http/AgentHttpAction.java | 4 +- .../{edc => }/http/DelegationResponse.java | 2 +- .../{edc => }/http/DelegationService.java | 2 +- .../{edc => }/http/DelegationServiceImpl.java | 14 +- .../{edc => }/http/GraphController.java | 12 +- .../{edc => }/http/HttpClientAdapter.java | 2 +- .../{edc => }/http/HttpResponseAdapter.java | 2 +- .../http/HttpServletContextAdapter.java | 2 +- .../http/HttpServletRequestAdapter.java | 2 +- .../http/HttpServletResponseAdapter.java | 2 +- .../agents/{edc => }/http/HttpUtils.java | 4 +- .../agents/{edc => }/http/JakartaAdapter.java | 4 +- .../{edc => }/http/JakartaAdapterImpl.java | 4 +- .../JakartaServletInputStreamAdapter.java | 4 +- .../JakartaServletOutputStreamAdapter.java | 4 +- .../http/ServletInputStreamDelegator.java | 2 +- .../http/ServletOutputStreamDelegator.java | 2 +- .../http/transfer/AgentSourceController.java | 28 +- .../http/transfer/AgentSourceServlet.java | 8 +- .../agents/{edc => }/jsonld/JsonLd.java | 15 +- .../agents/{edc => }/jsonld/JsonLdObject.java | 2 +- .../Bootstrap.java | 135 +++---- .../SharedObjectManager.java | 38 +- .../agents/{edc => }/model/Asset.java | 4 +- .../{edc => }/model/ContractAgreement.java | 5 +- .../{edc => }/model/ContractNegotiation.java | 4 +- .../model/ContractNegotiationRequest.java | 2 +- .../model/ContractOfferDescription.java | 2 +- .../agents/{edc => }/model/DcatCatalog.java | 4 +- .../agents/{edc => }/model/DcatDataset.java | 4 +- .../agents/{edc => }/model/IdResponse.java | 4 +- .../agents/{edc => }/model/OdrlPolicy.java | 4 +- .../{edc => }/model/TransferProcess.java | 4 +- .../{edc => }/model/TransferRequest.java | 6 +- .../agents/{edc => }/rdf/ExternalFormat.java | 2 +- .../agents/{edc => }/rdf/RdfStore.java | 8 +- .../{edc => }/service/DataManagement.java | 22 +- .../{edc => }/service/DataManagementImpl.java | 32 +- .../service/DataspaceSynchronizer.java | 20 +- .../{edc => }/service/EdcSkillStore.java | 18 +- .../{edc => }/service/InMemorySkillStore.java | 6 +- .../{edc => }/sparql/CatenaxWarning.java | 2 +- .../sparql/DataspaceServiceExecutor.java | 14 +- .../agents/{edc => }/sparql/GraphRewrite.java | 4 +- .../{edc => }/sparql/GraphRewriteVisitor.java | 2 +- ...ervletRequestToOkHttpRequestConverter.java | 2 +- .../sparql/OptimizeJoinStrategy.java | 2 +- .../agents/{edc => }/sparql/Optimizer.java | 2 +- .../{edc => }/sparql/OptimizerFactory.java | 2 +- .../{edc => }/sparql/QueryExecutor.java | 4 +- .../sparql/QueryExecutorBuilder.java | 4 +- .../{edc => }/sparql/QueryIterFutures.java | 6 +- .../{edc => }/sparql/QueryIterJoin.java | 2 +- .../sparql/SkillVariableDetector.java | 2 +- .../sparql/SparqlQueryProcessor.java | 56 ++- .../sparql/SparqlQuerySerializer.java | 2 +- .../sparql/SparqlQuerySerializerFactory.java | 2 +- .../sparql/StratifiedFormatterElement.java | 2 +- .../{edc => }/sparql/VariableDetector.java | 2 +- .../agents/utils/CallbackAddress.java | 117 ++++++ .../eclipse/tractusx/agents/utils/Config.java | 178 ++++++++ .../tractusx/agents/utils/ConfigFactory.java | 71 ++++ .../tractusx/agents/utils/ConfigImpl.java | 208 ++++++++++ .../tractusx/agents/utils/ConsoleMonitor.java | 99 +++++ .../tractusx/agents/utils/CoreConstants.java | 21 + .../tractusx/agents/utils/Criterion.java | 136 +++++++ .../tractusx/agents/utils/DataAddress.java | 158 ++++++++ .../agents/utils/EndpointDataReference.java | 134 +++++++ .../agents/utils/MatchmakingException.java | 38 ++ .../tractusx/agents/utils/Monitor.java | 67 ++++ .../tractusx/agents/utils/QuerySpec.java | 179 +++++++++ .../eclipse/tractusx/agents/utils/Range.java | 57 +++ .../tractusx/agents/utils/SortOrder.java | 21 + .../tractusx/agents/utils/TypeManager.java | 172 ++++++++ .../DataPlaneTokenValidationApi.java | 2 +- ...hingDataPlaneTokenValidatorController.java | 6 +- .../conforming/ConformingAgentTest.java | 158 -------- .../conforming/MatchmakingAgentTest.java | 94 ----- .../agents/conforming/TransferAgentTest.java | 48 --- pom.xml | 1 - 128 files changed, 2846 insertions(+), 3703 deletions(-) create mode 100644 matchmaking/docs/MatchmakingAgentTeststellung.drawio create mode 100644 matchmaking/resources/dataspace.ttl rename matchmaking/resources/{dataplane.properties => matchmaking.properties} (96%) create mode 100644 matchmaking/resources/opentelemetry.properties delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/AgentApi.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/ApiException.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/ApiOriginFilter.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/JsonProvider.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/NotFoundException.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/Rfc3339DateFormat.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/SparqlProvider.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/StringUtil.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/XmlProvider.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/CxWarning.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultset.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultsetHead.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultsetResults.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultset.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetHead.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetHeadVariable.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResults.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResult.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResultBinding.java delete mode 100644 matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResultBindingLiteral.java rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/AgentConfig.java (91%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/AgentProtocol.java (96%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/AgreementController.java (93%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/AgreementControllerImpl.java (94%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/MonitorWrapper.java (96%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/SkillDistribution.java (97%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/SkillStore.java (91%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/Tuple.java (98%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/TupleSet.java (99%) create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/annotation/ExtensionPoint.java delete mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/BindingAgent.java delete mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/BindingProfileChecker.java delete mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/ConformingAgent.java delete mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/MatchmakingAgent.java delete mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/TransferAgent.java delete mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentExtension.java delete mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientFactory.java delete mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceHttpParamsDecorator.java delete mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceRequestParamsSupplier.java rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/AgentController.java (97%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/AgentHttpAction.java (98%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/DelegationResponse.java (97%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/DelegationService.java (97%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/DelegationServiceImpl.java (97%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/GraphController.java (94%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/HttpClientAdapter.java (99%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/HttpResponseAdapter.java (98%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/HttpServletContextAdapter.java (99%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/HttpServletRequestAdapter.java (99%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/HttpServletResponseAdapter.java (99%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/HttpUtils.java (98%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/JakartaAdapter.java (97%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/JakartaAdapterImpl.java (95%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/JakartaServletInputStreamAdapter.java (96%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/JakartaServletOutputStreamAdapter.java (95%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/ServletInputStreamDelegator.java (98%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/ServletOutputStreamDelegator.java (97%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/transfer/AgentSourceController.java (87%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/http/transfer/AgentSourceServlet.java (96%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/jsonld/JsonLd.java (93%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/jsonld/JsonLdObject.java (96%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{conforming => matchmaking}/Bootstrap.java (80%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{conforming => matchmaking}/SharedObjectManager.java (85%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/model/Asset.java (93%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/model/ContractAgreement.java (91%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/model/ContractNegotiation.java (92%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/model/ContractNegotiationRequest.java (98%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/model/ContractOfferDescription.java (96%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/model/DcatCatalog.java (94%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/model/DcatDataset.java (94%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/model/IdResponse.java (89%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/model/OdrlPolicy.java (89%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/model/TransferProcess.java (90%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/model/TransferRequest.java (96%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/rdf/ExternalFormat.java (97%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/rdf/RdfStore.java (98%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/service/DataManagement.java (89%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/service/DataManagementImpl.java (97%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/service/DataspaceSynchronizer.java (97%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/service/EdcSkillStore.java (89%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/service/InMemorySkillStore.java (92%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/sparql/CatenaxWarning.java (99%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/sparql/DataspaceServiceExecutor.java (98%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/sparql/GraphRewrite.java (98%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/sparql/GraphRewriteVisitor.java (95%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/sparql/HttpServletRequestToOkHttpRequestConverter.java (98%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/sparql/OptimizeJoinStrategy.java (98%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/sparql/Optimizer.java (97%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/sparql/OptimizerFactory.java (95%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/sparql/QueryExecutor.java (99%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/sparql/QueryExecutorBuilder.java (96%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/sparql/QueryIterFutures.java (97%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/sparql/QueryIterJoin.java (98%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/sparql/SkillVariableDetector.java (97%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/sparql/SparqlQueryProcessor.java (92%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/sparql/SparqlQuerySerializer.java (99%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/sparql/SparqlQuerySerializerFactory.java (98%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/sparql/StratifiedFormatterElement.java (98%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/sparql/VariableDetector.java (97%) create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/CallbackAddress.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/Config.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/ConfigFactory.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/ConfigImpl.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/ConsoleMonitor.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/CoreConstants.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/Criterion.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/DataAddress.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/EndpointDataReference.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/MatchmakingException.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/Monitor.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/QuerySpec.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/Range.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/SortOrder.java create mode 100644 matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/TypeManager.java rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/validation/DataPlaneTokenValidationApi.java (94%) rename matchmaking/src/main/java/org/eclipse/tractusx/agents/{edc => }/validation/SwitchingDataPlaneTokenValidatorController.java (96%) delete mode 100644 matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/ConformingAgentTest.java delete mode 100644 matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/MatchmakingAgentTest.java delete mode 100644 matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/TransferAgentTest.java diff --git a/.gitignore b/.gitignore index 197ea71b..8b951521 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,11 @@ logs/ .vscode .env __pycache__ +.classpath +.project +.settings/ +*.bak +*cs-cleanup.xml +*cs-formatter.xml +.checkstyle + diff --git a/matchmaking/docs/MatchmakingAgentDiagram.drawio.svg b/matchmaking/docs/MatchmakingAgentDiagram.drawio.svg index ddfa12dd..8a37cc5d 100644 --- a/matchmaking/docs/MatchmakingAgentDiagram.drawio.svg +++ b/matchmaking/docs/MatchmakingAgentDiagram.drawio.svg @@ -1,4 +1,4 @@ -
EDC Control Plane
EDC Control Plane
Matchmaking Agent
AgentSource
AgentSourceController
SparqlProcessor
GraphController
AgentController
AgreementController
DataManagementImpl
DataspaceSynchronizer
Actor
RdfStore
Matchmaking functionality 
isolating REST interface
EDR Callback
Management API
\ No newline at end of file +
EDC Control Plane
EDC Data Plane
Matchmaking Agent
AgentSource
AgentSourceController
SparqlProcessor
GraphController
AgentController
AgreementController
DataManagementImpl
DataspaceSynchronizer
Actor
RdfStore
Matchmaking functionality 
isolating REST interface
EDR Callback
Management API
\ No newline at end of file diff --git a/matchmaking/docs/MatchmakingAgentTeststellung.drawio b/matchmaking/docs/MatchmakingAgentTeststellung.drawio new file mode 100644 index 00000000..19a355ab --- /dev/null +++ b/matchmaking/docs/MatchmakingAgentTeststellung.drawio @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/matchmaking/pom.xml b/matchmaking/pom.xml index b1bcce99..72176bd3 100644 --- a/matchmaking/pom.xml +++ b/matchmaking/pom.xml @@ -54,10 +54,16 @@ 3.4.0 2.5 2.0.1.Final + 24.1.0 + + org.jetbrains + annotations + ${jetbrain-annotation} + com.google.code.gson gson @@ -213,41 +219,7 @@ --> - - - org.eclipse.edc - boot - 0.4.1 - - - - org.eclipse.edc - web-spi - ${edc.version} - - - - org.eclipse.edc - data-plane-http - ${edc.version} - - - dev.failsafe - failsafe-okhttp - - - - - org.eclipse.edc - http-spi - ${edc.version} - - - - org.eclipse.edc - core-spi - 0.2.1 - + @@ -292,15 +264,7 @@ guava ${guava.version} - - - - org.eclipse.edc - jersey-core - ${edc.version} - test-fixtures - test - + diff --git a/matchmaking/resources/dataspace.ttl b/matchmaking/resources/dataspace.ttl new file mode 100644 index 00000000..4b25fc91 --- /dev/null +++ b/matchmaking/resources/dataspace.ttl @@ -0,0 +1,366 @@ +# Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +################################################################# +# Catena-X Agent Bootstrap in TTL/RDF/OWL FORMAT +# See copyright notice in the top folder +# See authors file in the top folder +# See license file in the top folder +################################################################# + +@prefix : . +@prefix cx: . +@prefix cx-common: . +@prefix cx-diag: . +@prefix cx-telematics: . +@prefix owl: . +@prefix rdf: . +@prefix xml: . +@prefix json: . +@prefix xsd: . +@prefix rdfs: . +@prefix bpnl: . +@prefix bpns: . +@prefix skos: . +@prefix dc: . + +@base . + +bpnl:BPNL00000003AYRE cx:hasBusinessPartnerNumber "BPNL00000003COJN"^^xsd:string; + cx:hasBusinessPartnerNumber "BPNL00000003AYRE"^^xsd:string; + cx:hasBusinessPartnerNumber "BPNL00000003AVTH"^^xsd:string; + cx:hasBusinessPartnerNumber "BPNL00000003AZQP"^^xsd:string; + cx:isIssuerOfVehicleIdentificationNumber "WBAAL31029PZ00001"^^xsd:string; + cx:isIssuerOfVehicleIdentificationNumber "WBAAL31029PZ00002"^^xsd:string; + cx:isIssuerOfVehicleIdentificationNumber "WBAAL31029PZ00003"^^xsd:string; + cx:hasConnector ; + cx-common:hasConnector . + + +bpnl:BPNL00000003B2OM cx:hasBusinessPartnerNumber "BPNL00000003CPIY"^^xsd:string; + cx:hasBusinessPartnerNumber "BPNL00000003B2OM"^^xsd:string; + cx:hasConnector ; + cx-common:hasConnector . + +bpnl:BPNL00000003CQI9 cx:hasBusinessPartnerNumber "BPNL00000003CQI9"^^xsd:string; + cx:hasBusinessPartnerNumber "BPNL00000007OR16"^^xsd:string; + cx:hasConnector ; + cx-common:hasConnector . + +bpnl:BPNL00000003AXS3 cx-common:hasSite bpns:BPNS00000003AXS3. +bpnl:BPNL00000003B0Q0 cx-common:hasSite bpns:BPNS00000003B0Q0. +bpnl:BPNL00000003B3NX cx-common:hasSite bpns:BPNS00000003B3NX. +bpnl:BPNL00000003AYRE cx-common:hasSite bpns:BPNS000004711DMY. +bpnl:BPNL00000003AZQP cx-common:hasSite bpns:BPNS000001111DMY. +bpnl:BPNL00000003B5MJ cx-common:hasSite bpns:BPNS00000003B5MJ. +bpnl:BPNL00000003AVTH cx-common:hasSite bpns:BPNS000000815DMY. +bpnl:BPNL00000003B2OM cx-common:hasSite bpns:BPNS00000003B2OM. +bpnl:BPNL00000003CSGV cx-common:hasSite bpns:BPNS000000000DQB. +bpnl:BPNL00000007OR16 cx-common:hasSite bpns:BPNS0000000002XY. +bpnl:BPNL00000003B2OM cx-common:hasSite bpns:BPNS0000000006V6. + +bpnl:BPNL00000003B0Q0 cx-common:hasConnector . +bpnl:BPNL00000003CSGV cx-common:hasConnector . +bpnl:BPNL00000003AXS3 cx-common:hasConnector . +bpnl:BPNL00000003AYRE cx-common:hasConnector . +bpnl:BPNL00000003B2OM cx-common:hasConnector . +bpnl:BPNL00000007OR16 cx-common:hasConnector . +bpnl:BPNL00000003AVTH cx-common:hasConnector . +bpnl:BPNL00000003AZQP cx-common:hasConnector . + +bpns:BPNS00000003AXS3 cx-common:hasGeoInformation . +bpns:BPNS00000003B0Q0 cx-common:hasGeoInformation . +bpns:BPNS00000003B3NX cx-common:hasGeoInformation . +bpns:BPNS000004711DMY cx-common:hasGeoInformation . +bpns:BPNS000001111DMY cx-common:hasGeoInformation . +bpns:BPNS00000003B5MJ cx-common:hasGeoInformation . +bpns:BPNS000000815DMY cx-common:hasGeoInformation . +bpns:BPNS00000003B2OM cx-common:hasGeoInformation . +bpns:BPNS000000000DQB cx-common:hasGeoInformation . +bpns:BPNS0000000002XY cx-common:hasGeoInformation . +bpns:BPNS0000000006V6 cx-common:hasGeoInformation . + + cx-common:hasLatitude "35.62306268137165"^^xsd:double; + cx-common:hasLongitude "139.7498516425976"^^xsd:double. + cx-common:hasLatitude "12.992287272083951"^^xsd:double; + cx-common:hasLongitude "74.84030406238573"^^xsd:double. + cx-common:hasLatitude "34.90316856022901"^^xsd:double; + cx-common:hasLongitude "-82.10778890159467"^^xsd:double. + cx-common:hasLatitude "48.648900476926926"^^xsd:double; + cx-common:hasLongitude "12.465527980565177"^^xsd:double. + cx-common:hasLatitude "-25.632334804928544"^^xsd:double; + cx-common:hasLongitude "28.084500971267506"^^xsd:double. + cx-common:hasLatitude "41.90277"^^xsd:double; + cx-common:hasLongitude "-2.70559"^^xsd:double. + + cx-common:hasLatitude "-22.4775436688588"^^xsd:double; + cx-common:hasLongitude "-47.024968046462206"^^xsd:double. + cx-common:hasLatitude "31.889668725991893"^^xsd:double; + cx-common:hasLongitude "119.9591474486991"^^xsd:double. + cx-common:hasLatitude "14.0590"^^xsd:double; + cx-common:hasLongitude "80.13451"^^xsd:double. + cx-common:hasLatitude "7.88710"^^xsd:double; + cx-common:hasLongitude "89.3895"^^xsd:double. + cx-common:hasLatitude "7.79778"^^xsd:double; + cx-common:hasLongitude "98.34148"^^xsd:double. + + cx:isAnonymousVehicle "WBAAL31029PZ00001"^^xsd:string; + cx:hasRegistration "{ \"Value\": 20220624, \"Unit\": \"yyyymmdd\" }"^^json:Object; + cx-telematics:latestMileageReceived "{ \"Value\": 6017, \"Unit\": \"km\" }"^^json:Object; + cx-telematics:operatingTime "45667765"^^xsd:long; + cx-telematics:latestMileage "82563.02"^^xsd:double; + cx-telematics:latestDetailReceived . + + cx-diag:hasPartType "engine control module"^^xsd:string; + cx-diag:whenRecorded "2022-10-12T08:17:18.734Z"^^xsd:dateTime; + cx-diag:hasAdaptionValues "[ 0.543534, 0.543535, 0.543536, 0.543537 ]"^^json:Object; + cx-diag:hasLoadSpectrum "{ \"Temp_Oil-class\": [1, 3, 4, 5, 7, 8, 12, 13, 17, 18, 20, 22, 23, 25, 28, 29, 31, 32, 33, 34, 36, 37, 38, 41, 42, 44, 45, 47, 48, 49, 50, 51], \"Counts\": [7.234E+01, 2.345E+02, 6.654E+02, 5.983E+01, 4.321E+02, 3.876E+02, 5.567E+01, 3.4456E+02, 4.556645E+02, 5.678E+01, 4.321E+02, 6.098E+02, 7.432E+02, 8.873E+02, 4.738E+01, 6.927E+01, 1.234E+02, 2.345E+02, 3.654E+02, 2.983E+01, 4.321E+01, 3.876E+02, 5.567E+02, 3.4456E+02, 4.556645E+02, 5.678E+01, 4.321E+01, 6.098E+01, 3.432E+02, 1.873E+02, 4.738E+02, 6.927E+02] }"^^json:Object. + + cx:isAnonymousVehicle "WBAAL31029PZ00002"^^xsd:string; + cx:hasRegistration "{ \"Value\": 20171206, \"Unit\": \"yyyymmdd\" }"^^json:Object; + cx-telematics:latestMileage "82563.02"^^xsd:double; + cx-telematics:operatingTime "45667765"^^xsd:long; + cx-telematics:latestMileageReceived "{ \"Value\": 82563, \"Unit\": \"km\" }"^^json:Object; + cx-telematics:latestDetailReceived . + + cx-diag:hasPartType "clutch"^^xsd:string; + cx-diag:whenRecorded "2022-10-12T08:17:18.734Z"^^xsd:dateTime; + cx-diag:hasAdaptionValues "[ 0.543534, 0.543535, 0.543536, 0.543537 ]"^^json:Object; + cx-diag:hasLoadSpectrum "{ \"Temp_Oil-class\": [2, 3, 4, 6, 7, 8, 12, 18, 20, 22, 23, 25, 28, 29, 31, 32, 33, 34, 36, 37, 38, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51], \"Counts\": [1.234E+01, 2.345E+02, 1.654E+02, 4.321E+01, 6.098E+01, 3.432E+02, 1.873E+02, 4.738E+01, 6.927E+01, 1.234E+01, 2.345E+02, 1.654E+02, 2.983E+01, 2.983E+01, 4.321E+01, 3.876E+02, 5.567E+01, 3.4456E+02, 4.556645E+02, 5.678E+01, 4.321E+01, 3.876E+02, 5.567E+01, 3.4456E+02, 4.556645E+02, 5.678E+01, 4.321E+01, 6.098E+01, 3.432E+02, 1.873E+02, 4.738E+01, 6.927E+01] }"^^json:Object. + + cx:isAnonymousVehicle "WBAAL31029PZ00003"^^xsd:string; + cx:hasRegistration "{ \"Value\": 20130302, \"Unit\": \"yyyymmdd\" }"^^json:Object; + cx-telematics:latestMileage "82563.02"^^xsd:double; + cx-telematics:operatingTime "45667765"^^xsd:long; + cx-telematics:latestMileageReceived "{ \"Value\": 247332, \"Unit\": \"km\" }"^^json:Object; + cx-telematics:latestDetailReceived . + + cx-diag:hasPartType "wiring harness"^^xsd:string; + cx-diag:whenRecorded "2022-10-12T08:17:18.734Z"^^xsd:dateTime; + cx-diag:hasAdaptionValues "[ 0.543534, 0.543535, 0.543536, 0.543537 ]"^^json:Object; + cx-diag:hasLoadSpectrum "{ \"Temp_Oil-class\": [1, 3, 4, 5, 7, 8, 12, 13, 17, 18, 20, 22, 23, 25, 28, 29, 31, 32, 33, 34, 36, 37, 38, 41, 42, 44, 45, 47, 48, 49, 50, 51], \"Counts\": [1.234E+01, 2.345E+02, 1.654E+02, 2.983E+02, 4.321E+01, 3.876E+02, 5.567E+01, 3.4456E+02, 4.556645E+02, 5.678E+01, 4.321E+02, 6.098E+02, 3.432E+02, 1.873E+02, 4.738E+01, 6.927E+01, 8.234E+01, 2.345E+02, 4.654E+02, 2.983E+01, 4.321E+01, 3.876E+02, 9.567E+01, 3.4456E+02, 4.556645E+02, 5.678E+01, 4.321E+02, 6.098E+01, 3.432E+02, 1.873E+02, 4.738E+01, 5.927E+01] }"^^json:Object. + + cx:isComponentOf ; + cx:hasPartType "engine control module"^^xsd:string; + cx:hasSupplier bpnl:BPNL00000003B2OM; + cx:hasName "Gear Box"^^xsd:string. + + cx:isComponentOf ; + cx:hasPartType "clutch"^^xsd:string; + cx:hasSupplier bpnl:BPNL00000003B2OM; + cx:hasName "Gear Oil"^^xsd:string. + + cx:isComponentOf ; + cx:hasPartType "wiring harness"^^xsd:string; + cx:hasSupplier bpnl:BPNL00000003B2OM; + cx:hasName "Wiring Harness"^^xsd:string. + + cx-telematics:hasFile "{ \"Type\": \"ZF_load_collective\", \"Version\": \"1.7\" }"^^json:Object; + cx-telematics:hasAdaptionVersion "VER_AV_001"^^xsd:string; + cx-telematics:hasHeader "{ \"CountingMethod\": \"ZF_TimeAtLevel\", \"CountingUnit\": \"s\", \"Channels\": [ { \"Name\": \"Temp_Oil\", \"Type\": \"Load\", \"Unit\": \"degC\", \"LowerLimit\": -40, \"UpperLimit\": 220, \"NumberOfBins\": 52 } ] }"^^json:Object. + + cx-telematics:hasFile "{ \"Type\": \"ZF_load_collective\", \"Version\": \"1.7\" }"^^json:Object; + cx-telematics:hasAdaptionVersion "VER_AV_001"^^xsd:string; + cx-telematics:hasHeader "{ \"CountingMethod\": \"ZF_TimeAtLevel\", \"CountingUnit\": \"s\", \"Channels\": [ { \"Name\": \"Temp_Oil\", \"Type\": \"Load\", \"Unit\": \"degC\", \"LowerLimit\": -40, \"UpperLimit\": 220, \"NumberOfBins\": 52 } ] }"^^json:Object. + + cx-telematics:hasFile "{ \"Type\": \"ZF_load_collective\", \"Version\": \"1.7\" }"^^json:Object; + cx-telematics:hasAdaptionVersion "VER_AV_001"^^xsd:string; + cx-telematics:hasHeader "{ \"CountingMethod\": \"ZF_TimeAtLevel\", \"CountingUnit\": \"s\", \"Channels\": [ { \"Name\": \"Temp_Oil\", \"Type\": \"Load\", \"Unit\": \"degC\", \"LowerLimit\": -40, \"UpperLimit\": 220, \"NumberOfBins\": 52 } ] }"^^json:Object. + +cx-common:EngineeringMaterial a owl:Class ; + rdfs:isDefinedBy ; + rdfs:seeAlso , + ; + rdfs:subClassOf [ a owl:Restriction ; + owl:onProperty cx-common:isPartOf ; + owl:someValuesFrom cx-common:Product ], + [ a owl:Restriction ; + owl:onProperty cx-common:contains ; + owl:someValuesFrom cx-common:RawMaterial ], + [ a owl:Restriction ; + owl:onProperty cx-common:engineeringMaterialNumber ; + owl:someValuesFrom xsd:string ], + [ a owl:Restriction ; + owl:onProperty cx-common:participatesIn ; + owl:someValuesFrom cx-common:Process ], + [ a owl:Restriction ; + owl:onProperty cx-common:engineeringMaterialName ; + owl:someValuesFrom xsd:string ], + [ a owl:Restriction ; + owl:onProperty cx-common:isMadeOf ; + owl:someValuesFrom cx-common:RawMaterial ], + cx-common:IntermediateProduct ; + skos:altLabel "engineered material"@en, + "engineering material"@en, + "technische Werkstoff"@en ; + skos:definition "A material that is used in the production of a product and becomes part of the product."@en ; + skos:example "aluminium alloy"@en ; + skos:prefLabel "Werkstoff"@de, + "Engineering Material"@en . + +cx-common:SemiconductorMaterial a owl:Class ; + rdfs:isDefinedBy ; + rdfs:seeAlso ; + rdfs:subClassOf cx-common:EngineeringMaterial ; + skos:prefLabel "Halbleiter Material"@de, + "Semiconductor Material"@en . + +cx-common:CeramicMaterial a owl:Class ; + rdfs:isDefinedBy ; + rdfs:subClassOf cx-common:EngineeringMaterial ; + skos:altLabel "anorganisch-nichtmetallischer Werkstoff"@de ; + skos:prefLabel "Keramisches Material"@de, + "Ceramic Material"@en . + +cx-common:CompositeMaterial a owl:Class ; + rdfs:isDefinedBy ; + rdfs:seeAlso ; + rdfs:subClassOf cx-common:EngineeringMaterial ; + skos:definition "mixture of materials"@en ; + skos:prefLabel "Verbundwerkstoff"@de, + "Composite Material"@en . + +cx-common:PolymerMaterial a owl:Class ; + rdfs:isDefinedBy ; + rdfs:seeAlso , + ; + rdfs:subClassOf cx-common:EngineeringMaterial ; + skos:prefLabel "Kunststoff"@de, + "Polymer Material"@en . + +cx-common:MetalMaterial a owl:Class ; + rdfs:isDefinedBy ; + rdfs:seeAlso ; + rdfs:subClassOf cx-common:EngineeringMaterial ; + skos:prefLabel "Metallmaterial"@de, + "Metal Material"@en . + +cx-common:HeavyMetal a owl:Class ; + rdfs:isDefinedBy ; + rdfs:seeAlso ; + rdfs:subClassOf cx-common:MetalMaterial ; + skos:definition "density above 5 g/cm³"@en ; + skos:prefLabel "Schwermetall"@de, + "Heavy Metal"@en . + +cx-common:LightMetal a owl:Class ; + rdfs:isDefinedBy ; + rdfs:seeAlso ; + rdfs:subClassOf cx-common:MetalMaterial ; + skos:definition "density below 5 g/cm³"@en ; + skos:prefLabel "Leichtmetall"@de, + "Light Metal"@en . + +cx-common:NativeMetal a owl:Class ; + rdfs:isDefinedBy ; + rdfs:seeAlso ; + rdfs:subClassOf cx-common:MetalMaterial ; + skos:prefLabel "Reinmetall"@de, + "Native Metal"@en . + +cx-common:Alloy a owl:Class ; + rdfs:isDefinedBy ; + rdfs:seeAlso ; + rdfs:subClassOf cx-common:MetalMaterial ; + skos:prefLabel "Legierung"@de, + "Alloy"@en . + +cx-common:CathodeMaterial a owl:Class ; + rdfs:isDefinedBy ; + rdfs:seeAlso ; + rdfs:subClassOf cx-common:Alloy ; + skos:prefLabel "Kathodenmaterial"@de, + "Cathode Material"@en. + +cx-common:MetalMaterial_Aluminium a cx-common:MetalMaterial ; + skos:altLabel "DIN EN 573" ; + skos:note "body"@en ; + skos:prefLabel "Aluminium"@en ; + skos:prefLabel "Aluminium"@de. + +cx-common:MetalMaterial_Copper a cx-common:MetalMaterial ; + skos:altLabel "DIN EN 1173", + "DIN EN 1412"@de ; + skos:note "electric"@en ; + skos:prefLabel "Copper"@en ; + skos:prefLabel "Kupfer"@de. + +cx-common:MetalMaterial_Steel a cx-common:MetalMaterial ; + rdfs:seeAlso ; + skos:altLabel "DIN EN 10027" ; + skos:note "body"@en ; + skos:prefLabel "Steel"@en ; + skos:prefLabel "Stahl"@de. + +cx-common:CompositeMaterial_Carbon a cx-common:CompositeMaterial ; + skos:altLabel "DIN EN 14598" ; + skos:note "body"@en ; + skos:prefLabel "Carbon"@en ; + skos:prefLabel "Karbon"@de. + +cx-common:OrganicMaterial a owl:Class ; + rdfs:isDefinedBy ; + rdfs:seeAlso ; + rdfs:subClassOf cx-common:EngineeringMaterial ; + skos:altLabel "Organischer Werkstoff"@de ; + skos:example "fiber"@en, + "paper"@en, + "wood"@en ; + skos:prefLabel "Organisches Material"@de, + "Organic Material"@en . + +cx-common:OrganicMaterial_ArtificialLeather a cx-common:OrganicMaterial ; + rdfs:seeAlso ; + skos:note "interior"@en ; + skos:prefLabel "Kunstleder"@de, + "Artificial Leather"@en . + +cx-common:OrganicMaterial_Leather a cx-common:OrganicMaterial ; + rdfs:seeAlso ; + skos:note "interior"@en ; + skos:prefLabel "Leder"@de, + "Leather"@en . + +cx-common:OrganicMaterial_Rubber a cx-common:OrganicMaterial ; + skos:altLabel "DIN EN ISO 1629" ; + skos:note "interior"@en ; + skos:prefLabel "Natural Rubber"@en; + skos:prefLabel "Naturgummi"@de. + +cx-common:PolymerMaterial_Plastic a cx-common:PolymerMaterial ; + skos:altLabel "DIN EN ISO 1043" ; + skos:note "interior"@en ; + skos:prefLabel "Plastic"@en ; + skos:prefLabel "Plastik"@de. + +cx-common:PolymerMaterial_Rubber a cx-common:PolymerMaterial ; + skos:altLabel "DIN EN ISO 1629"@de ; + skos:note "interior"@en ; + skos:note "tires"@en ; + skos:prefLabel "Synthetic Rubber"@en; + skos:prefLabel "Synthetisches Gummi"@de. + +cx-common:CathodeMaterial_LithiumNickelManganeseCobaltOxides a cx-common:CathodeMaterial ; + rdfs:seeAlso ; + skos:note "battery"@en ; + skos:prefLabel "Lithium Nickel Manganese Cobalt Oxides"@en; + skos:prefLabel "Lithium-Nickel-Mangan-Kobalt Oxide"@de. + +cx-common:CathodeMaterial_LeadDioxide a cx-common:CathodeMaterial ; + rdfs:seeAlso ; + skos:note "battery"@en ; + skos:prefLabel "Lead Dioxide"@en; + skos:prefLabel "Bleidioxid"@de. diff --git a/matchmaking/resources/dataplane.properties b/matchmaking/resources/matchmaking.properties similarity index 96% rename from matchmaking/resources/dataplane.properties rename to matchmaking/resources/matchmaking.properties index d51362b4..f5ea917a 100644 --- a/matchmaking/resources/dataplane.properties +++ b/matchmaking/resources/matchmaking.properties @@ -29,10 +29,13 @@ edc.participant.id=BPNL0000000DUMMY web.http.default.port=8082 web.http.default.path=/api -web.http.public.port=8185 -web.http.public.path=/api/v1/public web.http.callback.port=8187 web.http.callback.path=/callback +web.http.internal.port=8080 +web.http.internal.path=/agentsource + +web.http.public.port=8185 +web.http.public.path=/api/v1/public web.http.control.port=9999 web.http.control.path=/api/dataplane/control edc.web.rest.cors.enabled=true @@ -80,3 +83,4 @@ cx.agent.asset.file=dataspace.ttl cx.agent.dataspace.synchronization=60000 cx.agent.dataspace.remotes=http://oem-control-plane:8282,http://consumer-control-plane:8282 cx.agent.matchmaking.internal.api=8080 +cx.agent.matchmaking.external.api=8280 diff --git a/matchmaking/resources/opentelemetry.properties b/matchmaking/resources/opentelemetry.properties new file mode 100644 index 00000000..2a30d6fb --- /dev/null +++ b/matchmaking/resources/opentelemetry.properties @@ -0,0 +1,19 @@ +# Copyright (c) 2022,2024 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +otel.javaagent.enabled=false +otel.javaagent.debug=false \ No newline at end of file diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/AgentApi.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/AgentApi.java deleted file mode 100644 index 8d6e70e0..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/AgentApi.java +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.api; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.enums.ParameterIn; -import io.swagger.v3.oas.annotations.headers.Header; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.core.Application; -import jakarta.ws.rs.core.Context; -import jakarta.ws.rs.core.HttpHeaders; -import jakarta.ws.rs.core.Request; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.SecurityContext; -import jakarta.ws.rs.core.UriInfo; -import org.eclipse.tractusx.agents.conforming.model.CxWarning; -import org.eclipse.tractusx.agents.conforming.model.JsonResultset; -import org.eclipse.tractusx.agents.conforming.model.XmlResultset; - -import java.util.List; - - -@Path("/") -@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") -public abstract class AgentApi { - - @Context - public SecurityContext securityContext; - @Context - public Application application; - @Context - public HttpHeaders headers; - @Context - public Request request; - @Context - public Response response; - @Context - public UriInfo uri; - - @GET - @Produces({ "application/sparql-results+json", - "application/sparql-results+xml" - }) - @Operation(summary = "Invoke a Skill or Query (Simple)", description = "", tags = { "agent" }) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "The SparQL query has been processed successfully.", - content = { - @Content(mediaType = "application/sparql-results+json", schema = @Schema(implementation = JsonResultset.class)), - @Content(mediaType = "application/sparql-results+xml", schema = @Schema(implementation = XmlResultset.class)) - }), - @ApiResponse(responseCode = "203", description = "The SparQL query has been processed successfully but warnings did occur.", - headers = { @Header(name = "cx_warnings", schema = @Schema(type = "array", implementation = CxWarning.class)) }, - content = { - @Content(mediaType = "application/sparql-results+json", schema = @Schema(implementation = JsonResultset.class)), - @Content(mediaType = "application/sparql-results+xml", schema = @Schema(implementation = XmlResultset.class)) - }), - @ApiResponse(responseCode = "400", description = "Bad request or malformed SPARQL"), - @ApiResponse(responseCode = "500", description = "Fatal error") - }) - public abstract Response getAgent( - @Parameter(in = ParameterIn.QUERY, description = "The Target Asset of the Query (targets the complete dataspace if empty)") - @QueryParam("asset") String asset, - @Parameter(in = ParameterIn.QUERY, description = "The Query language (fixed: SPARQL)") - @QueryParam("queryLn") String queryLn, - @Parameter(in = ParameterIn.QUERY, description = "The SPARQL query") - @QueryParam("query") String query, - @Parameter(in = ParameterIn.QUERY, description = "A sample bound parameter 'vin' which opens a new input tuple") - @QueryParam("(vin") String vin, - @Parameter(in = ParameterIn.QUERY, description = "A sample multi-bound parameter 'troubleCode' which closes the tuple") - @QueryParam("troubleCode") List troubleCode) - throws org.eclipse.tractusx.agents.conforming.api.NotFoundException; - - @POST - @Consumes({ "application/sparql-results+json", "application/sparql-results+xml", "application/sparql-query" }) - @Produces({ "application/sparql-results+json", "application/sparql-results+xml" }) - @Operation(summary = "Invoke a Skill or Query (Flexible)", description = "", tags = { "agent" }) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "The SparQL query has been processed successfully.", - content = { - @Content(mediaType = "application/sparql-results+json", schema = @Schema(implementation = JsonResultset.class)), - @Content(mediaType = "application/sparql-results+xml", schema = @Schema(implementation = XmlResultset.class)) - }), - @ApiResponse(responseCode = "203", description = "The SparQL query has been processed successfully but warnings did occur.", - headers = { @Header(name = "cx_warnings", schema = @Schema(type = "array", implementation = CxWarning.class)) }, - content = { - @Content(mediaType = "application/sparql-results+json", schema = @Schema(implementation = JsonResultset.class)), - @Content(mediaType = "application/sparql-results+xml", schema = @Schema(implementation = XmlResultset.class)) - }), - @ApiResponse(responseCode = "400", description = "Bad request or malformed SPARQL"), - @ApiResponse(responseCode = "500", description = "Fatal error") - }) - public abstract Response postAgent( - @Parameter(in = ParameterIn.DEFAULT, description = "The body either contains the query or a binding data set when a skill is invoked", required = true) - Object body, - @Parameter(in = ParameterIn.QUERY, description = "The Target Asset of the Query (targets the complete dataspace if empty)") - @QueryParam("asset") String asset, - @Parameter(in = ParameterIn.QUERY, description = "The Query language (fixed: SPARQL)") - @QueryParam("queryLn") String queryLn, - @Parameter(in = ParameterIn.QUERY, description = "The SPARQL query") - @QueryParam("query") String query, - @Parameter(in = ParameterIn.QUERY, description = "A sample bound parameter 'vin' which opens a new input tuple") - @QueryParam("(vin") String vin, - @Parameter(in = ParameterIn.QUERY, description = "A sample multi-bound parameter 'troubleCode' which closes the tuple") - @QueryParam("troubleCode") List troubleCode) - throws org.eclipse.tractusx.agents.conforming.api.NotFoundException; - - @POST - @Path("/skill") - @Consumes({ "application/sparql-query" }) - @Operation(summary = "Register a Skill", description = "", tags = { "agent" }) - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Skill has been registered"), - @ApiResponse(responseCode = "204", description = "Skill has been updated"), - @ApiResponse(responseCode = "400", description = "Bad request or malformed SPARQL"), - @ApiResponse(responseCode = "500", description = "Fatal error") }) - public abstract Response postSkill( - @Parameter(in = ParameterIn.DEFAULT, description = "The body either contains the parameterized query", required = true) - String body, - @Parameter(in = ParameterIn.QUERY, description = "The Target Asset of the Query (targets the complete dataspace if empty)", required = true) - @QueryParam("asset") String asset) - throws org.eclipse.tractusx.agents.conforming.api.NotFoundException; - -} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/ApiException.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/ApiException.java deleted file mode 100644 index 03887970..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/ApiException.java +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.api; - -@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") -public class ApiException extends Exception { - private int code; - - public ApiException(int code, String msg) { - super(msg); - this.code = code; - } -} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/ApiOriginFilter.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/ApiOriginFilter.java deleted file mode 100644 index a012627f..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/ApiOriginFilter.java +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.api; - -import java.io.IOException; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletResponse; - -@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") -public class ApiOriginFilter implements javax.servlet.Filter { - @Override - public void init(FilterConfig filterConfig) throws ServletException { - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, - FilterChain chain) throws IOException, ServletException { - HttpServletResponse res = (HttpServletResponse) response; - res.addHeader("Access-Control-Allow-Origin", "*"); - res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT"); - res.addHeader("Access-Control-Allow-Headers", "Content-Type"); - chain.doFilter(request, response); - } - - @Override - public void destroy() { - } -} \ No newline at end of file diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/JsonProvider.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/JsonProvider.java deleted file mode 100644 index 2540c5a3..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/JsonProvider.java +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.api; - -import com.fasterxml.jackson.databind.ObjectMapper; -import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.MultivaluedMap; -import jakarta.ws.rs.ext.MessageBodyReader; -import jakarta.ws.rs.ext.MessageBodyWriter; -import jakarta.ws.rs.ext.Provider; -import org.eclipse.tractusx.agents.conforming.ConformingAgent; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; - -@Provider -public class JsonProvider implements MessageBodyReader, MessageBodyWriter { - - ObjectMapper objectMapper = new ObjectMapper(); - - @Override - public boolean isReadable(Class aclass, Type type, Annotation[] annotations, MediaType mediaType) { - return mediaType.isCompatible(ConformingAgent.srj); - } - - @Override - public Object readFrom(Class aclass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap multivaluedMap, InputStream inputStream) throws IOException, WebApplicationException { - return objectMapper.readTree(inputStream); - } - - @Override - public boolean isWriteable(Class aclass, Type type, Annotation[] annotations, MediaType mediaType) { - return mediaType.isCompatible(ConformingAgent.srj); - } - - @Override - public void writeTo(Object o, Class aclass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap multivaluedMap, OutputStream outputStream) throws IOException, WebApplicationException { - objectMapper.writeValue(outputStream, o); - } -} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/NotFoundException.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/NotFoundException.java deleted file mode 100644 index 84b02191..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/NotFoundException.java +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.api; - -@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") -public class NotFoundException extends ApiException { - private int code; - - public NotFoundException(int code, String msg) { - super(code, msg); - this.code = code; - } -} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/Rfc3339DateFormat.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/Rfc3339DateFormat.java deleted file mode 100644 index 8ee61c98..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/Rfc3339DateFormat.java +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.api; - -import com.fasterxml.jackson.databind.util.ISO8601DateFormat; -import com.fasterxml.jackson.databind.util.ISO8601Utils; - -import java.text.FieldPosition; -import java.util.Date; - -public class Rfc3339DateFormat extends ISO8601DateFormat { - - // Same as ISO8601DateFormat but serializing milliseconds. - @Override - public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { - String value = ISO8601Utils.format(date, true); - toAppendTo.append(value); - return toAppendTo; - } - -} \ No newline at end of file diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/SparqlProvider.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/SparqlProvider.java deleted file mode 100644 index 85397577..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/SparqlProvider.java +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.api; - -import com.fasterxml.jackson.databind.ObjectMapper; -import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.MultivaluedMap; -import jakarta.ws.rs.ext.MessageBodyReader; -import jakarta.ws.rs.ext.MessageBodyWriter; -import jakarta.ws.rs.ext.Provider; -import org.eclipse.tractusx.agents.conforming.ConformingAgent; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; -import java.util.stream.Collectors; - -@Provider -public class SparqlProvider implements MessageBodyReader, MessageBodyWriter { - - ObjectMapper objectMapper = new ObjectMapper(); - - @Override - public boolean isReadable(Class aclass, Type type, Annotation[] annotations, MediaType mediaType) { - return mediaType.isCompatible(ConformingAgent.sq); - } - - @Override - public Object readFrom(Class aclass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap multivaluedMap, InputStream inputStream) throws IOException, WebApplicationException { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { - return reader.lines().collect(Collectors.joining("\n")); - } - } - - @Override - public boolean isWriteable(Class aclass, Type type, Annotation[] annotations, MediaType mediaType) { - return mediaType.isCompatible(ConformingAgent.sq); - } - - @Override - public void writeTo(Object o, Class aclass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap multivaluedMap, OutputStream outputStream) throws IOException, WebApplicationException { - new OutputStreamWriter(outputStream).append(String.valueOf(o)); - } -} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/StringUtil.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/StringUtil.java deleted file mode 100644 index 691a2e47..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/StringUtil.java +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.api; - -@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") -public class StringUtil { - /** - * Check if the given array contains the given value (with case-insensitive comparison). - * - * @param array The array - * @param value The value to search - * @return true if the array contains the value - */ - public static boolean containsIgnoreCase(String[] array, String value) { - for (String str : array) { - if (value == null && str == null) return true; - if (value != null && value.equalsIgnoreCase(str)) return true; - } - return false; - } - - /** - * Join an array of strings with the given separator. - *

- * Note: This might be replaced by utility method from commons-lang or guava someday - * if one of those libraries is added as dependency. - *

- * - * @param array The array of strings - * @param separator The separator - * @return the resulting string - */ - public static String join(String[] array, String separator) { - int len = array.length; - if (len == 0) return ""; - - StringBuilder out = new StringBuilder(); - out.append(array[0]); - for (int i = 1; i < len; i++) { - out.append(separator).append(array[i]); - } - return out.toString(); - } -} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/XmlProvider.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/XmlProvider.java deleted file mode 100644 index 9c79b801..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/api/XmlProvider.java +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.api; - -import jakarta.ws.rs.WebApplicationException; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.MultivaluedMap; -import jakarta.ws.rs.ext.MessageBodyReader; -import jakarta.ws.rs.ext.MessageBodyWriter; -import jakarta.ws.rs.ext.Provider; -import org.eclipse.tractusx.agents.conforming.ConformingAgent; -import org.w3c.dom.Document; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - -/** - * This class provides a MessageBodyReader and MessageBodyWriter for XML content type. - * It prevents access to external DTDs and stylesheets while reading and writing XML. - */ -@Provider -public class XmlProvider implements MessageBodyReader, MessageBodyWriter { - - @Override - public boolean isReadable(Class aclass, Type type, Annotation[] annotations, MediaType mediaType) { - return mediaType.isCompatible(ConformingAgent.srx); - } - - @Override - public Object readFrom(Class aclass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap multivaluedMap, InputStream inputStream) throws IOException, WebApplicationException { - try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - DocumentBuilder parser = factory.newDocumentBuilder(); - return parser.parse(new InputSource(inputStream)); - } catch (ParserConfigurationException | SAXException e) { - throw new IOException("Could not xml parse message body", e); - } - } - - @Override - public boolean isWriteable(Class aclass, Type type, Annotation[] annotations, MediaType mediaType) { - return mediaType.isCompatible(ConformingAgent.srx); - } - - @Override - public void writeTo(Object o, Class aclass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap multivaluedMap, OutputStream outputStream) throws IOException, WebApplicationException { - try { - TransformerFactory factory = TransformerFactory.newInstance(); - factory.setAttribute("http://javax.xml.XMLConstants/property/accessExternalDTD", ""); - factory.setAttribute("http://javax.xml.XMLConstants/property/accessExternalStylesheet", ""); - Transformer transformer = factory.newTransformer(); - transformer.transform(new DOMSource((Document) o), new StreamResult(outputStream)); - } catch (TransformerException e) { - throw new IOException("Cannot render xml body", e); - } - } -} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/CxWarning.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/CxWarning.java deleted file mode 100644 index c36d1612..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/CxWarning.java +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.media.Schema; - -import java.util.Objects; - -/** - * CxWarning - */ -@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") -public class CxWarning { - @JsonProperty("source-tenant") - private String sourceTenant = null; - - @JsonProperty("source-asset") - private String sourceAsset = null; - - @JsonProperty("target-tenant") - private String targetTenant = null; - - @JsonProperty("target-asset") - private String targetAsset = null; - - @JsonProperty("problem") - private String problem = null; - - @JsonProperty("context") - private String context = null; - - public CxWarning sourceTenant(String sourceTenant) { - this.sourceTenant = sourceTenant; - return this; - } - - /** - * Get sourceTenant - * - * @return sourceTenant - **/ - @JsonProperty("source-tenant") - @Schema(description = "") - public String getSourceTenant() { - return sourceTenant; - } - - public void setSourceTenant(String sourceTenant) { - this.sourceTenant = sourceTenant; - } - - public CxWarning sourceAsset(String sourceAsset) { - this.sourceAsset = sourceAsset; - return this; - } - - /** - * Get sourceAsset - * - * @return sourceAsset - **/ - @JsonProperty("source-asset") - @Schema(description = "") - public String getSourceAsset() { - return sourceAsset; - } - - public void setSourceAsset(String sourceAsset) { - this.sourceAsset = sourceAsset; - } - - public CxWarning targetTenant(String targetTenant) { - this.targetTenant = targetTenant; - return this; - } - - /** - * Get targetTenant - * - * @return targetTenant - **/ - @JsonProperty("target-tenant") - @Schema(description = "") - public String getTargetTenant() { - return targetTenant; - } - - public void setTargetTenant(String targetTenant) { - this.targetTenant = targetTenant; - } - - public CxWarning targetAsset(String targetAsset) { - this.targetAsset = targetAsset; - return this; - } - - /** - * Get targetAsset - * - * @return targetAsset - **/ - @JsonProperty("target-asset") - @Schema(description = "") - public String getTargetAsset() { - return targetAsset; - } - - public void setTargetAsset(String targetAsset) { - this.targetAsset = targetAsset; - } - - public CxWarning problem(String problem) { - this.problem = problem; - return this; - } - - /** - * Get problem - * - * @return problem - **/ - @JsonProperty("problem") - @Schema(description = "") - public String getProblem() { - return problem; - } - - public void setProblem(String problem) { - this.problem = problem; - } - - public CxWarning context(String context) { - this.context = context; - return this; - } - - /** - * Get context - * - * @return context - **/ - @JsonProperty("context") - @Schema(description = "") - public String getContext() { - return context; - } - - public void setContext(String context) { - this.context = context; - } - - @Override - public int hashCode() { - return Objects.hash(sourceTenant, sourceAsset, targetTenant, targetAsset, problem, context); - } - - @Override - public boolean equals(java.lang.Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - CxWarning cxWarning = (CxWarning) o; - return Objects.equals(this.sourceTenant, cxWarning.sourceTenant) && - Objects.equals(this.sourceAsset, cxWarning.sourceAsset) && - Objects.equals(this.targetTenant, cxWarning.targetTenant) && - Objects.equals(this.targetAsset, cxWarning.targetAsset) && - Objects.equals(this.problem, cxWarning.problem) && - Objects.equals(this.context, cxWarning.context); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class CxWarning {\n"); - - sb.append(" sourceTenant: ").append(toIndentedString(sourceTenant)).append("\n"); - sb.append(" sourceAsset: ").append(toIndentedString(sourceAsset)).append("\n"); - sb.append(" targetTenant: ").append(toIndentedString(targetTenant)).append("\n"); - sb.append(" targetAsset: ").append(toIndentedString(targetAsset)).append("\n"); - sb.append(" problem: ").append(toIndentedString(problem)).append("\n"); - sb.append(" context: ").append(toIndentedString(context)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(java.lang.Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } -} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultset.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultset.java deleted file mode 100644 index 8c888026..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultset.java +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.media.Schema; - -import java.util.Objects; -import javax.validation.Valid; - -/** - * JsonResultset - */ -@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") -public class JsonResultset { - @JsonProperty("head") - private JsonResultsetHead head = null; - - @JsonProperty("results") - private JsonResultsetResults results = null; - - public JsonResultset head(JsonResultsetHead head) { - this.head = head; - return this; - } - - /** - * Get head - * - * @return head - **/ - @JsonProperty("head") - @Schema(description = "") - @Valid - public JsonResultsetHead getHead() { - return head; - } - - public void setHead(JsonResultsetHead head) { - this.head = head; - } - - public JsonResultset results(JsonResultsetResults results) { - this.results = results; - return this; - } - - /** - * Get results - * - * @return results - **/ - @JsonProperty("results") - @Schema(description = "") - @Valid - public JsonResultsetResults getResults() { - return results; - } - - public void setResults(JsonResultsetResults results) { - this.results = results; - } - - @Override - public int hashCode() { - return Objects.hash(head, results); - } - - @Override - public boolean equals(java.lang.Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - JsonResultset jsonResultset = (JsonResultset) o; - return Objects.equals(this.head, jsonResultset.head) && - Objects.equals(this.results, jsonResultset.results); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class JsonResultset {\n"); - - sb.append(" head: ").append(toIndentedString(head)).append("\n"); - sb.append(" results: ").append(toIndentedString(results)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(java.lang.Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } -} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultsetHead.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultsetHead.java deleted file mode 100644 index 7de6ed5d..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultsetHead.java +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.media.Schema; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * JsonResultsetHead - */ -@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") -public class JsonResultsetHead { - @JsonProperty("vars") - private List vars = null; - - public JsonResultsetHead vars(List vars) { - this.vars = vars; - return this; - } - - public JsonResultsetHead addVarsItem(String varsItem) { - if (this.vars == null) { - this.vars = new ArrayList(); - } - this.vars.add(varsItem); - return this; - } - - /** - * Get vars - * - * @return vars - **/ - @JsonProperty("vars") - @Schema(description = "") - public List getVars() { - return vars; - } - - public void setVars(List vars) { - this.vars = vars; - } - - @Override - public int hashCode() { - return Objects.hash(vars); - } - - @Override - public boolean equals(java.lang.Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - JsonResultsetHead jsonResultsetHead = (JsonResultsetHead) o; - return Objects.equals(this.vars, jsonResultsetHead.vars); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class JsonResultsetHead {\n"); - - sb.append(" vars: ").append(toIndentedString(vars)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(java.lang.Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } -} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultsetResults.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultsetResults.java deleted file mode 100644 index 20de1434..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/JsonResultsetResults.java +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.media.Schema; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * JsonResultsetResults - */ -@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") -public class JsonResultsetResults { - @JsonProperty("bindings") - private List bindings = null; - - public JsonResultsetResults bindings(List bindings) { - this.bindings = bindings; - return this; - } - - public JsonResultsetResults addBindingsItem(Object bindingsItem) { - if (this.bindings == null) { - this.bindings = new ArrayList(); - } - this.bindings.add(bindingsItem); - return this; - } - - /** - * Get bindings - * - * @return bindings - **/ - @JsonProperty("bindings") - @Schema(description = "") - public List getBindings() { - return bindings; - } - - public void setBindings(List bindings) { - this.bindings = bindings; - } - - @Override - public int hashCode() { - return Objects.hash(bindings); - } - - @Override - public boolean equals(java.lang.Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - JsonResultsetResults jsonResultsetResults = (JsonResultsetResults) o; - return Objects.equals(this.bindings, jsonResultsetResults.bindings); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class JsonResultsetResults {\n"); - - sb.append(" bindings: ").append(toIndentedString(bindings)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(java.lang.Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } -} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultset.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultset.java deleted file mode 100644 index 1755388a..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultset.java +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.media.Schema; - -import java.util.Objects; -import javax.validation.Valid; - -/** - * XmlResultset - */ -@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") -public class XmlResultset { - @JsonProperty("head") - private XmlResultsetHead head = null; - - @JsonProperty("results") - private XmlResultsetResults results = null; - - public XmlResultset head(XmlResultsetHead head) { - this.head = head; - return this; - } - - /** - * Get head - * - * @return head - **/ - @JsonProperty("head") - @Schema(description = "") - @Valid - public XmlResultsetHead getHead() { - return head; - } - - public void setHead(XmlResultsetHead head) { - this.head = head; - } - - public XmlResultset results(XmlResultsetResults results) { - this.results = results; - return this; - } - - /** - * Get results - * - * @return results - **/ - @JsonProperty("results") - @Schema(description = "") - @Valid - public XmlResultsetResults getResults() { - return results; - } - - public void setResults(XmlResultsetResults results) { - this.results = results; - } - - @Override - public int hashCode() { - return Objects.hash(head, results); - } - - @Override - public boolean equals(java.lang.Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - XmlResultset xmlResultset = (XmlResultset) o; - return Objects.equals(this.head, xmlResultset.head) && - Objects.equals(this.results, xmlResultset.results); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class XmlResultset {\n"); - - sb.append(" head: ").append(toIndentedString(head)).append("\n"); - sb.append(" results: ").append(toIndentedString(results)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(java.lang.Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } -} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetHead.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetHead.java deleted file mode 100644 index e6c16b01..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetHead.java +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.model; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * XmlResultsetHead - */ -@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") -public class XmlResultsetHead { - @JsonProperty("variable") - private List variables = new ArrayList<>(); - - public XmlResultsetHead addVariable(XmlResultsetHeadVariable variable) { - this.variables.add(variable); - return this; - } - - /** - * Get variables - * - * @return variables - **/ - public List getVariables() { - return variables; - } - - @Override - public int hashCode() { - return Objects.hash(variables); - } - - @Override - public boolean equals(java.lang.Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - XmlResultsetHead xmlResultsetHead = (XmlResultsetHead) o; - return Objects.equals(this.variables, xmlResultsetHead.variables); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class XmlResultsetHead {\n"); - - sb.append(" variable: ").append(toIndentedString(variables)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(java.lang.Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } -} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetHeadVariable.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetHeadVariable.java deleted file mode 100644 index 0bb8ddb1..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetHeadVariable.java +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.media.Schema; - -import java.util.Objects; - -/** - * XmlResultsetHeadVariable - */ -@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") -public class XmlResultsetHeadVariable { - @JsonProperty("name") - private String name = null; - - public XmlResultsetHeadVariable name(String name) { - this.name = name; - return this; - } - - /** - * Get name - * - * @return name - **/ - @JsonProperty("name") - @Schema(description = "") - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public int hashCode() { - return Objects.hash(name); - } - - @Override - public boolean equals(java.lang.Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - XmlResultsetHeadVariable xmlResultsetHeadVariable = (XmlResultsetHeadVariable) o; - return Objects.equals(this.name, xmlResultsetHeadVariable.name); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class XmlResultsetHeadVariable {\n"); - - sb.append(" name: ").append(toIndentedString(name)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(java.lang.Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } -} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResults.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResults.java deleted file mode 100644 index 3049250f..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResults.java +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.model; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * XmlResultsetResults - */ -@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") -public class XmlResultsetResults { - @JsonProperty("result") - private List results = new ArrayList<>(); - - public XmlResultsetResults addResult(XmlResultsetResultsResult result) { - this.results.add(result); - return this; - } - - /** - * Get result - * - * @return result - **/ - public List getResults() { - return results; - } - - @Override - public int hashCode() { - return Objects.hash(results); - } - - @Override - public boolean equals(java.lang.Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - XmlResultsetResults xmlResultsetResults = (XmlResultsetResults) o; - return Objects.equals(this.results, xmlResultsetResults.results); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class XmlResultsetResults {\n"); - - sb.append(" result: ").append(toIndentedString(results)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(java.lang.Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } -} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResult.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResult.java deleted file mode 100644 index 9107a207..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResult.java +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.model; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * XmlResultsetResultsResult - */ -@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") -public class XmlResultsetResultsResult { - @JsonProperty("binding") - private List bindings = new ArrayList<>(); - - public XmlResultsetResultsResult addBinding(XmlResultsetResultsResultBinding binding) { - this.bindings.add(binding); - return this; - } - - /** - * Get binding - * - * @return binding - **/ - public List getBindings() { - return bindings; - } - - @Override - public int hashCode() { - return Objects.hash(bindings); - } - - @Override - public boolean equals(java.lang.Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - XmlResultsetResultsResult xmlResultsetResultsResult = (XmlResultsetResultsResult) o; - return Objects.equals(this.bindings, xmlResultsetResultsResult.bindings); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class XmlResultsetResultsResult {\n"); - - sb.append(" binding: ").append(toIndentedString(bindings)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(java.lang.Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } -} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResultBinding.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResultBinding.java deleted file mode 100644 index 136ed872..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResultBinding.java +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.media.Schema; - -import java.util.Objects; - -/** - * XmlResultsetResultsResultBinding - */ -@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-23T11:28:11.277776230Z[GMT]") -public class XmlResultsetResultsResultBinding { - @JsonProperty("name") - private String name = null; - - @JsonProperty("literal") - private XmlResultsetResultsResultBindingLiteral literal = null; - - @JsonProperty("uri") - private String uri = null; - - public XmlResultsetResultsResultBinding name(String name) { - this.name = name; - return this; - } - - /** - * Get name - * - * @return name - **/ - @JsonProperty("name") - @Schema(description = "") - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public XmlResultsetResultsResultBinding literal(XmlResultsetResultsResultBindingLiteral literal) { - this.literal = literal; - return this; - } - - /** - * Get literal - * - * @return literal - **/ - @JsonProperty("literal") - @Schema(description = "") - public XmlResultsetResultsResultBindingLiteral getLiteral() { - return literal; - } - - public void setLiteral(XmlResultsetResultsResultBindingLiteral literal) { - this.literal = literal; - } - - public XmlResultsetResultsResultBinding uri(String uri) { - this.uri = uri; - return this; - } - - /** - * Get uri - * - * @return uri - **/ - @JsonProperty("uri") - @Schema(description = "") - public String getUri() { - return uri; - } - - public void setUri(String uri) { - this.uri = uri; - } - - @Override - public int hashCode() { - return Objects.hash(name, literal, uri); - } - - @Override - public boolean equals(java.lang.Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - XmlResultsetResultsResultBinding xmlResultsetResultsResultBinding = (XmlResultsetResultsResultBinding) o; - return Objects.equals(this.name, xmlResultsetResultsResultBinding.name) && - Objects.equals(this.literal, xmlResultsetResultsResultBinding.literal) && - Objects.equals(this.uri, xmlResultsetResultsResultBinding.uri); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class XmlResultsetResultsResultBinding {\n"); - - sb.append(" name: ").append(toIndentedString(name)).append("\n"); - sb.append(" literal: ").append(toIndentedString(literal)).append("\n"); - sb.append(" uri: ").append(toIndentedString(uri)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(java.lang.Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } -} diff --git a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResultBindingLiteral.java b/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResultBindingLiteral.java deleted file mode 100644 index 56eec6c3..00000000 --- a/matchmaking/src/gen/java/org/eclipse/tractusx/agents/conforming/model/XmlResultsetResultsResultBindingLiteral.java +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming.model; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText; -import io.swagger.v3.oas.annotations.media.Schema; - -import java.util.Objects; - -/** - * XmlResultsetResultsResultBindingLiteral - */ -@jakarta.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen", date = "2023-03-24T17:09:51.803733265Z[GMT]") -public class XmlResultsetResultsResultBindingLiteral { - @JsonProperty("xml:lang") - private String xmllang = null; - - @JsonProperty("datatype") - private String datatype = null; - - @JsonProperty("value") - @JacksonXmlText - private String value = null; - - public XmlResultsetResultsResultBindingLiteral xmllang(String xmllang) { - this.xmllang = xmllang; - return this; - } - - /** - * Get xmllang - * - * @return xmllang - **/ - @JsonProperty("xml:lang") - @Schema(description = "") - public String getXmllang() { - return xmllang; - } - - public void setXmllang(String xmllang) { - this.xmllang = xmllang; - } - - public XmlResultsetResultsResultBindingLiteral datatype(String datatype) { - this.datatype = datatype; - return this; - } - - /** - * Get datatype - * - * @return datatype - **/ - @JsonProperty("datatype") - @Schema(description = "") - public String getDatatype() { - return datatype; - } - - public void setDatatype(String datatype) { - this.datatype = datatype; - } - - public XmlResultsetResultsResultBindingLiteral value(String value) { - this.value = value; - return this; - } - - /** - * Get value - * - * @return value - **/ - @JsonProperty("value") - @Schema(description = "") - @JacksonXmlText() - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - @Override - public int hashCode() { - return Objects.hash(xmllang, datatype, value); - } - - @Override - public boolean equals(java.lang.Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - XmlResultsetResultsResultBindingLiteral xmlResultsetResultsResultBindingLiteral = (XmlResultsetResultsResultBindingLiteral) o; - return Objects.equals(this.xmllang, xmlResultsetResultsResultBindingLiteral.xmllang) && - Objects.equals(this.datatype, xmlResultsetResultsResultBindingLiteral.datatype) && - Objects.equals(this.value, xmlResultsetResultsResultBindingLiteral.value); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class XmlResultsetResultsResultBindingLiteral {\n"); - - sb.append(" xmllang: ").append(toIndentedString(xmllang)).append("\n"); - sb.append(" datatype: ").append(toIndentedString(datatype)).append("\n"); - sb.append(" value: ").append(toIndentedString(value)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(java.lang.Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } -} diff --git a/matchmaking/src/main/docker/Dockerfile b/matchmaking/src/main/docker/Dockerfile index f4cc5f5e..9cd141d4 100644 --- a/matchmaking/src/main/docker/Dockerfile +++ b/matchmaking/src/main/docker/Dockerfile @@ -20,7 +20,7 @@ ARG JAR ARG LIB ARG APP_USER=agent -ARG APP_UID=10100 +ARG APP_UID=10001 ARG APP_GID=30000 RUN addgroup --gid "$APP_GID" --system "$APP_USER" @@ -41,7 +41,7 @@ WORKDIR /app VOLUME /tmp COPY target/matchmaking-agent-*.jar /app/lib/ -COPY resources/dataplane.properties /app/configuration.properties +COPY resources/matchmaking.properties /app/configuration.properties COPY resources/dataspace.ttl /app/dataspace.ttl # TODO implement wget or curl-based health check @@ -49,4 +49,4 @@ HEALTHCHECK NONE EXPOSE 8080 -ENTRYPOINT ["java","-cp","/app/lib/*", "org.eclipse.tractusx.agents.conforming.Bootstrap"] \ No newline at end of file +ENTRYPOINT ["java","-cp","/app/lib/*", "org.eclipse.tractusx.agents.matchmaking.Bootstrap"] \ No newline at end of file diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentConfig.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/AgentConfig.java similarity index 91% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentConfig.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/AgentConfig.java index 564d5866..43f62468 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentConfig.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/AgentConfig.java @@ -14,10 +14,10 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc; +package org.eclipse.tractusx.agents; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.system.configuration.Config; +import org.eclipse.tractusx.agents.utils.Config; +import org.eclipse.tractusx.agents.utils.Monitor; import java.util.Map; import java.util.regex.Pattern; @@ -94,7 +94,14 @@ public class AgentConfig { public static final String TX_EDC_VERSION_PROPERTY = "cx.agent.edc.version"; - public static final String MATCHMAKING_PORT_INTERNAL = "cx.agent.matchmaking.internal.api"; + public static final String MATCHMAKING_PORT = "web.http.internal.port"; + public static final String MATCHMAKING_PATH = "web.http.internal.path"; + + public static final String DEFAULT_PORT = "web.http.default.port"; + public static final String DEFAULT_PATH = "web.http.default.path"; + + public static final String CALLBACK_PORT = "web.http.callback.port"; + public static final String CALLBACK_PATH = "web.http.callback.path"; /** * precompiled stuff @@ -398,8 +405,28 @@ public boolean isPrerelease() { return getEdcVersion().compareTo("0.5.0") <= 0; } - public int getMatchmakingPortInternal() { - return config.getInteger(MATCHMAKING_PORT_INTERNAL); + public int getMatchmakingPort() { + return config.getInteger(MATCHMAKING_PORT); } + public String getMatchmakingPath() { + return config.getString(MATCHMAKING_PATH); + } + + public int getDefaultPort() { + return config.getInteger(DEFAULT_PORT); + } + + public String getDefaultPath() { + return config.getString(DEFAULT_PATH); + } + + public int getCallbackPort() { + return config.getInteger(CALLBACK_PORT); + } + + public String getCallbacktPath() { + return config.getString(CALLBACK_PATH); + } + } diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentProtocol.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/AgentProtocol.java similarity index 96% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentProtocol.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/AgentProtocol.java index 165fe0a5..0b98e416 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentProtocol.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/AgentProtocol.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc; +package org.eclipse.tractusx.agents; /** * lists the various protocols supported diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgreementController.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/AgreementController.java similarity index 93% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgreementController.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/AgreementController.java index 86208478..4073d5f6 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgreementController.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/AgreementController.java @@ -14,10 +14,10 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc; +package org.eclipse.tractusx.agents; import jakarta.ws.rs.WebApplicationException; -import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; +import org.eclipse.tractusx.agents.utils.EndpointDataReference; /** * Interface to any agreement controller diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgreementControllerImpl.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/AgreementControllerImpl.java similarity index 94% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgreementControllerImpl.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/AgreementControllerImpl.java index 5ab110b0..c432eddc 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgreementControllerImpl.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/AgreementControllerImpl.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc; +package org.eclipse.tractusx.agents; import com.nimbusds.jose.JWSObject; import jakarta.json.JsonValue; @@ -27,23 +27,23 @@ import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.types.domain.DataAddress; -import org.eclipse.edc.spi.types.domain.callback.CallbackAddress; -import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; -import org.eclipse.tractusx.agents.edc.jsonld.JsonLd; -import org.eclipse.tractusx.agents.edc.model.ContractAgreement; -import org.eclipse.tractusx.agents.edc.model.ContractNegotiation; -import org.eclipse.tractusx.agents.edc.model.ContractNegotiationRequest; -import org.eclipse.tractusx.agents.edc.model.ContractOfferDescription; -import org.eclipse.tractusx.agents.edc.model.DcatCatalog; -import org.eclipse.tractusx.agents.edc.model.DcatDataset; -import org.eclipse.tractusx.agents.edc.model.OdrlPolicy; -import org.eclipse.tractusx.agents.edc.model.TransferProcess; -import org.eclipse.tractusx.agents.edc.model.TransferRequest; -import org.eclipse.tractusx.agents.edc.service.DataManagement; -import org.eclipse.tractusx.agents.edc.service.DataManagementImpl; -import org.eclipse.tractusx.agents.edc.service.DataspaceSynchronizer; +import org.eclipse.tractusx.agents.jsonld.JsonLd; +import org.eclipse.tractusx.agents.model.ContractAgreement; +import org.eclipse.tractusx.agents.model.ContractNegotiation; +import org.eclipse.tractusx.agents.model.ContractNegotiationRequest; +import org.eclipse.tractusx.agents.model.ContractOfferDescription; +import org.eclipse.tractusx.agents.model.DcatCatalog; +import org.eclipse.tractusx.agents.model.DcatDataset; +import org.eclipse.tractusx.agents.model.OdrlPolicy; +import org.eclipse.tractusx.agents.model.TransferProcess; +import org.eclipse.tractusx.agents.model.TransferRequest; +import org.eclipse.tractusx.agents.service.DataManagement; +import org.eclipse.tractusx.agents.service.DataManagementImpl; +import org.eclipse.tractusx.agents.service.DataspaceSynchronizer; +import org.eclipse.tractusx.agents.utils.CallbackAddress; +import org.eclipse.tractusx.agents.utils.DataAddress; +import org.eclipse.tractusx.agents.utils.EndpointDataReference; +import org.eclipse.tractusx.agents.utils.Monitor; import java.io.IOException; import java.text.ParseException; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/MonitorWrapper.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/MonitorWrapper.java similarity index 96% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/MonitorWrapper.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/MonitorWrapper.java index d3aff72f..e612b36f 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/MonitorWrapper.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/MonitorWrapper.java @@ -14,9 +14,9 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc; +package org.eclipse.tractusx.agents; -import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.tractusx.agents.utils.Monitor; import org.slf4j.Marker; import org.slf4j.event.Level; import org.slf4j.helpers.AbstractLogger; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/SkillDistribution.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/SkillDistribution.java similarity index 97% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/SkillDistribution.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/SkillDistribution.java index d9dd6912..cb9cdaa6 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/SkillDistribution.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/SkillDistribution.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc; +package org.eclipse.tractusx.agents; /** * enumerates the various skill distribution/run modes diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/SkillStore.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/SkillStore.java similarity index 91% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/SkillStore.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/SkillStore.java index 1b7b3998..df355d79 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/SkillStore.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/SkillStore.java @@ -14,15 +14,18 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc; +package org.eclipse.tractusx.agents; import java.util.Optional; import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * interface to a skill store */ public interface SkillStore { + + Pattern SKILL_PATTERN = Pattern.compile("((?[^#]+)#)?(?.*Skill(Asset)?.*)"); /** * match a given asset @@ -31,7 +34,7 @@ public interface SkillStore { * @return matcher */ static Matcher matchSkill(String key) { - return AgentExtension.SKILL_PATTERN.matcher(key); + return SKILL_PATTERN.matcher(key); } /** diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/Tuple.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/Tuple.java similarity index 98% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/Tuple.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/Tuple.java index d96ed7b5..5fa4eb46 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/Tuple.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/Tuple.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc; +package org.eclipse.tractusx.agents; import java.util.HashMap; import java.util.Map; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/TupleSet.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/TupleSet.java similarity index 99% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/TupleSet.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/TupleSet.java index 586800b6..c1805544 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/TupleSet.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/TupleSet.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc; +package org.eclipse.tractusx.agents; import org.apache.jena.ext.com.google.common.collect.ArrayListMultimap; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/annotation/ExtensionPoint.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/annotation/ExtensionPoint.java new file mode 100644 index 00000000..8e1c0890 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/annotation/ExtensionPoint.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022 Microsoft Corporation + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation + * + */ + +package org.eclipse.tractusx.agents.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Denotes a service extension point. + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface ExtensionPoint { +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/BindingAgent.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/BindingAgent.java deleted file mode 100644 index 25843819..00000000 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/BindingAgent.java +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming; - -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.Response; -import org.eclipse.rdf4j.query.parser.ParsedQuery; -import org.eclipse.rdf4j.query.parser.sparql.SPARQLParser; -import org.eclipse.tractusx.agents.conforming.api.NotFoundException; - -import java.util.List; -import javax.validation.constraints.NotNull; - -/** - * Implements a standard binding agent - */ -@Path("/bind") -public class BindingAgent extends ConformingAgent { - - public BindingAgent() { - - } - - @Override - public Response getAgent(String asset, String queryLn, String query, String vin, List troubleCode) throws NotFoundException { - if (query == null) { - return annotate(Response.status(400, "{ \"error\":400, \"reason\":\"KA-BIND: query parameter must be set\" }")); - } - SPARQLParser parser = new SPARQLParser(); - ParsedQuery sparql = parser.parseQuery(query, uri.getAbsolutePath().toString()); - - try { - sparql.getTupleExpr().visit(new BindingProfileChecker()); - } catch (Exception e) { - return annotate(Response.status(400, "{ \"error\":400, \"reason\":\"" + e.getMessage() + "\" }")); - } - return super.getAgent(asset, queryLn, query, vin, troubleCode); - } - - @Override - public Response postAgent(Object body, String asset, String queryLn, String query, String vin, List troubleCode) throws NotFoundException { - if (body == null || String.valueOf(body).isEmpty()) { - return annotate(Response.status(400, "{ \"error\":400, \"reason\":\"KA-BIND: query parameter must be set\" }")); - } - return super.postAgent(body, asset, queryLn, query, vin, troubleCode); - } - - @Override - public Response postSkill(String body, @NotNull String asset) throws NotFoundException { - return annotate(Response.status(404, "{ \"error\":404, \"reason\":\"KA-BIND: does not support skills\" }")); - } -} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/BindingProfileChecker.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/BindingProfileChecker.java deleted file mode 100644 index a9037685..00000000 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/BindingProfileChecker.java +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming; - -import org.eclipse.rdf4j.query.algebra.StatementPattern; -import org.eclipse.rdf4j.query.algebra.helpers.AbstractQueryModelVisitor; - -public class BindingProfileChecker extends AbstractQueryModelVisitor { - @Override - public void meet(StatementPattern node) throws Exception { - if (!node.getPredicateVar().isConstant()) { - throw new Exception("Predicate must be not constant."); - } - if (!node.getPredicateVar().getValue().isIRI()) { - throw new Exception("Predicate must be IRI."); - } - if ("http://www.w3.org/1999/02/22-rdf-syntax-ns#type".equals(node.getPredicateVar().getValue().stringValue())) { - if (!node.getObjectVar().isConstant()) { - throw new Exception("Object of rdf:type must be constant."); - } - } - super.meet(node); - } -} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/ConformingAgent.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/ConformingAgent.java deleted file mode 100644 index 99c87f77..00000000 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/ConformingAgent.java +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming; - -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.eclipse.tractusx.agents.conforming.api.AgentApi; -import org.eclipse.tractusx.agents.conforming.api.NotFoundException; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; -import java.util.regex.Matcher; -import javax.validation.constraints.NotNull; - -public class ConformingAgent extends AgentApi { - - public static String emptyJson = "{\n" + - " \"head\": {\n" + - " \"vars\": [\n" + - " ]\n" + - " },\n" + - " \"results\": {\n" + - " \"bindings\": [\n" + - " ]\n" + - " }\n" + - "}"; - - public static String simpleJson = "{\n" + - " \"head\": {\n" + - " \"vars\": [\n" + - " \"subject\",\n" + - " \"predicate\",\n" + - " \"object\"\n" + - " ]\n" + - " },\n" + - " \"results\": {\n" + - " \"bindings\": [\n" + - " {\n" + - " \"subject\": {\n" + - " \"type\": \"uri\",\n" + - " \"value\": \"urn:cx:AnonymousSerializedPart#GB4711\"\n" + - " },\n" + - " \"predicate\": {\n" + - " \"type\": \"uri\",\n" + - " \"value\": \"https://w3id.org/catenax/ontology#hasPartType\"\n" + - " },\n" + - " \"object\": {\n" + - " \"type\": \"literal\",\n" + - " \"value\": \"engine control module\",\n" + - " \"datatype\": \"http://www.w3.org/1999/02/22-rdf-syntax-ns#langString\",\n" + - " \"xml:lang\": \"en\"\n" + - " }\n" + - " }\n" + - " ]\n" + - " }\n" + - "}"; - - public static String simpleBindJson = "{\n" + - " \"head\": {\n" + - " \"vars\": [\n" + - " \"subject\",\n" + - " \"predicate\",\n" + - " \"object\",\n" + - " \"bindingVar\"\n" + - " ]\n" + - " },\n" + - " \"results\": {\n" + - " \"bindings\": [\n" + - " {\n" + - " \"bindingVar\": {\n" + - " \"type\": \"literal\",\n" + - " \"value\": \"0\"\n" + - " },\n" + - " \"subject\": {\n" + - " \"type\": \"uri\",\n" + - " \"value\": \"urn:cx:AnonymousSerializedPart#GB4711\"\n" + - " },\n" + - " \"predicate\": {\n" + - " \"type\": \"uri\",\n" + - " \"value\": \"hhttps://w3id.org/catenax/ontology#hasPartType\"\n" + - " },\n" + - " \"object\": {\n" + - " \"type\": \"literal\",\n" + - " \"value\": \"engine control module\",\n" + - " \"datatype\": \"http://www.w3.org/1999/02/22-rdf-syntax-ns#langString\",\n" + - " \"xml:lang\": \"en\"\n" + - " }\n" + - " }\n" + - " ]\n" + - " }\n" + - "}"; - - public static String emptyXml = "\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - ""; - - public static String simpleXml = "\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " urn:cx:AnonymousSerializedPart#GB4711\n" + - " \n" + - " \n" + - " https://w3id.org/catenax/ontology#hasPartType\n" + - " \n" + - " \n" + - " engine control module\n" + - " \n" + - " \n" + - " \n" + - ""; - - public static String simpleBindXml = "\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 0\n" + - " \n" + - " \n" + - " urn:cx:AnonymousSerializedPart#GB4711\n" + - " \n" + - " \n" + - " https://w3id.org/catenax/ontology#hasPartType\n" + - " \n" + - " \n" + - " engine control module\n" + - " \n" + - " \n" + - " \n" + - ""; - - public static MediaType srj = MediaType.valueOf("application/sparql-results+json"); - public static MediaType srx = MediaType.valueOf("application/sparql-results+xml"); - public static MediaType sq = MediaType.valueOf("application/sparql-query"); - - public boolean useSimple = true; - public int status = 200; - public String warnings = "[ { \"source-tenant\": \"BPNL00000003CQI9\", \"target-tenant\": \"BPNL00000003COJN\", \"target-asset\": \"urn:cx:GraphAsset#TestAsset\", \"problem\": \"Could not access graph.\", \"context\": \"SPARQL-QUERY 1027\" } ]"; - java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("\\?(binding[0-9]+)"); - - @Override - public Response getAgent(String asset, String queryLn, String query, String vin, List troubleCode) throws NotFoundException { - MediaType resultType = getDefaultResultType(); - if (resultType == null) { - return annotate(Response.status(400, "KA-BIND/KA-MATCH: Only supports application/sparql-results+json|xml compatible Accept header")); - } - String bindingVar = null; - if (query != null) { - Matcher matcher = pattern.matcher(query); - if (matcher.find()) { - bindingVar = matcher.group(1); - } - } - return annotate(compute(resultType, bindingVar)); - } - - @Override - public Response postAgent(Object body, String asset, String queryLn, String query, String vin, List troubleCode) throws NotFoundException { - MediaType resultType = getDefaultResultType(); - if (resultType == null) { - return annotate(Response.status(400, "KA-BIND/KA-MATCH: Only supports application/sparql-results+json|xml compatible Accept header")); - } - MediaType bodyType = MediaType.valueOf(headers.getHeaderString("Content-Type")); - if (!bodyType.isCompatible(sq) && !bodyType.isCompatible(srj) && !bodyType.isCompatible(srx)) { - return annotate(Response.status(400, "KA-BIND/KA-MATCH postAgent only accepts application/sparql-query|results+json|xml in body.")); - } - String bindingVar = null; - String toCheck = query; - if (query == null) { - toCheck = String.valueOf(body); - } - if (toCheck != null) { - Matcher matcher = pattern.matcher(toCheck); - if (matcher.find()) { - bindingVar = matcher.group(1); - } - } - return annotate(compute(resultType, bindingVar)); - } - - @Override - public Response postSkill(String body, @NotNull String asset) throws NotFoundException { - if (asset.length() == 0) { - return Response.status(400, "KA-BIND/KA-MATCH postSkill requires a non-empty asset name.").build(); - } - MediaType bodyType = MediaType.valueOf(headers.getHeaderString("Content-Type")); - if (body != null || body.isEmpty() || !bodyType.isCompatible(sq)) { - return Response.status(400, "KA-BIND/KA-MATCH postSkill only accepts application/sparql-query|results+json|xml in body.").build(); - } - return Response.ok().build(); - } - - protected MediaType getDefaultResultType() { - if (headers.getHeaderString("Accept") != null) { - String[] compartments = headers.getHeaderString("Accept").split(","); - for (String compartment : compartments) { - String[] qualifiers = compartment.split(";"); - try { - MediaType wantedEncoding = MediaType.valueOf(qualifiers[0]); - if (wantedEncoding.isCompatible(srj)) { - return srj; - } else if (wantedEncoding.isCompatible(srx)) { - return srx; - } - } catch (IllegalArgumentException iae) { - System.err.printf("Warning: Ingoring unsupported accepted mediatype %s%n", qualifiers[0]); - } - } - return null; - } - return srj; - } - - /** - * produces a standard response - */ - protected Map computeBody(MediaType resultType, String bindingVar) { - String target; - if (useSimple) { - if (resultType.isCompatible(srj)) { - target = getSimpleJson(bindingVar); - } else { - target = getSimpleXml(bindingVar); - } - } else { - if (resultType.isCompatible(srj)) { - target = emptyJson; - } else { - target = emptyXml; - } - } - return Map.of(resultType.toString(), target.getBytes()); - } - - protected String getSimpleJson(String bindingVar) { - if (bindingVar != null) { - return simpleBindJson.replaceAll("bindingVar", bindingVar); - } - return simpleJson; - } - - protected String getSimpleXml(String bindingVar) { - if (bindingVar != null) { - return simpleBindXml.replaceAll("bindingVar", bindingVar); - } else { - return simpleXml; - } - } - - /** - * produces a standard response - */ - protected Response.ResponseBuilder compute(MediaType resultType, String bindingVar) { - AtomicReference response = new AtomicReference<>(Response.status(status)); - Map body = computeBody(resultType, bindingVar); - body.forEach((key, value) -> response.set(response.get().type(key).entity(value))); - return response.get(); - } - - protected Response annotate(Response.ResponseBuilder builder) { - return builder.build(); - } -} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/MatchmakingAgent.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/MatchmakingAgent.java deleted file mode 100644 index 59f2ebc9..00000000 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/MatchmakingAgent.java +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming; - -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.Response; -import org.eclipse.tractusx.agents.conforming.api.NotFoundException; - -import java.util.List; - -/** - * Implements a standard matchmaking agent - */ -@Path("/match") -public class MatchmakingAgent extends ConformingAgent { - - public MatchmakingAgent() { - status = 203; - } - - @Override - public Response getAgent(String asset, String queryLn, String query, String vin, List troubleCode) throws NotFoundException { - if (query == null && asset == null) { - return annotate(Response.status(400, "{ \"error\":400, \"reason\":\"KA-MATCH: query or asset parameter must be set\" }")); - } - return super.getAgent(asset, queryLn, query, vin, troubleCode); - } - - @Override - public Response postAgent(Object body, String asset, String queryLn, String query, String vin, List troubleCode) throws NotFoundException { - if ((body == null || String.valueOf(body).isEmpty()) && asset == null) { - return annotate(Response.status(400, "{ \"error\":400, \"reason\":\"KA-BIND: body or asset parameter must be set\" }")); - } - return super.postAgent(body, asset, queryLn, query, vin, troubleCode); - } - - @Override - protected Response annotate(Response.ResponseBuilder builder) { - return builder.header("cx_warnings", warnings) - .header("Access-Control-Expose-Headers", "cx_warnings, content-length, content-type") - .build(); - } -} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/TransferAgent.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/TransferAgent.java deleted file mode 100644 index f5e0aa0e..00000000 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/TransferAgent.java +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming; - -import jakarta.annotation.PostConstruct; -import jakarta.validation.constraints.NotNull; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import org.eclipse.tractusx.agents.conforming.api.NotFoundException; -import org.glassfish.jersey.media.multipart.FormDataMultiPart; - -import java.util.List; - -/** - * Implements a standard transfer agent - */ -@Path("/transfer") -public class TransferAgent extends ConformingAgent { - - /** - * the actual delegator to use - */ - ConformingAgent delegator = new MatchmakingAgent(); - - @PostConstruct - public void init() { - delegator.application = application; - delegator.securityContext = securityContext; - delegator.headers = headers; - delegator.request = request; - delegator.response = response; - delegator.uri = uri; - } - - @Override - public Response getAgent(String asset, String queryLn, String query, String vin, List troubleCode) throws NotFoundException { - Response intermediate = delegator.getAgent(asset, queryLn, query, vin, troubleCode); - return compute(intermediate); - } - - @Override - public Response postAgent(Object body, String asset, String queryLn, String query, String vin, List troubleCode) throws NotFoundException { - Response intermediate = delegator.postAgent(body, asset, queryLn, query, vin, troubleCode); - return compute(intermediate); - } - - @Override - public Response postSkill(String body, @NotNull String asset) throws NotFoundException { - return Response.status(404, "{ \"error\":404, \"reason\":\"KA-BIND: does not support skills\" }").build(); - } - - @Override - protected MediaType getDefaultResultType() { - if (this.uri.getQueryParameters().containsKey("cx_accepts")) { - List allCompartments = this.uri.getQueryParameters().get("cx_accepts"); - for (String compartments : allCompartments) { - for (String compartment : compartments.split(",")) { - String[] qualifiers = compartment.split(";"); - try { - MediaType wantedEncoding = MediaType.valueOf(qualifiers[0]); - if (wantedEncoding.isCompatible(srj)) { - return srj; - } else if (wantedEncoding.isCompatible(srx)) { - return srx; - } - } catch (IllegalArgumentException iae) { - // we simply return null then - } - } - } - return null; - } - return srj; - } - - /** - * produces a standard response - */ - protected Response compute(Response delegateResponse) { - Response.ResponseBuilder response = Response.status(delegateResponse.getStatus()).type(MediaType.MULTIPART_FORM_DATA); - FormDataMultiPart mpe = new FormDataMultiPart(); - if (delegateResponse.hasEntity()) { - mpe.bodyPart(delegateResponse.getEntity(), delegateResponse.getMediaType()); - } - if (delegateResponse.getHeaders().containsKey("cx_warnings")) { - mpe.bodyPart(delegateResponse.getHeaderString("cx_warnings"), MediaType.APPLICATION_JSON_TYPE); - } - if (mpe.getBodyParts().size() > 0) { - response = response.entity(mpe); - } - return response.build(); - } - -} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentExtension.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentExtension.java deleted file mode 100644 index b5096119..00000000 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/AgentExtension.java +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc; - -import okhttp3.OkHttpClient; -import org.apache.jena.query.Syntax; -import org.apache.jena.sparql.serializer.SerializerRegistry; -import org.apache.jena.sparql.service.ServiceExecutorRegistry; -import org.eclipse.edc.connector.dataplane.http.spi.HttpRequestParamsProvider; -import org.eclipse.edc.connector.dataplane.spi.pipeline.PipelineService; -import org.eclipse.edc.runtime.metamodel.annotation.Inject; -import org.eclipse.edc.runtime.metamodel.annotation.Requires; -import org.eclipse.edc.spi.http.EdcHttpClient; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.security.Vault; -import org.eclipse.edc.spi.system.ServiceExtension; -import org.eclipse.edc.spi.system.ServiceExtensionContext; -import org.eclipse.edc.spi.types.TypeManager; -import org.eclipse.edc.web.spi.WebService; -import org.eclipse.tractusx.agents.edc.http.AgentController; -import org.eclipse.tractusx.agents.edc.http.DelegationServiceImpl; -import org.eclipse.tractusx.agents.edc.http.HttpClientFactory; -import org.eclipse.tractusx.agents.edc.rdf.RdfStore; -import org.eclipse.tractusx.agents.edc.service.DataManagementImpl; -import org.eclipse.tractusx.agents.edc.service.DataspaceSynchronizer; -import org.eclipse.tractusx.agents.edc.service.EdcSkillStore; -import org.eclipse.tractusx.agents.edc.sparql.DataspaceServiceExecutor; -import org.eclipse.tractusx.agents.edc.sparql.SparqlQueryProcessor; -import org.eclipse.tractusx.agents.edc.sparql.SparqlQuerySerializerFactory; -import org.eclipse.tractusx.agents.edc.validation.SwitchingDataPlaneTokenValidatorController; - -import java.util.Map; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.regex.Pattern; - -/** - * EDC extension that initializes the Agent subsystem (Agent Sources, Agent Endpoint and Federation Callbacks - */ -@Requires(HttpRequestParamsProvider.class) -public class AgentExtension implements ServiceExtension { - - /** - * static constants - */ - protected static final String DEFAULT_CONTEXT_ALIAS = "default"; - protected static final String CALLBACK_CONTEXT_ALIAS = "callback"; - public static final Pattern GRAPH_PATTERN = Pattern.compile("((?[^#]+)#)?(?.*Graph(Asset)?.*)"); - public static final Pattern SKILL_PATTERN = Pattern.compile("((?[^#]+)#)?(?.*Skill(Asset)?.*)"); - - - /** - * dependency injection part - */ - @Inject - protected WebService webService; - - - @Inject - protected PipelineService pipelineService; - - @Inject - protected Vault vault; - - @Inject - protected TypeManager typeManager; - - // we reuse the http settings of the http transfer - @Inject - protected EdcHttpClient edcHttpClient; - @Inject - protected OkHttpClient httpClient; - - /** - * refers a scheduler - * TODO maybe reuse an injected scheduler - */ - protected ScheduledExecutorService executorService; - - /** - * data synchronization service - */ - protected DataspaceSynchronizer synchronizer; - - /** - * access - * - * @return name of the extension - */ - @Override - public String name() { - return "Knowledge Agents Extension"; - } - - /** - * runs on extension initialization - * - * @param context EDC bootstrap context - */ - @Override - public void initialize(ServiceExtensionContext context) { - Monitor monitor = context.getMonitor(); - - monitor.debug(String.format("Initializing %s", name())); - - AgentConfig config = new AgentConfig(monitor, context.getConfig()); - Map.Entry instance = HttpClientFactory.create(edcHttpClient, httpClient, pipelineService, config); - edcHttpClient = instance.getKey(); - httpClient = instance.getValue(); - - DataManagementImpl catalogService = new DataManagementImpl(monitor, typeManager, httpClient, config); - - AgreementControllerImpl agreementController = new AgreementControllerImpl(monitor, config, catalogService); - monitor.debug(String.format("Registering agreement controller %s", agreementController)); - webService.registerResource(CALLBACK_CONTEXT_ALIAS, agreementController); - - RdfStore rdfStore = new RdfStore(config, monitor); - - executorService = Executors.newScheduledThreadPool(config.getThreadPoolSize()); - synchronizer = new DataspaceSynchronizer(executorService, config, catalogService, rdfStore, monitor); - - SwitchingDataPlaneTokenValidatorController validatorController = new SwitchingDataPlaneTokenValidatorController(httpClient, config, monitor); - if (validatorController.isEnabled()) { - monitor.debug(String.format("Registering switching validator controller %s", validatorController)); - webService.registerResource(DEFAULT_CONTEXT_ALIAS, validatorController); - } - - // EDC Remoting Support - ServiceExecutorRegistry reg = new ServiceExecutorRegistry(); - reg.addBulkLink(new DataspaceServiceExecutor(monitor, agreementController, config, httpClient, executorService, typeManager)); - //reg.add(new DataspaceServiceExecutor(monitor,agreementController,config,httpClient)); - - // Ontop and other deep nesting-afraid providers/optimizers - // should be supported by not relying on the Fuseki syntax graph - SparqlQuerySerializerFactory arqQuerySerializerFactory = new SparqlQuerySerializerFactory(); - SerializerRegistry.get().addQuerySerializer(Syntax.syntaxARQ, arqQuerySerializerFactory); - SerializerRegistry.get().addQuerySerializer(Syntax.syntaxSPARQL_10, arqQuerySerializerFactory); - SerializerRegistry.get().addQuerySerializer(Syntax.syntaxSPARQL_11, arqQuerySerializerFactory); - - // the actual sparql engine inside the EDC - SparqlQueryProcessor processor = new SparqlQueryProcessor(reg, monitor, config, rdfStore, typeManager); - - // stored procedure store and transport endpoint - SkillStore skillStore = new EdcSkillStore(catalogService, typeManager, config); - DelegationServiceImpl delegationService = new DelegationServiceImpl(agreementController, monitor, httpClient, typeManager, config); - - // register endpoint /agent - AgentController agentController = new AgentController(monitor, agreementController, config, processor, skillStore, delegationService); - monitor.debug(String.format("Registering agent controller %s", agentController)); - webService.registerResource(DEFAULT_CONTEXT_ALIAS, agentController); - - // register endpoint /agentsource - //AgentSourceController agentSourceController = new AgentSourceController(monitor, config, processor, skillStore, delegationService); - //AgentSourceController agentSourceController = new AgentSourceController(monitor, config, processor, skillStore); - //monitor.debug(String.format("Registering agent source controller %s", agentSourceController)); - //webService.registerResource(DEFAULT_CONTEXT_ALIAS, agentSourceController); - - monitor.debug(String.format("Initialized %s", name())); - - // mho HttpRequestFactory httpRequestFactory = new HttpRequestFactory(); - // mho AgentSourceFactory sourceFactory = new AgentSourceFactory(edcHttpClient, new AgentSourceRequestParamsSupplier(vault, typeManager, config, monitor), monitor, httpRequestFactory, processor, skillStore); - // mho pipelineService.registerFactory(sourceFactory); - } - - /** - * start scheduled services - */ - @Override - public void start() { - synchronizer.start(); - } - - /** - * Signals the extension to release resources and shutdown. - * stop any schedules services - */ - @Override - public void shutdown() { - synchronizer.shutdown(); - } -} \ No newline at end of file diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientFactory.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientFactory.java deleted file mode 100644 index e8f08a61..00000000 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientFactory.java +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; - -import okhttp3.OkHttpClient; -import org.eclipse.edc.connector.dataplane.spi.pipeline.DataSourceFactory; -import org.eclipse.edc.connector.dataplane.spi.pipeline.PipelineService; -import org.eclipse.edc.spi.http.EdcHttpClient; -import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.jetbrains.annotations.NotNull; - -import java.lang.reflect.Field; -import java.util.AbstractMap; -import java.util.Collection; -import java.util.Map; -import java.util.Optional; - -/** - * Extended Http Client Factory which has configurable timeouts - */ -public class HttpClientFactory { - - protected static Class httpDataSourceFactory; - protected static Field sourceFactories; - protected static Field httpClient; - protected static Field okHttpClient; - protected static Field connectTimeoutMillis; - protected static Field callTimeoutMillis; - protected static Field readTimeoutMillis; - protected static Field writeTimeoutMillis; - protected static Field pingIntervalMillis; - - static { - try { - sourceFactories = HttpClientFactory.class.getClassLoader().loadClass("org.eclipse.edc.connector.dataplane.framework.pipeline.PipelineServiceImpl").getDeclaredField("sourceFactories"); - sourceFactories.setAccessible(true); - httpDataSourceFactory = HttpClientFactory.class.getClassLoader().loadClass("org.eclipse.edc.connector.dataplane.http.pipeline.HttpDataSourceFactory"); - httpClient = httpDataSourceFactory.getDeclaredField("httpClient"); - httpClient.setAccessible(true); - okHttpClient = HttpClientFactory.class.getClassLoader().loadClass("org.eclipse.edc.connector.core.base.EdcHttpClientImpl").getDeclaredField("okHttpClient"); - okHttpClient.setAccessible(true); - connectTimeoutMillis = OkHttpClient.class.getDeclaredField("connectTimeoutMillis"); - connectTimeoutMillis.setAccessible(true); - readTimeoutMillis = OkHttpClient.class.getDeclaredField("readTimeoutMillis"); - readTimeoutMillis.setAccessible(true); - writeTimeoutMillis = OkHttpClient.class.getDeclaredField("writeTimeoutMillis"); - writeTimeoutMillis.setAccessible(true); - pingIntervalMillis = OkHttpClient.class.getDeclaredField("pingIntervalMillis"); - pingIntervalMillis.setAccessible(true); - callTimeoutMillis = OkHttpClient.class.getDeclaredField("pingIntervalMillis"); - callTimeoutMillis.setAccessible(true); - } catch (ClassNotFoundException | NoSuchFieldException e) { - System.err.println("HttpClientFactory could not be initialised. Leaving default okhttp settings."); - } - } - - /** - * Create an modified OkHttpClient instance - * - * @param config agent config - * @param client parent/blueprint instance - * @return the modified OkHttpClient - */ - @NotNull - public static Map.Entry create(EdcHttpClient edcClient, OkHttpClient client, PipelineService service, AgentConfig config) { - Integer connectTimeout = config.getConnectTimeout(); - Integer readTimeout = config.getReadTimeout(); - Integer callTimeout = config.getCallTimeout(); - Integer writeTimeout = config.getWriteTimeout(); - - if (connectTimeout != null || readTimeout != null || callTimeout != null || writeTimeout != null) { - try { - edcClient = ((Collection) sourceFactories.get(service)).stream().flatMap(factory -> { - if (httpDataSourceFactory.equals(factory.getClass())) { - try { - return Optional.of((EdcHttpClient) httpClient.get(factory)).stream(); - } catch (IllegalArgumentException | IllegalAccessException e) { - System.err.println("HttpClientFactory could not reuse okhttp client."); - } - } - return Optional.empty().stream(); - } - ).findFirst().orElse(edcClient); - client = (OkHttpClient) okHttpClient.get(edcClient); - } catch (IllegalArgumentException | IllegalAccessException e) { - System.err.println("HttpClientFactory could not reuse okhttp client."); - } - if (connectTimeoutMillis != null && connectTimeout != null) { - try { - connectTimeoutMillis.set(client, connectTimeout); - } catch (IllegalArgumentException | IllegalAccessException e) { - System.err.println("HttpClientFactory could not set connectTimeout"); - } - } - if (readTimeoutMillis != null && readTimeout != null) { - try { - readTimeoutMillis.set(client, readTimeout); - } catch (IllegalArgumentException | IllegalAccessException e) { - System.err.println("HttpClientFactory could not set readTimeout"); - } - } - if (callTimeoutMillis != null && callTimeout != null) { - try { - callTimeoutMillis.set(client, callTimeout); - } catch (IllegalArgumentException | IllegalAccessException e) { - System.err.println("HttpClientFactory could not set callTimeout"); - } - } - if (writeTimeoutMillis != null && writeTimeout != null) { - try { - writeTimeoutMillis.set(client, writeTimeout); - } catch (IllegalArgumentException | IllegalAccessException e) { - System.err.println("HttpClientFactory could not set writeTimeout"); - } - } - } - return new AbstractMap.SimpleEntry(edcClient, client); - } - -} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceHttpParamsDecorator.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceHttpParamsDecorator.java deleted file mode 100644 index 1aeba9ab..00000000 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceHttpParamsDecorator.java +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http.transfer; - -import org.eclipse.edc.connector.dataplane.http.spi.HttpParamsDecorator; -import org.eclipse.edc.connector.dataplane.http.spi.HttpRequestParams; -import org.eclipse.edc.spi.EdcException; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.types.domain.HttpDataAddress; -import org.eclipse.edc.spi.types.domain.transfer.DataFlowRequest; -import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.eclipse.tractusx.agents.edc.http.HttpUtils; -import org.eclipse.tractusx.agents.edc.sparql.DataspaceServiceExecutor; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -/** - * Decorator to implement specifics of the http-based Agent transfer protocol. - * In particular the translation back from transfer to matchmaking. - * should be placed instead of {@see org.eclipse.edc.connector.dataplane.http.params.decorators.BaseSourceHttpParamsDecorator} - */ -public class AgentSourceHttpParamsDecorator implements HttpParamsDecorator { - - /** - * static constants - */ - public static final String ASSET_PROP_ID = "https://w3id.org/edc/v0.0.1/ns/id"; - public static final String ACCEPT_HEADER = "https://w3id.org/catenax/ontology/common#acceptsContentType"; - public static final String QUERY_PARAMS = "queryParams"; - public static final String QUERY_PARAM = "query"; - public static final String METHOD = "method"; - public static final String DEFAULT_METHOD = "GET"; - public static final String PATH_SEGMENTS = "pathSegments"; - public static final String BASE_URL = "https://w3id.org/edc/v0.0.1/ns/baseUrl"; - public static final String BODY = "body"; - public static final String MEDIA_TYPE = "mediaType"; - public static final String SLASH = "/"; - - public static final String CX_ACCEPT_PARAM = "cx_accept"; - - public static final String DEFAULT_ACCEPT = "*/*"; - /** - * regexes to extract url-encoded form and query parts - */ - public static final String PARAM_GROUP = "param"; - public static final String VALUE_GROUP = "value"; - - - public static final Pattern PARAMS = Pattern.compile(String.format("(\\?|&)(?<%s>[^=&]+)=(?<%s>[^=&]*)", PARAM_GROUP, VALUE_GROUP)); - - public static final String WWW_FORM_ENCODED = "application/x-www-form-urlencoded"; - - public static final String SPARQL_QUERY = "application/sparql-query"; - - public static final String CONTENT_TYPE_DISPOSITION = "q=[0-9]+(\\.[0-9]+)?, "; - - /** - * service references - */ - protected final AgentConfig config; - protected final Monitor monitor; - - /** - * creates a new decorator - * - * @param config agent configuration - * @param monitor logging facility - */ - public AgentSourceHttpParamsDecorator(AgentConfig config, Monitor monitor) { - this.config = config; - this.monitor = monitor; - } - - /** - * check whether this is a transfer or a source request - * - * @param dataflowRequest the request to check - * @return if this is a transfer request - */ - public static boolean isTransferRequest(DataFlowRequest dataflowRequest) { - return false; - } - - /** - * parse the body or parameter string as a url-encoded form into a map - * - * @param body url-encoded form body - * @return a map of parameters - */ - public static Map> parseParams(String body) { - Map> parts = new HashMap<>(); - if (body != null) { - Matcher matcher = PARAMS.matcher(body); - while (matcher.find()) { - String paramName = matcher.group(PARAM_GROUP); - List partSet = parts.computeIfAbsent(paramName, k -> new ArrayList<>()); - partSet.add(matcher.group(VALUE_GROUP)); - } - } - return parts; - } - - public static Map> mergeParams(Map> param1, Map> param2) { - param2.forEach((key, value) -> { - if (param1.containsKey(key)) { - param1.get(key).addAll(value); - } else { - param1.put(key, value); - } - }); - return param1; - } - - /** - * Implements the decoration - * - * @param request transfer request (contains dynamic stuff) - * @param address target address (contains static stuff) - * @param params translated call content (up to now) - * @return translated call content (identical to params) - */ - @Override - public HttpRequestParams.Builder decorate(DataFlowRequest request, HttpDataAddress address, HttpRequestParams.Builder params) { - String contentType = this.extractContentType(address, request); - String body = this.extractBody(address, request); - Map> queryParams = parseParams("?" + getRequestQueryParams(address, request)); - - if (isTransferRequest(request)) { - if (!address.getStringProperty(BASE_URL).endsWith(SLASH)) { - params.baseUrl(address.getStringProperty(BASE_URL) + SLASH); - } - } else { - // we need to annotate the base url "pure" because we do not directly hit the endpoint - params.baseUrl("https://w3id.org/catenax"); - params.header(DataspaceServiceExecutor.TARGET_URL_SYMBOL.getSymbol(), address.getStringProperty(BASE_URL)); - - // there is the case where a KA-BIND protocol call is - // one-to-one routed through the transfer plane ... in which case - // we may get query parameters in the body - // in this case we leave the query in the body (and rewriting the content type) - if (contentType != null && contentType.contains(WWW_FORM_ENCODED)) { - Map> bodyParams = parseParams("&" + body); - contentType = SPARQL_QUERY; - List queries = queryParams.getOrDefault(QUERY_PARAM, bodyParams.getOrDefault(QUERY_PARAM, List.of())); - if (queries.size() != 1) { - throw new EdcException(String.format("DataFlowRequest %s: found %d queries when contentType %s is used", request.getId(), queries.size(), WWW_FORM_ENCODED)); - } - body = HttpUtils.urlDecodeParameter(queries.get(0)); - bodyParams.remove(QUERY_PARAM); - queryParams.remove(QUERY_PARAM); - mergeParams(queryParams, bodyParams); - } - String accept = address.getStringProperty(ACCEPT_HEADER, null); - List cxAccepts = queryParams.getOrDefault(CX_ACCEPT_PARAM, List.of()); - queryParams.remove(CX_ACCEPT_PARAM); - if (accept == null) { - accept = cxAccepts.stream().findFirst().orElse(DEFAULT_ACCEPT); - } - accept = accept.replace(CONTENT_TYPE_DISPOSITION, "").replace("%2F", "/"); - params.header("Accept", accept); - } - Map> addressParams = parseParams("?" + address.getQueryParams()); - mergeParams(queryParams, addressParams); - String paramString = queryParams.entrySet().stream().flatMap((param) -> param.getValue().stream().map((value) -> param.getKey() + "=" + value)).collect(Collectors.joining("&")); - params.queryParams(!paramString.isEmpty() ? paramString : null); - params.method(this.extractMethod(address, request)); - params.path(this.extractPath(address, request)); - if (contentType != null) { - params.contentType(contentType); - } - params.body(body); - params.nonChunkedTransfer(false); - return params; - } - - protected @NotNull String extractMethod(HttpDataAddress address, DataFlowRequest request) { - if (Boolean.parseBoolean(address.getProxyMethod())) { - return Optional.ofNullable(request.getProperties().get(METHOD)).orElseThrow(() -> new EdcException(String.format("DataFlowRequest %s: 'method' property is missing", request.getId()))); - } else { - return Optional.ofNullable(address.getMethod()).orElse(DEFAULT_METHOD); - } - } - - protected @Nullable String extractPath(HttpDataAddress address, DataFlowRequest request) { - return Boolean.parseBoolean(address.getProxyPath()) ? request.getProperties().get(PATH_SEGMENTS) : address.getPath(); - } - - protected @Nullable String getRequestQueryParams(HttpDataAddress address, DataFlowRequest request) { - return Boolean.parseBoolean(address.getProxyQueryParams()) ? request.getProperties().get(QUERY_PARAMS) : null; - } - - /** - * extract the content type - * - * @param address target address - * @param request data flow request - * @return the content type (which would be derived from the query language part in case the original content type is a url-encoded form) - */ - protected @Nullable String extractContentType(HttpDataAddress address, DataFlowRequest request) { - String contentType = Boolean.parseBoolean(address.getProxyBody()) ? request.getProperties().get(MEDIA_TYPE) : address.getContentType(); - return contentType; - } - - protected @Nullable String extractBody(HttpDataAddress address, DataFlowRequest request) { - return Boolean.parseBoolean(address.getProxyBody()) ? request.getProperties().get(BODY) : null; - } -} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceRequestParamsSupplier.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceRequestParamsSupplier.java deleted file mode 100644 index bb554e95..00000000 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceRequestParamsSupplier.java +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http.transfer; - -import org.eclipse.edc.connector.dataplane.http.params.decorators.BaseCommonHttpParamsDecorator; -import org.eclipse.edc.connector.dataplane.http.params.decorators.BaseSinkHttpParamsDecorator; -import org.eclipse.edc.connector.dataplane.http.spi.HttpParamsDecorator; -import org.eclipse.edc.connector.dataplane.http.spi.HttpRequestParams; -import org.eclipse.edc.connector.dataplane.http.spi.HttpRequestParamsProvider; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.security.Vault; -import org.eclipse.edc.spi.types.TypeManager; -import org.eclipse.edc.spi.types.domain.HttpDataAddress; -import org.eclipse.edc.spi.types.domain.transfer.DataFlowRequest; -import org.eclipse.tractusx.agents.edc.AgentConfig; - -import java.util.ArrayList; -import java.util.List; - - -/** - * request params supplier which correctly double encodes - * valid url symbols in the parameter section, extracts - * original headers like accept from special parameters and caters for - * translating url-encoded form bodies into their - * "normal" param+body form - */ -public class AgentSourceRequestParamsSupplier implements HttpRequestParamsProvider { - protected final List sourceDecorators = new ArrayList<>(); - protected final List sinkDecorators = new ArrayList<>(); - - /** - * the edc config section - */ - protected final AgentConfig config; - - /** - * logging subsystem - */ - protected Monitor monitor; - - /** - * creates a supplier - * - * @param vault secret host - * @param config edc config section - * @param monitor logging reference - */ - public AgentSourceRequestParamsSupplier(Vault vault, TypeManager typeManager, AgentConfig config, Monitor monitor) { - BaseCommonHttpParamsDecorator commonHttpParamsDecorator = new BaseCommonHttpParamsDecorator(vault, typeManager); - this.registerSinkDecorator(commonHttpParamsDecorator); - this.registerSourceDecorator(commonHttpParamsDecorator); - this.registerSourceDecorator(new AgentSourceHttpParamsDecorator(config, monitor)); - this.registerSinkDecorator(new BaseSinkHttpParamsDecorator()); - this.config = config; - this.monitor = monitor; - } - - @Override - public void registerSourceDecorator(HttpParamsDecorator decorator) { - this.sourceDecorators.add(decorator); - } - - @Override - public void registerSinkDecorator(HttpParamsDecorator decorator) { - this.sinkDecorators.add(decorator); - } - - @Override - public HttpRequestParams provideSourceParams(DataFlowRequest request) { - HttpRequestParams.Builder params = HttpRequestParams.Builder.newInstance(); - HttpDataAddress address = org.eclipse.edc.spi.types.domain.HttpDataAddress.Builder.newInstance().copyFrom(request.getSourceDataAddress()).build(); - this.sourceDecorators.forEach((decorator) -> decorator.decorate(request, address, params)); - return params.build(); - } - - @Override - public HttpRequestParams provideSinkParams(DataFlowRequest request) { - HttpRequestParams.Builder params = HttpRequestParams.Builder.newInstance(); - HttpDataAddress address = org.eclipse.edc.spi.types.domain.HttpDataAddress.Builder.newInstance().copyFrom(request.getDestinationDataAddress()).build(); - this.sinkDecorators.forEach((decorator) -> decorator.decorate(request, address, params)); - return params.build(); - } -} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentController.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/AgentController.java similarity index 97% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentController.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/AgentController.java index b1cde041..12c0d603 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentController.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/AgentController.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; +package org.eclipse.tractusx.agents.http; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -30,16 +30,16 @@ import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.UriInfo; import org.apache.http.HttpStatus; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.eclipse.tractusx.agents.edc.AgentExtension; -import org.eclipse.tractusx.agents.edc.AgreementController; -import org.eclipse.tractusx.agents.edc.SkillDistribution; -import org.eclipse.tractusx.agents.edc.SkillStore; -import org.eclipse.tractusx.agents.edc.sparql.SparqlQueryProcessor; +import org.eclipse.tractusx.agents.AgentConfig; +import org.eclipse.tractusx.agents.AgreementController; +import org.eclipse.tractusx.agents.SkillDistribution; +import org.eclipse.tractusx.agents.SkillStore; +import org.eclipse.tractusx.agents.sparql.SparqlQueryProcessor; +import org.eclipse.tractusx.agents.utils.Monitor; import java.util.Optional; import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * The Agent Controller exposes a REST API endpoint @@ -62,6 +62,8 @@ public class AgentController { // the actual Matchmaking Agent is a Fuseki engine protected final SparqlQueryProcessor processor; protected final DelegationService delegationService; + + public static final Pattern GRAPH_PATTERN = Pattern.compile("((?[^#]+)#)?(?.*Graph(Asset)?.*)"); /** * creates a new agent controller @@ -379,7 +381,7 @@ public Response executeQuery(String asset, HttpHeaders headers, HttpServletReque String remoteUrl = null; if (asset != null) { - Matcher matcher = AgentExtension.GRAPH_PATTERN.matcher(asset); + Matcher matcher = GRAPH_PATTERN.matcher(asset); if (matcher.matches()) { remoteUrl = matcher.group("url"); graph = matcher.group("graph"); diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentHttpAction.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/AgentHttpAction.java similarity index 98% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentHttpAction.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/AgentHttpAction.java index 4c802ce1..594ac1d9 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/AgentHttpAction.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/AgentHttpAction.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; +package org.eclipse.tractusx.agents.http; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -22,7 +22,7 @@ import org.apache.http.HttpStatus; import org.apache.jena.fuseki.servlets.HttpAction; import org.apache.jena.fuseki.system.ActionCategory; -import org.eclipse.tractusx.agents.edc.TupleSet; +import org.eclipse.tractusx.agents.TupleSet; import org.slf4j.Logger; import java.net.URLDecoder; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationResponse.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/DelegationResponse.java similarity index 97% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationResponse.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/DelegationResponse.java index 3d691b5b..a269481f 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationResponse.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/DelegationResponse.java @@ -15,7 +15,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; +package org.eclipse.tractusx.agents.http; import jakarta.ws.rs.core.Response; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationService.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/DelegationService.java similarity index 97% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationService.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/DelegationService.java index 6bdd4237..45b0ec15 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationService.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/DelegationService.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; +package org.eclipse.tractusx.agents.http; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationServiceImpl.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/DelegationServiceImpl.java similarity index 97% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationServiceImpl.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/DelegationServiceImpl.java index 16d9d2c2..4daff70f 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/DelegationServiceImpl.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/DelegationServiceImpl.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; +package org.eclipse.tractusx.agents.http; import com.fasterxml.jackson.core.type.TypeReference; import jakarta.servlet.http.HttpServletRequest; @@ -28,12 +28,12 @@ import okhttp3.OkHttpClient; import org.apache.commons.io.IOUtils; import org.apache.http.HttpStatus; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.types.TypeManager; -import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; -import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.eclipse.tractusx.agents.edc.AgreementController; -import org.eclipse.tractusx.agents.edc.sparql.CatenaxWarning; +import org.eclipse.tractusx.agents.AgentConfig; +import org.eclipse.tractusx.agents.AgreementController; +import org.eclipse.tractusx.agents.sparql.CatenaxWarning; +import org.eclipse.tractusx.agents.utils.EndpointDataReference; +import org.eclipse.tractusx.agents.utils.Monitor; +import org.eclipse.tractusx.agents.utils.TypeManager; import java.io.BufferedInputStream; import java.io.BufferedReader; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/GraphController.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/GraphController.java similarity index 94% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/GraphController.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/GraphController.java index 5a452044..cd90ae4c 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/GraphController.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/GraphController.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; +package org.eclipse.tractusx.agents.http; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -29,11 +29,11 @@ import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response.ResponseBuilder; import jakarta.ws.rs.core.UriInfo; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.eclipse.tractusx.agents.edc.rdf.ExternalFormat; -import org.eclipse.tractusx.agents.edc.rdf.RdfStore; -import org.eclipse.tractusx.agents.edc.service.DataManagement; +import org.eclipse.tractusx.agents.AgentConfig; +import org.eclipse.tractusx.agents.rdf.ExternalFormat; +import org.eclipse.tractusx.agents.rdf.RdfStore; +import org.eclipse.tractusx.agents.service.DataManagement; +import org.eclipse.tractusx.agents.utils.Monitor; import java.io.IOException; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientAdapter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/HttpClientAdapter.java similarity index 99% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientAdapter.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/HttpClientAdapter.java index fdde30e7..843784e8 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpClientAdapter.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/HttpClientAdapter.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; +package org.eclipse.tractusx.agents.http; import okhttp3.Call; import okhttp3.MediaType; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpResponseAdapter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/HttpResponseAdapter.java similarity index 98% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpResponseAdapter.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/HttpResponseAdapter.java index 34b500b6..ef7ae903 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpResponseAdapter.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/HttpResponseAdapter.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; +package org.eclipse.tractusx.agents.http; import okhttp3.Response; import okhttp3.ResponseBody; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletContextAdapter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/HttpServletContextAdapter.java similarity index 99% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletContextAdapter.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/HttpServletContextAdapter.java index decd58a2..b41ccf4b 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletContextAdapter.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/HttpServletContextAdapter.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; +package org.eclipse.tractusx.agents.http; import okhttp3.Request; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletRequestAdapter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/HttpServletRequestAdapter.java similarity index 99% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletRequestAdapter.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/HttpServletRequestAdapter.java index a0c71696..8132cbf4 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletRequestAdapter.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/HttpServletRequestAdapter.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; +package org.eclipse.tractusx.agents.http; import okhttp3.Request; import okio.Buffer; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletResponseAdapter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/HttpServletResponseAdapter.java similarity index 99% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletResponseAdapter.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/HttpServletResponseAdapter.java index 7a6733bb..2283c123 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpServletResponseAdapter.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/HttpServletResponseAdapter.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; +package org.eclipse.tractusx.agents.http; import okhttp3.MediaType; import okhttp3.Protocol; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpUtils.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/HttpUtils.java similarity index 98% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpUtils.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/HttpUtils.java index dfcfb02e..b685ae2f 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/HttpUtils.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/HttpUtils.java @@ -14,11 +14,11 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; +package org.eclipse.tractusx.agents.http; import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.Response; -import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.tractusx.agents.utils.Monitor; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaAdapter.java similarity index 97% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapter.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaAdapter.java index 46772340..ff489ac9 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapter.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaAdapter.java @@ -14,9 +14,9 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; +package org.eclipse.tractusx.agents.http; -import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.tractusx.agents.utils.Monitor; import java.lang.reflect.Proxy; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapterImpl.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaAdapterImpl.java similarity index 95% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapterImpl.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaAdapterImpl.java index 0b38ae6f..a7f11266 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaAdapterImpl.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaAdapterImpl.java @@ -14,9 +14,9 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; +package org.eclipse.tractusx.agents.http; -import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.tractusx.agents.utils.Monitor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletInputStreamAdapter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaServletInputStreamAdapter.java similarity index 96% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletInputStreamAdapter.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaServletInputStreamAdapter.java index c624c373..b17e2f4d 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletInputStreamAdapter.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaServletInputStreamAdapter.java @@ -14,10 +14,10 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; +package org.eclipse.tractusx.agents.http; import jakarta.servlet.ServletInputStream; -import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.tractusx.agents.utils.Monitor; import org.jetbrains.annotations.NotNull; import java.io.IOException; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletOutputStreamAdapter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaServletOutputStreamAdapter.java similarity index 95% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletOutputStreamAdapter.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaServletOutputStreamAdapter.java index 1b694772..06469130 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/JakartaServletOutputStreamAdapter.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaServletOutputStreamAdapter.java @@ -14,10 +14,10 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; +package org.eclipse.tractusx.agents.http; import jakarta.servlet.ServletOutputStream; -import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.tractusx.agents.utils.Monitor; import org.jetbrains.annotations.NotNull; import java.io.IOException; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletInputStreamDelegator.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/ServletInputStreamDelegator.java similarity index 98% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletInputStreamDelegator.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/ServletInputStreamDelegator.java index d72936ae..2113559f 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletInputStreamDelegator.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/ServletInputStreamDelegator.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; +package org.eclipse.tractusx.agents.http; import java.io.IOException; import java.io.InputStream; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletOutputStreamDelegator.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/ServletOutputStreamDelegator.java similarity index 97% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletOutputStreamDelegator.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/ServletOutputStreamDelegator.java index 47ef06df..9f1de572 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/ServletOutputStreamDelegator.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/ServletOutputStreamDelegator.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http; +package org.eclipse.tractusx.agents.http; import java.io.IOException; import java.io.OutputStream; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceController.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/transfer/AgentSourceController.java similarity index 87% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceController.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/transfer/AgentSourceController.java index 80c0356b..a58ac4e6 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceController.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/transfer/AgentSourceController.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http.transfer; +package org.eclipse.tractusx.agents.http.transfer; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; @@ -34,19 +34,19 @@ import org.apache.jena.query.Syntax; import org.apache.jena.sparql.serializer.SerializerRegistry; import org.apache.jena.sparql.service.ServiceExecutorRegistry; -import org.eclipse.edc.spi.monitor.ConsoleMonitor; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.system.configuration.Config; -import org.eclipse.edc.spi.system.configuration.ConfigFactory; -import org.eclipse.edc.spi.types.TypeManager; -import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.eclipse.tractusx.agents.edc.SkillStore; -import org.eclipse.tractusx.agents.edc.http.HttpUtils; -import org.eclipse.tractusx.agents.edc.rdf.RdfStore; -import org.eclipse.tractusx.agents.edc.service.DataManagementImpl; -import org.eclipse.tractusx.agents.edc.service.EdcSkillStore; -import org.eclipse.tractusx.agents.edc.sparql.SparqlQueryProcessor; -import org.eclipse.tractusx.agents.edc.sparql.SparqlQuerySerializerFactory; +import org.eclipse.tractusx.agents.AgentConfig; +import org.eclipse.tractusx.agents.SkillStore; +import org.eclipse.tractusx.agents.http.HttpUtils; +import org.eclipse.tractusx.agents.rdf.RdfStore; +import org.eclipse.tractusx.agents.service.DataManagementImpl; +import org.eclipse.tractusx.agents.service.EdcSkillStore; +import org.eclipse.tractusx.agents.sparql.SparqlQueryProcessor; +import org.eclipse.tractusx.agents.sparql.SparqlQuerySerializerFactory; +import org.eclipse.tractusx.agents.utils.Config; +import org.eclipse.tractusx.agents.utils.ConfigFactory; +import org.eclipse.tractusx.agents.utils.ConsoleMonitor; +import org.eclipse.tractusx.agents.utils.Monitor; +import org.eclipse.tractusx.agents.utils.TypeManager; import java.io.IOException; import java.util.HashMap; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceServlet.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/transfer/AgentSourceServlet.java similarity index 96% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceServlet.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/http/transfer/AgentSourceServlet.java index 33249c8b..e2e4100a 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/http/transfer/AgentSourceServlet.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/transfer/AgentSourceServlet.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.http.transfer; +package org.eclipse.tractusx.agents.http.transfer; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; @@ -26,9 +26,9 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.tractusx.agents.conforming.SharedObjectManager; -import org.eclipse.tractusx.agents.edc.sparql.SparqlQueryProcessor; +import org.eclipse.tractusx.agents.matchmaking.SharedObjectManager; +import org.eclipse.tractusx.agents.sparql.SparqlQueryProcessor; +import org.eclipse.tractusx.agents.utils.Monitor; import java.io.IOException; import java.net.URLDecoder; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLd.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/jsonld/JsonLd.java similarity index 93% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLd.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/jsonld/JsonLd.java index 676296f4..07f8a82a 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLd.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/jsonld/JsonLd.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.jsonld; +package org.eclipse.tractusx.agents.jsonld; import jakarta.json.Json; import jakarta.json.JsonArray; @@ -24,12 +24,12 @@ import jakarta.json.JsonObjectBuilder; import jakarta.json.JsonString; import jakarta.json.JsonValue; -import org.eclipse.tractusx.agents.edc.model.Asset; -import org.eclipse.tractusx.agents.edc.model.ContractAgreement; -import org.eclipse.tractusx.agents.edc.model.ContractNegotiation; -import org.eclipse.tractusx.agents.edc.model.DcatCatalog; -import org.eclipse.tractusx.agents.edc.model.IdResponse; -import org.eclipse.tractusx.agents.edc.model.TransferProcess; +import org.eclipse.tractusx.agents.model.Asset; +import org.eclipse.tractusx.agents.model.ContractAgreement; +import org.eclipse.tractusx.agents.model.ContractNegotiation; +import org.eclipse.tractusx.agents.model.DcatCatalog; +import org.eclipse.tractusx.agents.model.IdResponse; +import org.eclipse.tractusx.agents.model.TransferProcess; import java.io.StringReader; import java.util.HashMap; @@ -37,6 +37,7 @@ import java.util.Map; import java.util.stream.Collectors; + /** * base facility to deal with EDC specific JSONLD structures */ diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLdObject.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/jsonld/JsonLdObject.java similarity index 96% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLdObject.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/jsonld/JsonLdObject.java index cbf98831..c0fe8cdc 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/jsonld/JsonLdObject.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/jsonld/JsonLdObject.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.jsonld; +package org.eclipse.tractusx.agents.jsonld; import jakarta.json.JsonObject; import jakarta.json.JsonValue; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/Bootstrap.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/matchmaking/Bootstrap.java similarity index 80% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/Bootstrap.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/matchmaking/Bootstrap.java index 33b3bfb6..548a0131 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/Bootstrap.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/matchmaking/Bootstrap.java @@ -14,22 +14,20 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming; +package org.eclipse.tractusx.agents.matchmaking; import io.swagger.v3.oas.annotations.OpenAPIDefinition; import io.swagger.v3.oas.annotations.info.Contact; import io.swagger.v3.oas.annotations.info.Info; import io.swagger.v3.oas.annotations.info.License; -import org.eclipse.edc.spi.monitor.Monitor; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.tractusx.agents.conforming.api.JsonProvider; -import org.eclipse.tractusx.agents.conforming.api.SparqlProvider; -import org.eclipse.tractusx.agents.conforming.api.XmlProvider; -import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.eclipse.tractusx.agents.edc.http.transfer.AgentSourceServlet; -import org.glassfish.jersey.media.multipart.MultiPartFeature; +import org.eclipse.tractusx.agents.AgentConfig; +import org.eclipse.tractusx.agents.http.transfer.AgentSourceServlet; +import org.eclipse.tractusx.agents.utils.Monitor; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.servlet.ServletContainer; import sun.misc.Signal; @@ -63,77 +61,74 @@ public Bootstrap() { handleSignal("TERM"); SharedObjectManager sharedObjectManager = SharedObjectManager.getInstance(); this.monitor = sharedObjectManager.getMonitor(); - ResourceConfig internalServerConfig = new ResourceConfig(); + + // Create Jetty server + Server server = new Server(); + HandlerCollection handlerList = new HandlerCollection(); + server.setHandler(handlerList); + + // For AgentSourceController endpoint (internal endpoints) AgentConfig conf = sharedObjectManager.getAgentConfig(); - internalServerConfig.register(AgentSourceServlet.class); - monitor.debug(String.format("Registering %s", "AgentSourceController Constructor")); - - // For AgentSource endpoint accessed by data plane - int port = conf.getMatchmakingPortInternal(); - monitor.debug(String.format("Starting servver on port %s", port)); - internalServer = new Server(port); - ServletContextHandler internalContext = new ServletContextHandler(ServletContextHandler.SESSIONS); - internalContext.setContextPath("/"); - internalServer.setHandler(internalContext); - internalContext.addServlet(AgentSourceServlet.class, "/agentsource"); - + int port1 = conf.getMatchmakingPort(); + monitor.debug(String.format("Configuring server on port %s", port1)); + ServletContextHandler handler1 = new ServletContextHandler(ServletContextHandler.SESSIONS); + handler1.setContextPath("/"); + ResourceConfig resourceConfig1 = new ResourceConfig(); + monitor.debug(String.format("Registering %s", "AgentSourceController Constructor")); + resourceConfig1.register(AgentSourceServlet.class); + handler1.addServlet(AgentSourceServlet.class, conf.getMatchmakingPath()); + ServerConnector connector1 = new ServerConnector(server); + connector1.setPort(port1); + connector1.setName("conn1"); + handler1.setVirtualHosts(new String[]{"@conn1"}); + handlerList.addHandler(handler1); + server.addConnector(connector1); + // For AgentController and GraphController endpoints (public endpoints) - ServletContextHandler handler = new ServletContextHandler(ServletContextHandler.SESSIONS); - handler.setContextPath("/api"); - ResourceConfig resourceConfig = new ResourceConfig(); - resourceConfig.packages("io.catenax.knowledge.agents.conforming"); - resourceConfig.register(JsonProvider.class); - resourceConfig.register(XmlProvider.class); - resourceConfig.register(SparqlProvider.class); - resourceConfig.register(BindingAgent.class); - resourceConfig.register(TransferAgent.class); - resourceConfig.register(MatchmakingAgent.class); - resourceConfig.packages("org.glassfish.jersey.examples.multipart"); - resourceConfig.register(MultiPartFeature.class); - monitor.debug(String.format("Registering agreement controller %s", sharedObjectManager.getAgreementController())); - resourceConfig.register(sharedObjectManager.getAgreementController()); + int port2 = conf.getDefaultPort(); + monitor.debug(String.format("Configuring server on port %s", port2)); + ServletContextHandler handler2 = new ServletContextHandler(ServletContextHandler.SESSIONS); + handler2.setContextPath(conf.getDefaultPath()); + ResourceConfig resourceConfig2 = new ResourceConfig(); monitor.debug("registering AgentController"); - resourceConfig.register(sharedObjectManager.getAgentController()); + resourceConfig2.register(sharedObjectManager.getAgentController()); monitor.debug("registering GraphController"); - resourceConfig.register(sharedObjectManager.getGraphController()); - handler.addServlet(new ServletHolder(new ServletContainer(resourceConfig)), "/*"); - externalServer = new Server(8280); - externalServer.setHandler(handler); - - // Start the external server - Thread externalServerThread = new Thread(() -> { - monitor.debug("Trying to start external server"); - try { - externalServer.start(); - externalServer.join(); - } catch (Exception e) { - e.printStackTrace(); - } - }); - - // Start the internal server - Thread internalServerThread = new Thread(() -> { - monitor.debug("Trying to start internal server"); - try { - internalServer.start(); - internalServer.join(); - } catch (Exception e) { - e.printStackTrace(); - } - }); - - // Start both servers concurrently - externalServerThread.start(); - internalServerThread.start(); + resourceConfig2.register(sharedObjectManager.getGraphController()); + handler2.addServlet(new ServletHolder(new ServletContainer(resourceConfig2)), "/*"); + ServerConnector connector2 = new ServerConnector(server); + connector2.setPort(port2); + connector2.setName("conn2"); + handler2.setVirtualHosts(new String[]{"@conn2"}); + handlerList.addHandler(handler2); + server.addConnector(connector2); + + // For AgreementController endpoint (callback endpoint between control plane and matchmaking agent) + int port3 = conf.getCallbackPort(); + monitor.debug(String.format("Configuring server on port %s", port3)); + ServletContextHandler handler3 = new ServletContextHandler(ServletContextHandler.SESSIONS); + handler3.setContextPath(conf.getCallbacktPath()); + ResourceConfig resourceConfig3 = new ResourceConfig(); + monitor.debug(String.format("Registering agreement controller %s", sharedObjectManager.getAgreementController())); + resourceConfig3.register(sharedObjectManager.getAgreementController()); + handler3.addServlet(new ServletHolder(new ServletContainer(resourceConfig3)), "/*"); + ServerConnector connector3 = new ServerConnector(server); + connector3.setPort(port3); + connector3.setName("conn3"); + handler3.setVirtualHosts(new String[]{"@conn3"}); + handlerList.addHandler(handler3); + server.addConnector(connector3); - // Wait for both server threads to finish + // Start the server + monitor.debug("Trying to start the server"); try { - externalServerThread.join(); - internalServerThread.join(); - } catch (InterruptedException e) { + server.start(); + server.join(); + } catch (Exception e) { e.printStackTrace(); } + + } /** diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/SharedObjectManager.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/matchmaking/SharedObjectManager.java similarity index 85% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/SharedObjectManager.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/matchmaking/SharedObjectManager.java index 5aa719af..2b6932df 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/conforming/SharedObjectManager.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/matchmaking/SharedObjectManager.java @@ -15,7 +15,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming; +package org.eclipse.tractusx.agents.matchmaking; import com.google.gson.Gson; import okhttp3.OkHttpClient; @@ -23,24 +23,24 @@ import org.apache.jena.query.Syntax; import org.apache.jena.sparql.serializer.SerializerRegistry; import org.apache.jena.sparql.service.ServiceExecutorRegistry; -import org.eclipse.edc.spi.monitor.ConsoleMonitor; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.system.configuration.Config; -import org.eclipse.edc.spi.system.configuration.ConfigFactory; -import org.eclipse.edc.spi.types.TypeManager; -import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.eclipse.tractusx.agents.edc.AgreementControllerImpl; -import org.eclipse.tractusx.agents.edc.SkillStore; -import org.eclipse.tractusx.agents.edc.http.AgentController; -import org.eclipse.tractusx.agents.edc.http.DelegationServiceImpl; -import org.eclipse.tractusx.agents.edc.http.GraphController; -import org.eclipse.tractusx.agents.edc.rdf.RdfStore; -import org.eclipse.tractusx.agents.edc.service.DataManagementImpl; -import org.eclipse.tractusx.agents.edc.service.DataspaceSynchronizer; -import org.eclipse.tractusx.agents.edc.service.EdcSkillStore; -import org.eclipse.tractusx.agents.edc.sparql.DataspaceServiceExecutor; -import org.eclipse.tractusx.agents.edc.sparql.SparqlQueryProcessor; -import org.eclipse.tractusx.agents.edc.sparql.SparqlQuerySerializerFactory; +import org.eclipse.tractusx.agents.AgentConfig; +import org.eclipse.tractusx.agents.AgreementControllerImpl; +import org.eclipse.tractusx.agents.SkillStore; +import org.eclipse.tractusx.agents.http.AgentController; +import org.eclipse.tractusx.agents.http.DelegationServiceImpl; +import org.eclipse.tractusx.agents.http.GraphController; +import org.eclipse.tractusx.agents.rdf.RdfStore; +import org.eclipse.tractusx.agents.service.DataManagementImpl; +import org.eclipse.tractusx.agents.service.DataspaceSynchronizer; +import org.eclipse.tractusx.agents.service.EdcSkillStore; +import org.eclipse.tractusx.agents.sparql.DataspaceServiceExecutor; +import org.eclipse.tractusx.agents.sparql.SparqlQueryProcessor; +import org.eclipse.tractusx.agents.sparql.SparqlQuerySerializerFactory; +import org.eclipse.tractusx.agents.utils.Config; +import org.eclipse.tractusx.agents.utils.ConfigFactory; +import org.eclipse.tractusx.agents.utils.ConsoleMonitor; +import org.eclipse.tractusx.agents.utils.Monitor; +import org.eclipse.tractusx.agents.utils.TypeManager; import java.io.FileInputStream; import java.io.IOException; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/Asset.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/Asset.java similarity index 93% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/Asset.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/model/Asset.java index 890aefcd..72afe1a7 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/Asset.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/Asset.java @@ -14,11 +14,11 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.model; +package org.eclipse.tractusx.agents.model; import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import org.eclipse.tractusx.agents.edc.jsonld.JsonLdObject; +import org.eclipse.tractusx.agents.jsonld.JsonLdObject; import java.util.Map; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractAgreement.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/ContractAgreement.java similarity index 91% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractAgreement.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/model/ContractAgreement.java index 40160873..77434616 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractAgreement.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/ContractAgreement.java @@ -14,10 +14,11 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.model; +package org.eclipse.tractusx.agents.model; import jakarta.json.JsonObject; -import org.eclipse.tractusx.agents.edc.jsonld.JsonLdObject; +import org.eclipse.tractusx.agents.jsonld.JsonLdObject; + public class ContractAgreement extends JsonLdObject { diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiation.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/ContractNegotiation.java similarity index 92% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiation.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/model/ContractNegotiation.java index 8494ac8d..0b32ff15 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiation.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/ContractNegotiation.java @@ -14,10 +14,10 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.model; +package org.eclipse.tractusx.agents.model; import jakarta.json.JsonObject; -import org.eclipse.tractusx.agents.edc.jsonld.JsonLdObject; +import org.eclipse.tractusx.agents.jsonld.JsonLdObject; /** * Result of a contract negotiation diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiationRequest.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/ContractNegotiationRequest.java similarity index 98% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiationRequest.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/model/ContractNegotiationRequest.java index 2752ecdf..fa18732b 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractNegotiationRequest.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/ContractNegotiationRequest.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.model; +package org.eclipse.tractusx.agents.model; public class ContractNegotiationRequest { diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractOfferDescription.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/ContractOfferDescription.java similarity index 96% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractOfferDescription.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/model/ContractOfferDescription.java index 88a6f9ad..1a82b76e 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/ContractOfferDescription.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/ContractOfferDescription.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.model; +package org.eclipse.tractusx.agents.model; public class ContractOfferDescription { private final String offerId; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatCatalog.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/DcatCatalog.java similarity index 94% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatCatalog.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/model/DcatCatalog.java index 34119314..42c13972 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatCatalog.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/DcatCatalog.java @@ -14,11 +14,11 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.model; +package org.eclipse.tractusx.agents.model; import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import org.eclipse.tractusx.agents.edc.jsonld.JsonLdObject; +import org.eclipse.tractusx.agents.jsonld.JsonLdObject; import java.util.ArrayList; import java.util.List; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatDataset.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/DcatDataset.java similarity index 94% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatDataset.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/model/DcatDataset.java index 4d27dfd3..b302982a 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/DcatDataset.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/DcatDataset.java @@ -14,11 +14,11 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.model; +package org.eclipse.tractusx.agents.model; import jakarta.json.JsonObject; import jakarta.json.JsonValue; -import org.eclipse.tractusx.agents.edc.jsonld.JsonLdObject; +import org.eclipse.tractusx.agents.jsonld.JsonLdObject; import java.util.ArrayList; import java.util.List; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/IdResponse.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/IdResponse.java similarity index 89% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/IdResponse.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/model/IdResponse.java index aaf02a5e..d8b6dab1 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/IdResponse.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/IdResponse.java @@ -14,10 +14,10 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.model; +package org.eclipse.tractusx.agents.model; import jakarta.json.JsonObject; -import org.eclipse.tractusx.agents.edc.jsonld.JsonLdObject; +import org.eclipse.tractusx.agents.jsonld.JsonLdObject; /** * represents a response object diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/OdrlPolicy.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/OdrlPolicy.java similarity index 89% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/OdrlPolicy.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/model/OdrlPolicy.java index 35d3c3a9..369f29c4 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/OdrlPolicy.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/OdrlPolicy.java @@ -14,10 +14,10 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.model; +package org.eclipse.tractusx.agents.model; import jakarta.json.JsonObject; -import org.eclipse.tractusx.agents.edc.jsonld.JsonLdObject; +import org.eclipse.tractusx.agents.jsonld.JsonLdObject; /** * represents a policy diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/TransferProcess.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/TransferProcess.java similarity index 90% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/TransferProcess.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/model/TransferProcess.java index 56d2ae29..221beb3e 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/TransferProcess.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/TransferProcess.java @@ -14,10 +14,10 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.model; +package org.eclipse.tractusx.agents.model; import jakarta.json.JsonObject; -import org.eclipse.tractusx.agents.edc.jsonld.JsonLdObject; +import org.eclipse.tractusx.agents.jsonld.JsonLdObject; public class TransferProcess extends JsonLdObject { diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/TransferRequest.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/TransferRequest.java similarity index 96% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/TransferRequest.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/model/TransferRequest.java index 83eac475..ae9ef92a 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/model/TransferRequest.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/model/TransferRequest.java @@ -14,13 +14,13 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.model; +package org.eclipse.tractusx.agents.model; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; -import org.eclipse.edc.spi.types.domain.DataAddress; -import org.eclipse.edc.spi.types.domain.callback.CallbackAddress; +import org.eclipse.tractusx.agents.utils.CallbackAddress; +import org.eclipse.tractusx.agents.utils.DataAddress; import java.util.ArrayList; import java.util.HashMap; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/rdf/ExternalFormat.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/rdf/ExternalFormat.java similarity index 97% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/rdf/ExternalFormat.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/rdf/ExternalFormat.java index 1d8dacc5..f9664e6e 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/rdf/ExternalFormat.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/rdf/ExternalFormat.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.rdf; +package org.eclipse.tractusx.agents.rdf; /** * lists the various formats that the rdf store can import diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/rdf/RdfStore.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/rdf/RdfStore.java similarity index 98% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/rdf/RdfStore.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/rdf/RdfStore.java index 7112d756..1157e57f 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/rdf/RdfStore.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/rdf/RdfStore.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.rdf; +package org.eclipse.tractusx.agents.rdf; import org.apache.jena.fuseki.server.DataAccessPoint; @@ -32,9 +32,9 @@ import org.apache.jena.sparql.core.DatasetGraph; import org.apache.jena.sparql.core.DatasetGraphFactory; import org.apache.jena.sparql.core.Quad; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.eclipse.tractusx.agents.edc.MonitorWrapper; +import org.eclipse.tractusx.agents.AgentConfig; +import org.eclipse.tractusx.agents.MonitorWrapper; +import org.eclipse.tractusx.agents.utils.Monitor; //import java.io.*; import java.io.BufferedReader; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/service/DataManagement.java similarity index 89% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/service/DataManagement.java index 35870363..0bd9d0d6 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagement.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/service/DataManagement.java @@ -14,17 +14,17 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.service; - -import org.eclipse.edc.spi.query.QuerySpec; -import org.eclipse.tractusx.agents.edc.model.Asset; -import org.eclipse.tractusx.agents.edc.model.ContractAgreement; -import org.eclipse.tractusx.agents.edc.model.ContractNegotiation; -import org.eclipse.tractusx.agents.edc.model.ContractNegotiationRequest; -import org.eclipse.tractusx.agents.edc.model.DcatCatalog; -import org.eclipse.tractusx.agents.edc.model.IdResponse; -import org.eclipse.tractusx.agents.edc.model.TransferProcess; -import org.eclipse.tractusx.agents.edc.model.TransferRequest; +package org.eclipse.tractusx.agents.service; + +import org.eclipse.tractusx.agents.model.Asset; +import org.eclipse.tractusx.agents.model.ContractAgreement; +import org.eclipse.tractusx.agents.model.ContractNegotiation; +import org.eclipse.tractusx.agents.model.ContractNegotiationRequest; +import org.eclipse.tractusx.agents.model.DcatCatalog; +import org.eclipse.tractusx.agents.model.IdResponse; +import org.eclipse.tractusx.agents.model.TransferProcess; +import org.eclipse.tractusx.agents.model.TransferRequest; +import org.eclipse.tractusx.agents.utils.QuerySpec; import java.io.IOException; import java.util.List; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagementImpl.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/service/DataManagementImpl.java similarity index 97% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagementImpl.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/service/DataManagementImpl.java index 2b29f41b..9b0b4547 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataManagementImpl.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/service/DataManagementImpl.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.service; +package org.eclipse.tractusx.agents.service; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -24,21 +24,21 @@ import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.ResponseBody; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.query.Criterion; -import org.eclipse.edc.spi.query.QuerySpec; -import org.eclipse.edc.spi.types.TypeManager; -import org.eclipse.tractusx.agents.conforming.SharedObjectManager; -import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.eclipse.tractusx.agents.edc.jsonld.JsonLd; -import org.eclipse.tractusx.agents.edc.model.Asset; -import org.eclipse.tractusx.agents.edc.model.ContractAgreement; -import org.eclipse.tractusx.agents.edc.model.ContractNegotiation; -import org.eclipse.tractusx.agents.edc.model.ContractNegotiationRequest; -import org.eclipse.tractusx.agents.edc.model.DcatCatalog; -import org.eclipse.tractusx.agents.edc.model.IdResponse; -import org.eclipse.tractusx.agents.edc.model.TransferProcess; -import org.eclipse.tractusx.agents.edc.model.TransferRequest; +import org.eclipse.tractusx.agents.AgentConfig; +import org.eclipse.tractusx.agents.jsonld.JsonLd; +import org.eclipse.tractusx.agents.matchmaking.SharedObjectManager; +import org.eclipse.tractusx.agents.model.Asset; +import org.eclipse.tractusx.agents.model.ContractAgreement; +import org.eclipse.tractusx.agents.model.ContractNegotiation; +import org.eclipse.tractusx.agents.model.ContractNegotiationRequest; +import org.eclipse.tractusx.agents.model.DcatCatalog; +import org.eclipse.tractusx.agents.model.IdResponse; +import org.eclipse.tractusx.agents.model.TransferProcess; +import org.eclipse.tractusx.agents.model.TransferRequest; +import org.eclipse.tractusx.agents.utils.Criterion; +import org.eclipse.tractusx.agents.utils.Monitor; +import org.eclipse.tractusx.agents.utils.QuerySpec; +import org.eclipse.tractusx.agents.utils.TypeManager; import java.io.IOException; import java.net.URLEncoder; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataspaceSynchronizer.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/service/DataspaceSynchronizer.java similarity index 97% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataspaceSynchronizer.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/service/DataspaceSynchronizer.java index f631b3f8..6b832af8 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/DataspaceSynchronizer.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/service/DataspaceSynchronizer.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.service; +package org.eclipse.tractusx.agents.service; import jakarta.json.Json; import jakarta.json.JsonValue; @@ -29,15 +29,15 @@ import org.apache.jena.riot.system.StreamRDF; import org.apache.jena.riot.system.StreamRDFLib; import org.apache.jena.sparql.core.Quad; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.query.Criterion; -import org.eclipse.edc.spi.query.QuerySpec; -import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.eclipse.tractusx.agents.edc.MonitorWrapper; -import org.eclipse.tractusx.agents.edc.jsonld.JsonLd; -import org.eclipse.tractusx.agents.edc.model.DcatCatalog; -import org.eclipse.tractusx.agents.edc.model.DcatDataset; -import org.eclipse.tractusx.agents.edc.rdf.RdfStore; +import org.eclipse.tractusx.agents.AgentConfig; +import org.eclipse.tractusx.agents.MonitorWrapper; +import org.eclipse.tractusx.agents.jsonld.JsonLd; +import org.eclipse.tractusx.agents.model.DcatCatalog; +import org.eclipse.tractusx.agents.model.DcatDataset; +import org.eclipse.tractusx.agents.rdf.RdfStore; +import org.eclipse.tractusx.agents.utils.Criterion; +import org.eclipse.tractusx.agents.utils.Monitor; +import org.eclipse.tractusx.agents.utils.QuerySpec; import java.io.StringReader; import java.util.ArrayList; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/EdcSkillStore.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/service/EdcSkillStore.java similarity index 89% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/EdcSkillStore.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/service/EdcSkillStore.java index 13fe5e96..74a672d4 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/EdcSkillStore.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/service/EdcSkillStore.java @@ -14,17 +14,17 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.service; +package org.eclipse.tractusx.agents.service; import com.fasterxml.jackson.databind.node.TextNode; -import org.eclipse.edc.spi.query.Criterion; -import org.eclipse.edc.spi.query.QuerySpec; -import org.eclipse.edc.spi.types.TypeManager; -import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.eclipse.tractusx.agents.edc.SkillDistribution; -import org.eclipse.tractusx.agents.edc.SkillStore; -import org.eclipse.tractusx.agents.edc.jsonld.JsonLd; -import org.eclipse.tractusx.agents.edc.model.Asset; +import org.eclipse.tractusx.agents.AgentConfig; +import org.eclipse.tractusx.agents.SkillDistribution; +import org.eclipse.tractusx.agents.SkillStore; +import org.eclipse.tractusx.agents.jsonld.JsonLd; +import org.eclipse.tractusx.agents.model.Asset; +import org.eclipse.tractusx.agents.utils.Criterion; +import org.eclipse.tractusx.agents.utils.QuerySpec; +import org.eclipse.tractusx.agents.utils.TypeManager; import java.io.IOException; import java.util.List; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/InMemorySkillStore.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/service/InMemorySkillStore.java similarity index 92% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/InMemorySkillStore.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/service/InMemorySkillStore.java index 744be30c..853ef591 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/service/InMemorySkillStore.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/service/InMemorySkillStore.java @@ -14,10 +14,10 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.service; +package org.eclipse.tractusx.agents.service; -import org.eclipse.tractusx.agents.edc.SkillDistribution; -import org.eclipse.tractusx.agents.edc.SkillStore; +import org.eclipse.tractusx.agents.SkillDistribution; +import org.eclipse.tractusx.agents.SkillStore; import java.util.HashMap; import java.util.Map; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/CatenaxWarning.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/CatenaxWarning.java similarity index 99% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/CatenaxWarning.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/CatenaxWarning.java index c27a3fbf..38b24a5c 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/CatenaxWarning.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/CatenaxWarning.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.sparql; import com.fasterxml.jackson.annotation.JsonProperty; import org.apache.jena.sparql.util.Context; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/DataspaceServiceExecutor.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/DataspaceServiceExecutor.java similarity index 98% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/DataspaceServiceExecutor.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/DataspaceServiceExecutor.java index 88415b35..80d9157a 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/DataspaceServiceExecutor.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/DataspaceServiceExecutor.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.sparql; import com.fasterxml.jackson.databind.ObjectMapper; import okhttp3.OkHttpClient; @@ -56,12 +56,12 @@ import org.apache.jena.sparql.service.single.ServiceExecutor; import org.apache.jena.sparql.util.Context; import org.apache.jena.sparql.util.Symbol; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.types.TypeManager; -import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; -import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.eclipse.tractusx.agents.edc.AgreementController; -import org.eclipse.tractusx.agents.edc.http.HttpClientAdapter; +import org.eclipse.tractusx.agents.AgentConfig; +import org.eclipse.tractusx.agents.AgreementController; +import org.eclipse.tractusx.agents.http.HttpClientAdapter; +import org.eclipse.tractusx.agents.utils.EndpointDataReference; +import org.eclipse.tractusx.agents.utils.Monitor; +import org.eclipse.tractusx.agents.utils.TypeManager; import java.io.IOException; import java.io.InputStream; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewrite.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/GraphRewrite.java similarity index 98% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewrite.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/GraphRewrite.java index 0b1af61f..06a08c6b 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewrite.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/GraphRewrite.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.sparql; import org.apache.jena.graph.Node; import org.apache.jena.graph.NodeFactory; @@ -23,7 +23,7 @@ import org.apache.jena.sparql.algebra.op.OpGraph; import org.apache.jena.sparql.core.Var; import org.apache.jena.sparql.engine.binding.Binding; -import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.tractusx.agents.utils.Monitor; import java.util.HashSet; import java.util.Iterator; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewriteVisitor.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/GraphRewriteVisitor.java similarity index 95% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewriteVisitor.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/GraphRewriteVisitor.java index b86c8e89..9d8145a8 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/GraphRewriteVisitor.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/GraphRewriteVisitor.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.sparql; import org.apache.jena.sparql.algebra.OpVisitorBase; import org.apache.jena.sparql.algebra.op.OpService; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/HttpServletRequestToOkHttpRequestConverter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/HttpServletRequestToOkHttpRequestConverter.java similarity index 98% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/HttpServletRequestToOkHttpRequestConverter.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/HttpServletRequestToOkHttpRequestConverter.java index dedc9b07..f3c1b8e2 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/HttpServletRequestToOkHttpRequestConverter.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/HttpServletRequestToOkHttpRequestConverter.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0package org.eclipse.tractusx.agents.edc.sparql; -package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.sparql; import com.google.gson.Gson; import jakarta.servlet.http.HttpServletRequest; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/OptimizeJoinStrategy.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/OptimizeJoinStrategy.java similarity index 98% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/OptimizeJoinStrategy.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/OptimizeJoinStrategy.java index 3e87fc3c..569eac2a 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/OptimizeJoinStrategy.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/OptimizeJoinStrategy.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.sparql; import org.apache.jena.sparql.algebra.Op; import org.apache.jena.sparql.algebra.op.OpGraph; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/Optimizer.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/Optimizer.java similarity index 97% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/Optimizer.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/Optimizer.java index 9b62778d..f1fc9212 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/Optimizer.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/Optimizer.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.sparql; import org.apache.jena.sparql.algebra.Op; import org.apache.jena.sparql.algebra.optimize.OptimizerStd; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/OptimizerFactory.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/OptimizerFactory.java similarity index 95% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/OptimizerFactory.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/OptimizerFactory.java index ea107741..1828bc95 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/OptimizerFactory.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/OptimizerFactory.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.sparql; import org.apache.jena.sparql.algebra.optimize.Rewrite; import org.apache.jena.sparql.algebra.optimize.RewriteFactory; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutor.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/QueryExecutor.java similarity index 99% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutor.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/QueryExecutor.java index 5ab861bb..8cef0421 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutor.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/QueryExecutor.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.sparql; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; @@ -60,7 +60,7 @@ import org.apache.jena.sparql.exec.http.Params; import org.apache.jena.sparql.exec.http.QuerySendMode; import org.apache.jena.sparql.util.Context; -import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.AgentConfig; import java.io.BufferedInputStream; import java.io.BufferedReader; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutorBuilder.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/QueryExecutorBuilder.java similarity index 96% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutorBuilder.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/QueryExecutorBuilder.java index fc900e78..924aacb8 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryExecutorBuilder.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/QueryExecutorBuilder.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.sparql; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.jena.http.sys.ExecHTTPBuilder; @@ -23,7 +23,7 @@ import org.apache.jena.sparql.exec.QueryExecMod; import org.apache.jena.sparql.exec.http.Params; import org.apache.jena.sparql.util.Context; -import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.AgentConfig; import java.net.http.HttpClient; import java.util.HashMap; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterFutures.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/QueryIterFutures.java similarity index 97% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterFutures.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/QueryIterFutures.java index efe1fcde..a6d4c35c 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterFutures.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/QueryIterFutures.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.sparql; import org.apache.jena.atlas.io.IndentedWriter; import org.apache.jena.graph.Node; @@ -24,8 +24,8 @@ import org.apache.jena.sparql.engine.iterator.QueryIteratorBase; import org.apache.jena.sparql.serializer.SerializationContext; import org.apache.jena.sparql.util.Context; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.AgentConfig; +import org.eclipse.tractusx.agents.utils.Monitor; import java.util.List; import java.util.Optional; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterJoin.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/QueryIterJoin.java similarity index 98% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterJoin.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/QueryIterJoin.java index 7ad26690..b9f39d91 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/QueryIterJoin.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/QueryIterJoin.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.sparql; import org.apache.jena.atlas.io.IndentedWriter; import org.apache.jena.atlas.lib.Lib; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SkillVariableDetector.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/SkillVariableDetector.java similarity index 97% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SkillVariableDetector.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/SkillVariableDetector.java index bbc6b966..55fac246 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SkillVariableDetector.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/SkillVariableDetector.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.sparql; import org.apache.jena.graph.Node; import org.apache.jena.sparql.algebra.Op; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQueryProcessor.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/SparqlQueryProcessor.java similarity index 92% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQueryProcessor.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/SparqlQueryProcessor.java index 19700196..f6ab3369 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQueryProcessor.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/SparqlQueryProcessor.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.sparql; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -39,23 +39,24 @@ import org.apache.jena.sparql.core.DatasetGraph; import org.apache.jena.sparql.engine.http.QueryExceptionHTTP; import org.apache.jena.sparql.service.ServiceExecutorRegistry; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.types.TypeManager; -import org.eclipse.tractusx.agents.edc.AgentConfig; -import org.eclipse.tractusx.agents.edc.MonitorWrapper; -import org.eclipse.tractusx.agents.edc.Tuple; -import org.eclipse.tractusx.agents.edc.TupleSet; -import org.eclipse.tractusx.agents.edc.http.AgentHttpAction; -import org.eclipse.tractusx.agents.edc.http.HttpServletContextAdapter; -import org.eclipse.tractusx.agents.edc.http.HttpServletRequestAdapter; -import org.eclipse.tractusx.agents.edc.http.HttpServletResponseAdapter; -import org.eclipse.tractusx.agents.edc.http.HttpUtils; -import org.eclipse.tractusx.agents.edc.http.JakartaAdapter; -import org.eclipse.tractusx.agents.edc.http.transfer.AgentSourceHttpParamsDecorator; -import org.eclipse.tractusx.agents.edc.rdf.RdfStore; +import org.eclipse.tractusx.agents.AgentConfig; +import org.eclipse.tractusx.agents.MonitorWrapper; +import org.eclipse.tractusx.agents.Tuple; +import org.eclipse.tractusx.agents.TupleSet; +import org.eclipse.tractusx.agents.http.AgentHttpAction; +import org.eclipse.tractusx.agents.http.HttpServletContextAdapter; +import org.eclipse.tractusx.agents.http.HttpServletRequestAdapter; +import org.eclipse.tractusx.agents.http.HttpServletResponseAdapter; +import org.eclipse.tractusx.agents.http.HttpUtils; +import org.eclipse.tractusx.agents.http.JakartaAdapter; +import org.eclipse.tractusx.agents.rdf.RdfStore; +import org.eclipse.tractusx.agents.utils.Monitor; +import org.eclipse.tractusx.agents.utils.TypeManager; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -91,6 +92,10 @@ public class SparqlQueryProcessor extends SPARQL_QueryGeneral.SPARQL_QueryProc { private long count = -1; public static final String UNSET_BASE = "http://server/unset-base/"; + + public static final String PARAM_GROUP = "param"; + public static final String VALUE_GROUP = "value"; + public static final Pattern PARAMS = Pattern.compile(String.format("(\\?|&)(?<%s>[^=&]+)=(?<%s>[^=&]*)", PARAM_GROUP, VALUE_GROUP)); /** * create a new sparql processor @@ -379,7 +384,7 @@ protected void execute(String queryString, HttpAction action) { queryString = HttpUtils.urlDecodeParameter(queryString); // support for the special www-forms form if (action.getRequestContentType() != null && action.getRequestContentType().contains("application/x-www-form-urlencoded")) { - Map> parts = AgentSourceHttpParamsDecorator.parseParams(queryString); + Map> parts = parseParams(queryString); Optional query = parts.getOrDefault("query", List.of()).stream().findFirst(); if (query.isEmpty()) { action.getResponse().setStatus(HttpStatus.SC_BAD_REQUEST); @@ -495,4 +500,23 @@ protected Pair decideDataset(HttpAction action, Query query } return Pair.create(rdfStore.getDataSet(), query); } + + /** + * parse the body or parameter string as a url-encoded form into a map + * + * @param body url-encoded form body + * @return a map of parameters + */ + public static Map> parseParams(String body) { + Map> parts = new HashMap<>(); + if (body != null) { + Matcher matcher = PARAMS.matcher(body); + while (matcher.find()) { + String paramName = matcher.group(PARAM_GROUP); + List partSet = parts.computeIfAbsent(paramName, k -> new ArrayList<>()); + partSet.add(matcher.group(VALUE_GROUP)); + } + } + return parts; + } } diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializer.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/SparqlQuerySerializer.java similarity index 99% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializer.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/SparqlQuerySerializer.java index 58dd9aee..75c3d212 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializer.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/SparqlQuerySerializer.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.sparql; import org.apache.jena.atlas.io.IndentedWriter; import org.apache.jena.graph.Node; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializerFactory.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/SparqlQuerySerializerFactory.java similarity index 98% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializerFactory.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/SparqlQuerySerializerFactory.java index 7ecc1b75..ed33ff2b 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/SparqlQuerySerializerFactory.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/SparqlQuerySerializerFactory.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.sparql; import org.apache.jena.atlas.io.IndentedWriter; import org.apache.jena.query.QueryVisitor; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/StratifiedFormatterElement.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/StratifiedFormatterElement.java similarity index 98% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/StratifiedFormatterElement.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/StratifiedFormatterElement.java index 824beb2c..83d7e670 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/StratifiedFormatterElement.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/StratifiedFormatterElement.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.sparql; import org.apache.jena.atlas.io.IndentedWriter; import org.apache.jena.sparql.serializer.FormatterElement; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/VariableDetector.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/VariableDetector.java similarity index 97% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/VariableDetector.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/VariableDetector.java index b85b64d9..9481e273 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/sparql/VariableDetector.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/sparql/VariableDetector.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.sparql; +package org.eclipse.tractusx.agents.sparql; import org.apache.jena.graph.Node; import org.apache.jena.sparql.core.Var; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/CallbackAddress.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/CallbackAddress.java new file mode 100644 index 00000000..936086f3 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/CallbackAddress.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ +package org.eclipse.tractusx.agents.utils; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import static org.eclipse.tractusx.agents.utils.CoreConstants.EDC_NAMESPACE; + +/** + * The {@link CallbackAddress} contains information about users configured callbacks + * that can be invoked in various state of the requests processing according to the filter provided + * in {@link CallbackAddress#events} + */ +@JsonDeserialize(builder = CallbackAddress.Builder.class) +public class CallbackAddress { + public static final String CALLBACKADDRESS_TYPE = EDC_NAMESPACE + "CallbackAddress"; + public static final String IS_TRANSACTIONAL = EDC_NAMESPACE + "transactional"; + public static final String URI = EDC_NAMESPACE + "uri"; + public static final String EVENTS = EDC_NAMESPACE + "events"; + + public static final String AUTH_KEY = EDC_NAMESPACE + "authKey"; + public static final String AUTH_CODE_ID = EDC_NAMESPACE + "authCodeId"; + + private String uri; + private Set events = new HashSet<>(); + private boolean transactional; + + private String authKey; + private String authCodeId; + + + public Set getEvents() { + return events; + } + + public String getUri() { + return uri; + } + + public boolean isTransactional() { + return transactional; + } + + public String getAuthCodeId() { + return authCodeId; + } + + public String getAuthKey() { + return authKey; + } + + @JsonPOJOBuilder(withPrefix = "") + public static class Builder { + + + private final CallbackAddress callbackAddress; + + protected Builder() { + callbackAddress = new CallbackAddress(); + } + + @JsonCreator + public static Builder newInstance() { + return new Builder(); + } + + public Builder uri(String url) { + callbackAddress.uri = url; + return this; + } + + public Builder events(Set events) { + callbackAddress.events = events; + return this; + } + + public Builder transactional(boolean transactional) { + callbackAddress.transactional = transactional; + return this; + } + + public Builder authKey(String authKey) { + callbackAddress.authKey = authKey; + return this; + } + + public Builder authCodeId(String authCodeId) { + callbackAddress.authCodeId = authCodeId; + return this; + } + + + public CallbackAddress build() { + Objects.requireNonNull(callbackAddress.uri, "URI should not be null"); + Objects.requireNonNull(callbackAddress.events, "Events should not be null"); + return callbackAddress; + } + } + +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/Config.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/Config.java new file mode 100644 index 00000000..f8723369 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/Config.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * Fraunhofer Institute for Software and Systems Engineering - Improvements + * + */ + +package org.eclipse.tractusx.agents.utils; + +import java.util.Map; +import java.util.stream.Stream; + +/** + * A Config facade that offers some utility functions to work with configuration settings based on the Java Properties format: + *
+ *   group.subgroup.key = value
+ * 
+ * The path components are separated by a dot, and the root path is considered to be an empty string. + */ +public interface Config { + + /** + * Returns the String representation of the value + * + * @param key of the setting + * @return a String representation of the setting + * @throws EdcException if no setting is found + */ + String getString(String key); + + /** + * Returns the String representation of the value, or the default one if not found + * + * @param key of the setting + * @return a String representation of the setting + */ + String getString(String key, String defaultValue); + + /** + * Returns the Integer representation of the value + * + * @param key of the setting + * @return an Integer representation of the setting + * @throws EdcException if no setting is found, or if it's not parsable + */ + Integer getInteger(String key); + + /** + * Returns the Integer representation of the value, or the default one if not found + * + * @param key of the setting + * @return an Integer representation of the setting + * @throws EdcException if the value it's not parsable + */ + Integer getInteger(String key, Integer defaultValue); + + /** + * Returns the Long representation of the value + * + * @param key of the setting + * @return a Long representation of the setting + * @throws EdcException if no setting is found, or if it's not parsable + */ + Long getLong(String key); + + /** + * Returns the Long representation of the value, or the default one if not found + * + * @param key of the setting + * @return a Long representation of the setting + * @throws EdcException if the value it's not parsable + */ + Long getLong(String key, Long defaultValue); + + /** + * Returns the Boolean representation of the value + * + * @param key of the setting + * @return a Boolean representation of the setting + * @throws EdcException if no setting is found, or if it's not parsable + */ + Boolean getBoolean(String key); + + /** + * Returns the Boolean representation of the value, or the default one if not found + * + * @param key of the setting + * @return a Boolean representation of the setting + * @throws EdcException if the value it's not parsable + */ + Boolean getBoolean(String key, Boolean defaultValue); + + /** + * Returns the Config representation relative to the specified path. + * The entries that are not relative to the path specified will be filtered out. + * + * @param path that will be appended to the root path + * @return another Config object relative to the path specified + */ + Config getConfig(String path); + + /** + * Return a config that will own the union of the entries (in case of duplicates, other's one will subdue). + * The root path will be reset. + * + * @param other another Config object + * @return a Config that's the merge of the current and the other + */ + Config merge(Config other); + + /** + * Return a stream of configs partitioned by the current group level + * + * @return a stream of configs + */ + Stream partition(); + + /** + * Returns the config entries + * + * @return the config entries + */ + Map getEntries(); + + /** + * Returns the config entries relative to the current root path. + * e.g. if the entries contains an entry that's + *
+     *     group.key = value
+     * 
+ * and the rootPath is "group", this method will return a map that contains this entry: + *
+     *     key = value
+     * 
+ * + * @return a map containing the config entries relative to the current root path + */ + Map getRelativeEntries(); + + /** + * Returns the config entries relative to the current root path filtering out properties that + * does not start with basePath. + * + * @return a map containing the config entries relative to the current root path filtered by basePath + */ + Map getRelativeEntries(String basePath); + + /** + * Returns the name of the current node. + * e.g. for a Config with a rootPath equal to "group.subgroup" the current node is "subgroup" + * + * @return the name of the current node + */ + String currentNode(); + + /** + * Checks whether a particular config is a "leaf", i.e. has no more children, or not + */ + boolean isLeaf(); + + /** + * Checks whether a (fully qualified) config key is present or not + */ + boolean hasKey(String key); + + /** + * Checks whether exist at least one setting with the passed root path + */ + boolean hasPath(String path); +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/ConfigFactory.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/ConfigFactory.java new file mode 100644 index 00000000..35ff50d9 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/ConfigFactory.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * + */ +package org.eclipse.tractusx.agents.utils; + +import java.util.Map; +import java.util.Properties; + +import static java.util.Collections.emptyMap; +import static org.eclipse.tractusx.agents.utils.ConfigImpl.TO_MAP; + +/** + * Creates a {@link Config} from another data structure. + */ +public class ConfigFactory { + + /** + * Returns an empty {@link Config}. + * + * @return an empty {@link Config} + */ + public static Config empty() { + return new ConfigImpl(emptyMap()); + } + + /** + * Returns a config built from a {@link Map}. + * + * @return a {@link Config} instance based on the given {@link Map} + */ + public static Config fromMap(Map settings) { + return new ConfigImpl(settings); + } + + /** + * Returns a config built from {@link Properties}. + * + * @return a {@link Config} instance based on the given {@link Properties} + */ + public static Config fromProperties(Properties properties) { + var entries = properties.entrySet().stream() + .map(it -> Map.entry(it.getKey().toString(), it.getValue().toString())) + .collect(TO_MAP); + + return new ConfigImpl(entries); + } + + /** + * Returns a config built from a {@link Map} containing environment variables, converting ENV_KEY_FORMAT to env.key.format + * keys. + * + * @return a {@link Config} instance based on the given {@link Properties} + */ + public static Config fromEnvironment(Map environmentVariables) { + var settings = environmentVariables.entrySet().stream() + .map(it -> Map.entry(it.getKey().toLowerCase().replace("_", "."), it.getValue())) + .collect(TO_MAP); + + return new ConfigImpl(settings); + } +} \ No newline at end of file diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/ConfigImpl.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/ConfigImpl.java new file mode 100644 index 00000000..c9564412 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/ConfigImpl.java @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation + * Fraunhofer Institute for Software and Systems Engineering - Improvements + * + */ +package org.eclipse.tractusx.agents.utils; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collector; +import java.util.stream.Stream; + +import static java.lang.String.format; +import static java.util.stream.Collectors.toMap; + +/** + * Default implementation. + */ +public class ConfigImpl implements Config { + + static final Collector, ?, Map> TO_MAP = toMap(Map.Entry::getKey, Map.Entry::getValue); + + private final Map entries; + private final String rootPath; + + ConfigImpl(Map entries) { + this("", entries); + } + + protected ConfigImpl(String rootPath, Map entries) { + Objects.requireNonNull(rootPath, "rootPath"); + + this.entries = entries; + this.rootPath = rootPath; + } + + @Override + public String getString(String key) { + return getNotNullValue(key, this::getString); + } + + @Override + public String getString(String key, String defaultValue) { + var value = entries.get(absolutePathOf(key)); + if (value == null) { + return defaultValue; + } else { + return value; + } + } + + @Override + public Integer getInteger(String key) { + return getNotNullValue(key, this::getInteger); + } + + @Override + public Integer getInteger(String key, Integer defaultValue) { + return getParsed(key, defaultValue, "integer", Integer::parseInt); + } + + @Override + public Long getLong(String key) { + return getNotNullValue(key, this::getLong); + } + + @Override + public Long getLong(String key, Long defaultValue) { + return getParsed(key, defaultValue, "long", Long::parseLong); + } + + @Override + public Boolean getBoolean(String key) { + return getNotNullValue(key, this::getBoolean); + } + + @Override + public Boolean getBoolean(String key, Boolean defaultValue) { + return getParsed(key, defaultValue, "boolean", this::parseBoolean); + } + + @Override + public Config getConfig(String path) { + var absolutePath = absolutePathOf(path); + var filteredEntries = entries.entrySet().stream() + .filter(entry -> absolutePath.isEmpty() || entry.getKey().startsWith(absolutePath + ".") || entry.getKey().equals(absolutePath)) + .collect(TO_MAP); + + return new ConfigImpl(absolutePath, filteredEntries); + } + + @Override + public Config merge(Config other) { + var all = new HashMap(); + all.putAll(entries); + all.putAll(other.getEntries()); + + return new ConfigImpl("", Collections.unmodifiableMap(all)); + } + + @Override + public Stream partition() { + return getRelativeEntries().keySet().stream().map(it -> it.split("\\.")[0]).distinct().map(this::getConfig); + } + + @Override + public Map getEntries() { + return entries; + } + + @Override + public Map getRelativeEntries() { + return getEntries().entrySet().stream().map(entry -> Map.entry(removePrefix(entry.getKey(), rootPath), entry.getValue())) + .collect(TO_MAP); + } + + @Override + public Map getRelativeEntries(String basePath) { + return getRelativeEntries().entrySet().stream().filter(entry -> entry.getKey().startsWith(basePath)).collect(TO_MAP); + } + + @Override + public String currentNode() { + var parts = rootPath.split("\\."); + return parts[parts.length - 1]; + } + + @Override + public boolean isLeaf() { + return entries.size() == 1 && entries.keySet().stream().allMatch(rootPath::equals); + } + + @Override + public boolean hasKey(String key) { + return getEntries().containsKey(key); + } + + @Override + public boolean hasPath(String path) { + return getEntries().keySet().stream().anyMatch(it -> it.startsWith(path)); + } + + private boolean parseBoolean(String value) { + if (value.equalsIgnoreCase("true")) { + return true; + } else if (value.equalsIgnoreCase("false")) { + return false; + } + + throw new MatchmakingException(format("Cannot parse %s to boolean", value)); + } + + private String removePrefix(String path, String rootPath) { + if (!rootPath.isEmpty() && path.startsWith(rootPath)) { + return path.substring(rootPath.length() + 1); + } else { + return path; + } + } + + @Nullable + private T getParsed(String key, T defaultValue, String typeDescription, Function parse) { + var value = getString(key, Objects.toString(defaultValue, null)); + if (value == null) { + return null; + } else { + try { + return parse.apply(value); + } catch (Exception e) { + throw new MatchmakingException(format("Setting %s with value %s cannot be parsed to %s", absolutePathOf(key), value, typeDescription)); + } + } + } + + @NotNull + private T getNotNullValue(String key, BiFunction function) { + var value = function.apply(key, null); + if (value == null) { + throw new MatchmakingException(format("No setting found for key %s", absolutePathOf(key))); + } else { + return value; + } + } + + @NotNull + private String absolutePathOf(String key) { + String rootPath = Optional.of(this.rootPath).filter(it -> !it.isEmpty()).map(it -> it + ".").orElse(""); + return rootPath + key; + } +} + diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/ConsoleMonitor.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/ConsoleMonitor.java new file mode 100644 index 00000000..137296f2 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/ConsoleMonitor.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2020, 2021 Microsoft Corporation + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation + * + */ + +package org.eclipse.tractusx.agents.utils; + +import org.jetbrains.annotations.Nullable; + +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.function.Supplier; + +import static java.lang.String.format; + +/** + * Default monitor implementation. Outputs messages to the console. + */ +public class ConsoleMonitor implements Monitor { + + private static final String SEVERE = "SEVERE"; + private static final String WARNING = "WARNING"; + private static final String INFO = "INFO"; + private static final String DEBUG = "DEBUG"; + + private final Level level; + private final String prefix; + + public ConsoleMonitor() { + this.prefix = ""; + this.level = Level.DEBUG; + } + + public ConsoleMonitor(@Nullable String runtimeName, Level level) { + this.prefix = format("[%s] ", runtimeName); + this.level = level; + } + + @Override + public void severe(Supplier supplier, Throwable... errors) { + output(SEVERE, supplier, errors); + } + + @Override + public void warning(Supplier supplier, Throwable... errors) { + if (Level.WARNING.value < level.value) { + return; + } + output(WARNING, supplier, errors); + } + + @Override + public void info(Supplier supplier, Throwable... errors) { + if (Level.INFO.value < level.value) { + return; + } + output(INFO, supplier, errors); + } + + @Override + public void debug(Supplier supplier, Throwable... errors) { + if (Level.DEBUG.value < level.value) { + return; + } + output(DEBUG, supplier, errors); + } + + private void output(String level, Supplier supplier, Throwable... errors) { + var time = ZonedDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); + System.out.println(prefix + level + " " + time + " " + sanitizeMessage(supplier)); + if (errors != null) { + for (Throwable error : errors) { + if (error != null) { + error.printStackTrace(System.out); + } + } + } + } + + public enum Level { + SEVERE(3), WARNING(2), INFO(1), DEBUG(0); + + private final int value; + + Level(int value) { + this.value = value; + } + } +} + diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/CoreConstants.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/CoreConstants.java new file mode 100644 index 00000000..fd1eff19 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/CoreConstants.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +* +* This program and the accompanying materials are made available under the +* terms of the Apache License, Version 2.0 which is available at +* https://www.apache.org/licenses/LICENSE-2.0 +* +* SPDX-License-Identifier: Apache-2.0 +* +* Contributors: +* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation +* +*/ + +package org.eclipse.tractusx.agents.utils; + +public interface CoreConstants { + String JSON_LD = "json-ld"; + String EDC_PREFIX = "edc"; + String EDC_NAMESPACE = "https://w3id.org/edc/v0.0.1/ns/"; +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/Criterion.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/Criterion.java new file mode 100644 index 00000000..4f4130a7 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/Criterion.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2020 - 2022 Microsoft Corporation + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation + * + */ +package org.eclipse.tractusx.agents.utils; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; + +import java.util.Objects; +import java.util.function.Function; + +import static java.lang.String.format; +import static org.eclipse.tractusx.agents.utils.CoreConstants.EDC_NAMESPACE; + +/** + * This class can be used to form select expressions e.g. in SQL statements. It is a way to express those statements in + * a generic way. For example: + *
+ * "operandLeft" = "name",
+ * "operator" = "=",
+ * "operandRight" = "someone"
+ * 
+ *

+ * can be translated to {@code [select * where name = someone]} + */ +public class Criterion { + + public static final String CRITERION_OPERAND_LEFT = EDC_NAMESPACE + "operandLeft"; + public static final String CRITERION_OPERAND_RIGHT = EDC_NAMESPACE + "operandRight"; + public static final String CRITERION_OPERATOR = EDC_NAMESPACE + "operator"; + public static final String CRITERION_TYPE = EDC_NAMESPACE + "Criterion"; + private Object operandLeft; + private String operator; + private Object operandRight; + + private Criterion() { + //for json serialization + } + + public static Criterion criterion(Object operandLeft, String operator, Object operandRight) { + return new Criterion(operandLeft, operator, operandRight); + } + + public Criterion(Object left, String op, Object right) { + operandLeft = Objects.requireNonNull(left); + operator = Objects.requireNonNull(op); + operandRight = right; // null may be allowed, for example when the operator is unary, like NOT_NULL + } + + public Object getOperandLeft() { + return operandLeft; + } + + public String getOperator() { + return operator; + } + + public Object getOperandRight() { + return operandRight; + } + + public Criterion withLeftOperand(String operandLeft) { + return new Criterion(operandLeft, operator, getOperandRight()); + } + + public Criterion withLeftOperand(Function function) { + return new Criterion(function.apply(operandLeft), operator, getOperandRight()); + } + + @Override + public int hashCode() { + return Objects.hash(operandLeft, operator, operandRight); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + var criterion = (Criterion) o; + return Objects.equals(operandLeft, criterion.operandLeft) && Objects.equals(operator, criterion.operator) && Objects.equals(operandRight, criterion.operandRight); + } + + @Override + public String toString() { + return format("%s %s %s", getOperandLeft(), getOperator(), getOperandRight()); + } + + @JsonPOJOBuilder(withPrefix = "") + public static final class Builder { + private final Criterion criterion; + + private Builder() { + this.criterion = new Criterion(); + } + + @JsonCreator + public static Builder newInstance() { + return new Builder(); + } + + public Builder operandLeft(Object operandLeft) { + criterion.operandLeft = operandLeft; + return this; + } + + public Builder operator(String operator) { + criterion.operator = operator; + return this; + } + + public Builder operandRight(Object operandRight) { + criterion.operandRight = operandRight; + return this; + } + + public Criterion build() { + Objects.requireNonNull(this.criterion.operandLeft); + Objects.requireNonNull(this.criterion.operator); + return criterion; + } + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/DataAddress.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/DataAddress.java new file mode 100644 index 00000000..02e6c677 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/DataAddress.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2020, 2021 Microsoft Corporation + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation + * Siemens AG - enable read property and return a default value is missing + * + */ +package org.eclipse.tractusx.agents.utils; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import static org.eclipse.tractusx.agents.utils.CoreConstants.EDC_NAMESPACE; + + +/** + * An address that can be used resolve a data location. Data addresses are used throughout the system. For example, an asset has a data address used to resolve its contents, + * which may be in an external store. A data address can also be used as a destination to send data during a transfer. + *

+ * This type is extensible as different properties may be required to resolve data. For example, an HTTP data address will require a URL. Data addresses may also contain + * references to information required to access the address, for example, the name of a shared token. Note, however, secrets should never be stored as properties as they may be + * compromised if the data address is serialized. + */ +@JsonDeserialize(builder = DataAddress.Builder.class) +public class DataAddress { + public static final String SIMPLE_TYPE = "type"; + public static final String SIMPLE_KEY_NAME = "keyName"; + public static final String EDC_DATA_ADDRESS_TYPE = EDC_NAMESPACE + "DataAddress"; + public static final String EDC_DATA_ADDRESS_TYPE_PROPERTY = EDC_NAMESPACE + SIMPLE_TYPE; + public static final String EDC_DATA_ADDRESS_KEY_NAME = EDC_NAMESPACE + "keyName"; + public static final String EDC_DATA_ADDRESS_SECRET = EDC_NAMESPACE + "secret"; + + protected final Map properties = new HashMap<>(); + + protected DataAddress() { + } + + @NotNull + public String getType() { + return getStringProperty(EDC_DATA_ADDRESS_TYPE_PROPERTY); + } + + @JsonIgnore + public void setType(String type) { + Objects.requireNonNull(type); + properties.put(EDC_DATA_ADDRESS_TYPE_PROPERTY, type); + } + + @Nullable + public String getStringProperty(String key) { + return getStringProperty(key, null); + } + + @Nullable + public String getStringProperty(String key, String defaultValue) { + var value = Optional.ofNullable(properties.get(EDC_NAMESPACE + key)).orElseGet(() -> properties.get(key)); + if (value != null) { + return (String) value; + } + return defaultValue; + } + + public Map getProperties() { + return properties; + } + + public String getKeyName() { + return getStringProperty(EDC_DATA_ADDRESS_KEY_NAME); + } + + @JsonIgnore + public void setKeyName(String keyName) { + Objects.requireNonNull(keyName); + properties.put(EDC_DATA_ADDRESS_KEY_NAME, keyName); + } + + /** + * Returns true if there's a property with the specified key + * + * @param key the key + * @return true if it exists, false if not + */ + @JsonIgnore + public boolean hasProperty(String key) { + return getStringProperty(key) != null; + } + + @JsonPOJOBuilder(withPrefix = "") + public static class Builder> { + protected final DA address; + + protected Builder(DA address) { + this.address = address; + } + + @JsonCreator() + public static > Builder newInstance() { + return new Builder<>(new DataAddress()); + } + + public B type(String type) { + address.properties.put(EDC_DATA_ADDRESS_TYPE_PROPERTY, Objects.requireNonNull(type)); + return self(); + } + + public B property(String key, Object value) { + Objects.requireNonNull(key, "Property key null."); + switch (key) { + case SIMPLE_TYPE: + address.properties.put(EDC_DATA_ADDRESS_TYPE_PROPERTY, value); + break; + case SIMPLE_KEY_NAME: + address.properties.put(EDC_DATA_ADDRESS_KEY_NAME, value); + break; + default: + address.properties.put(key, value); + break; + } + return self(); + } + + public B properties(Map properties) { + properties.forEach(this::property); + return self(); + } + + public B keyName(String keyName) { + address.getProperties().put(EDC_DATA_ADDRESS_KEY_NAME, Objects.requireNonNull(keyName)); + return self(); + } + + public DataAddress build() { + Objects.requireNonNull(address.getType(), "DataAddress builder missing Type property."); + return address; + } + + @SuppressWarnings("unchecked") + private B self() { + return (B) this; + } + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/EndpointDataReference.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/EndpointDataReference.java new file mode 100644 index 00000000..96c7d8d4 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/EndpointDataReference.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2020, 2021 Fraunhofer Institute for Software and Systems Engineering + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Amadeus - initial API and implementation + * + */ +package org.eclipse.tractusx.agents.utils; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + +import static org.eclipse.tractusx.agents.utils.CoreConstants.EDC_NAMESPACE; + +/** + * Describes an endpoint serving data. + */ +@JsonDeserialize(builder = EndpointDataReference.Builder.class) +@JsonIgnoreProperties(ignoreUnknown = true) +public class EndpointDataReference { + public static final String EDR_SIMPLE_TYPE = "EDR"; + + public static final String ID = EDC_NAMESPACE + "id"; + public static final String AUTH_CODE = EDC_NAMESPACE + "authCode"; + public static final String AUTH_KEY = EDC_NAMESPACE + "authKey"; + public static final String ENDPOINT = EDC_NAMESPACE + "endpoint"; + private final String id; + private final String endpoint; + private final String authKey; + private final String authCode; + private final Map properties; + + private EndpointDataReference(String id, String endpoint, String authKey, String authCode, Map properties) { + this.id = id; + this.endpoint = endpoint; + this.authKey = authKey; + this.authCode = authCode; + this.properties = properties; + } + + @NotNull + public String getId() { + return id; + } + + @NotNull + public String getEndpoint() { + return endpoint; + } + + @Nullable + public String getAuthKey() { + return authKey; + } + + @Nullable + public String getAuthCode() { + return authCode; + } + + @NotNull + public Map getProperties() { + return properties; + } + + @JsonPOJOBuilder(withPrefix = "") + public static class Builder { + private final Map properties = new HashMap<>(); + private String id = UUID.randomUUID().toString(); + private String endpoint; + private String authKey; + private String authCode; + + private Builder() { + } + + @JsonCreator + public static EndpointDataReference.Builder newInstance() { + return new EndpointDataReference.Builder(); + } + + public EndpointDataReference.Builder id(String id) { + this.id = id; + return this; + } + + public EndpointDataReference.Builder endpoint(String address) { + this.endpoint = address; + return this; + } + + public EndpointDataReference.Builder authKey(String authKey) { + this.authKey = authKey; + return this; + } + + public EndpointDataReference.Builder authCode(String authCode) { + this.authCode = authCode; + return this; + } + + public EndpointDataReference.Builder properties(Map properties) { + this.properties.putAll(properties); + return this; + } + + public EndpointDataReference build() { + Objects.requireNonNull(endpoint, "endpoint"); + if (authKey != null) { + Objects.requireNonNull(authCode, "authCode"); + } + if (authCode != null) { + Objects.requireNonNull(authKey, "authKey"); + } + return new EndpointDataReference(id, endpoint, authKey, authCode, properties); + } + } +} + diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/MatchmakingException.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/MatchmakingException.java new file mode 100644 index 00000000..03feb4f4 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/MatchmakingException.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, 2021 Microsoft Corporation + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation + * + */ +package org.eclipse.tractusx.agents.utils; + + +/** + * Base exception for the system. + * The system should use unchecked exceptions when appropriate (e.g., non-recoverable errors) and may extend this exception. + */ +public class MatchmakingException extends RuntimeException { + + public MatchmakingException(String message) { + super(message); + } + + public MatchmakingException(String message, Throwable cause) { + super(message, cause); + } + + public MatchmakingException(Throwable cause) { + super(cause); + } + + public MatchmakingException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/Monitor.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/Monitor.java new file mode 100644 index 00000000..6ab30f02 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/Monitor.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020, 2021 Microsoft Corporation + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation + * + */ +package org.eclipse.tractusx.agents.utils; + +import org.eclipse.tractusx.agents.annotation.ExtensionPoint; + +import java.util.Map; +import java.util.Optional; +import java.util.function.Supplier; + +/** + * System monitoring and logging interface. + */ +@ExtensionPoint +public interface Monitor { + + default void severe(Supplier supplier, Throwable... errors) { + } + + default void severe(String message, Throwable... errors) { + severe(() -> message, errors); + } + + default void severe(Map data) { + } + + + default void warning(Supplier supplier, Throwable... errors) { + } + + default void warning(String message, Throwable... errors) { + warning(() -> message, errors); + } + + default void info(Supplier supplier, Throwable... errors) { + } + + default void info(String message, Throwable... errors) { + info(() -> message, errors); + } + + default void debug(Supplier supplier, Throwable... errors) { + } + + default void debug(String message, Throwable... errors) { + debug(() -> message, errors); + } + + default String sanitizeMessage(Supplier supplier) { + return Optional.ofNullable(supplier.get()) + .map(msg -> msg.replaceAll("([\\r\\n])", " ")) + .orElse(null); + } + +} + diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/QuerySpec.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/QuerySpec.java new file mode 100644 index 00000000..420d9821 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/QuerySpec.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2020 - 2022 Microsoft Corporation + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation + * + */ +package org.eclipse.tractusx.agents.utils; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import static org.eclipse.tractusx.agents.utils.CoreConstants.EDC_NAMESPACE; + +/** + * Specifies various query parameters for collection-like queries. Typical uses include API endpoints, where the query + * is tunnelled through to the database level. + */ +public class QuerySpec { + + public static final String EDC_QUERY_SPEC_TYPE = EDC_NAMESPACE + "QuerySpec"; + public static final String EDC_QUERY_SPEC_OFFSET = EDC_NAMESPACE + "offset"; + public static final String EDC_QUERY_SPEC_LIMIT = EDC_NAMESPACE + "limit"; + public static final String EDC_QUERY_SPEC_FILTER_EXPRESSION = EDC_NAMESPACE + "filterExpression"; + public static final String EDC_QUERY_SPEC_SORT_ORDER = EDC_NAMESPACE + "sortOrder"; + public static final String EDC_QUERY_SPEC_SORT_FIELD = EDC_NAMESPACE + "sortField"; + + private int offset = 0; + private int limit = 50; + private final List filterExpression = new ArrayList<>(); + private SortOrder sortOrder = SortOrder.ASC; + private String sortField; + + public static QuerySpec none() { + return new QuerySpec(); + } + + /** + * Generates a {@link QuerySpec} with limit = {@link Integer#MAX_VALUE} and offset = 0 + */ + public static QuerySpec max() { + return QuerySpec.Builder.newInstance().limit(Integer.MAX_VALUE).build(); + } + + public String getSortField() { + return sortField; + } + + @Override + public int hashCode() { + return Objects.hash(offset, limit, filterExpression, sortOrder, sortField); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + QuerySpec querySpec = (QuerySpec) o; + return offset == querySpec.offset && limit == querySpec.limit && Objects.equals(filterExpression, querySpec.filterExpression) && sortOrder == querySpec.sortOrder && Objects.equals(sortField, querySpec.sortField); + } + + @Override + public String toString() { + return "QuerySpec{" + + "offset=" + offset + + ", pageSize=" + limit + + ", filterExpression=" + filterExpression + + ", sortOrder=" + sortOrder + + ", sortField=" + sortField + + '}'; + } + + public int getOffset() { + return offset; + } + + public int getLimit() { + return limit; + } + + @JsonIgnore + public Range getRange() { + return new Range(offset, offset + limit); + } + + public List getFilterExpression() { + return filterExpression; + } + + public SortOrder getSortOrder() { + return sortOrder; + } + + /** + * Checks whether any {@link Criterion} contains the given left-hand operand + */ + public boolean containsAnyLeftOperand(String leftOperand) { + return getFilterExpression().stream().anyMatch(c -> c.getOperandLeft().toString().startsWith(leftOperand)); + } + + public static final class Builder { + private final QuerySpec querySpec; + + private Builder() { + querySpec = new QuerySpec(); + } + + public static Builder newInstance() { + return new Builder(); + } + + public Builder offset(Integer offset) { + if (offset != null) { + querySpec.offset = offset; + } + return this; + } + + public Builder limit(Integer limit) { + if (limit != null) { + querySpec.limit = limit; + } + return this; + } + + public Builder range(Range range) { + offset(range.getFrom()); + limit(range.getTo() - range.getFrom()); + return this; + } + + public Builder sortOrder(SortOrder sortOrder) { + querySpec.sortOrder = sortOrder; + return this; + } + + public Builder sortField(String sortField) { + querySpec.sortField = sortField; + return this; + } + + public Builder filter(Criterion criterion) { + querySpec.filterExpression.add(criterion); + return this; + } + + public Builder filter(List criteria) { + if (criteria != null) { + querySpec.filterExpression.addAll(criteria); + } + return this; + } + + public QuerySpec build() { + if (querySpec.offset < 0) { + throw new IllegalArgumentException("offset"); + } + if (querySpec.limit <= 0) { + throw new IllegalArgumentException("limit"); + } + return querySpec; + } + + + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/Range.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/Range.java new file mode 100644 index 00000000..46fe5558 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/Range.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 Microsoft Corporation + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation + * + */ +package org.eclipse.tractusx.agents.utils; + +/** + * Represents a particular section of a collection of items. + */ +public class Range { + public static final String FROM = "from"; + public static final String TO = "to"; + private final int from; + private final int to; + + public Range(int from, int to) { + this.from = from; + this.to = to; + } + + public Range() { + this.from = 0; + this.to = Integer.MAX_VALUE; + } + + /** + * The index of the last item to be included in the range. Note that the actual number may be lower if the range + * overshoots the bounds of the collection + */ + public int getTo() { + return to; + } + + /** + * The index of the first item to be included in the range. + */ + public int getFrom() { + return from; + } + + @Override + public String toString() { + return "Range{" + + "from " + from + + ", to " + to + + '}'; + } +} \ No newline at end of file diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/SortOrder.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/SortOrder.java new file mode 100644 index 00000000..a6e0c997 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/SortOrder.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2020 - 2022 Microsoft Corporation + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation + * + */ +package org.eclipse.tractusx.agents.utils; + +/** + * Defines the sort order for query results. + */ +public enum SortOrder { + ASC, DESC +} \ No newline at end of file diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/TypeManager.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/TypeManager.java new file mode 100644 index 00000000..a8498d39 --- /dev/null +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/utils/TypeManager.java @@ -0,0 +1,172 @@ +package org.eclipse.tractusx.agents.utils; +/* + * Copyright (c) 2020 - 2022 Microsoft Corporation + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + * + * Contributors: + * Microsoft Corporation - initial API and implementation + * + */ + + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.jsontype.NamedType; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * Manages system types and is used to deserialize polymorphic types. + */ +public class TypeManager { + private final ObjectMapper defaultMapper; + + /** + * Concurrent support is not needed since this map is only populated a boot, which is single-threaded. + */ + private final Map objectMappers = new HashMap<>(); + + /** + * Default constructor. + */ + public TypeManager() { + defaultMapper = new ObjectMapper(); + defaultMapper.registerModule(new JavaTimeModule()); // configure ISO 8601 time de/serialization + defaultMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); // serialize dates in ISO 8601 format + defaultMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + registerContext("default", defaultMapper); + } + + /** + * Returns the object mapper for the default serialization context. + */ + public ObjectMapper getMapper() { + return defaultMapper; + } + + /** + * Returns the object mapper for the given serialization context, creating one based on the default mapper if required. + */ + @NotNull + public ObjectMapper getMapper(String key) { + return objectMappers.computeIfAbsent(key, k -> defaultMapper.copy()); + } + + /** + * Add custom mapper by key to list of object mappers. + */ + public void registerContext(String key, ObjectMapper mapper) { + objectMappers.put(key, mapper); + } + + /** + * Registers types with all contexts. + */ + public void registerTypes(Class... type) { + objectMappers.values().forEach(m -> m.registerSubtypes(type)); + } + + /** + * Registers types with all contexts. + */ + public void registerTypes(NamedType... type) { + objectMappers.values().forEach(m -> m.registerSubtypes(type)); + } + + /** + * Registers types with a context. + */ + public void registerTypes(String key, Class... type) { + getMapper(key).registerSubtypes(type); + } + + /** + * Registers types with a context. + */ + public void registerTypes(String key, NamedType... type) { + getMapper(key).registerSubtypes(type); + } + + /** + * Registers a serializer for the given type with a context. + */ + public void registerSerializer(String key, Class type, JsonSerializer serializer) { + var module = new SimpleModule(); + module.addSerializer(type, serializer); + getMapper(key).registerModule(module); + } + + /** + * Registers a serializer for the given type with the default context. + */ + public void registerSerializer(Class type, JsonSerializer serializer) { + var module = new SimpleModule(); + module.addSerializer(type, serializer); + getMapper().registerModule(module); + } + + /** + * Read value from string by type. + */ + public T readValue(String input, TypeReference typeReference) { + try { + return getMapper().readValue(input, typeReference); + } catch (IOException e) { + throw new MatchmakingException(e); + } + } + + public T readValue(String input, Class type) { + try { + return getMapper().readValue(input, type); + } catch (IOException e) { + throw new MatchmakingException(e); + } + } + + public T readValue(byte[] bytes, Class type) { + try { + return getMapper().readValue(bytes, type); + } catch (IOException e) { + throw new MatchmakingException(e); + } + } + + public String writeValueAsString(Object value) { + try { + return getMapper().writeValueAsString(value); + } catch (IOException e) { + throw new MatchmakingException(e); + } + } + + public byte[] writeValueAsBytes(Object value) { + try { + return getMapper().writeValueAsBytes(value); + } catch (IOException e) { + throw new MatchmakingException(e); + } + } + + public String writeValueAsString(Object value, TypeReference reference) { + try { + return getMapper().writerFor(reference).writeValueAsString(value); + } catch (IOException e) { + throw new MatchmakingException(e); + } + } +} diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/validation/DataPlaneTokenValidationApi.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/validation/DataPlaneTokenValidationApi.java similarity index 94% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/validation/DataPlaneTokenValidationApi.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/validation/DataPlaneTokenValidationApi.java index ba974e26..2065f810 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/validation/DataPlaneTokenValidationApi.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/validation/DataPlaneTokenValidationApi.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.validation; +package org.eclipse.tractusx.agents.validation; import jakarta.ws.rs.core.Response; diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/validation/SwitchingDataPlaneTokenValidatorController.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/validation/SwitchingDataPlaneTokenValidatorController.java similarity index 96% rename from matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/validation/SwitchingDataPlaneTokenValidatorController.java rename to matchmaking/src/main/java/org/eclipse/tractusx/agents/validation/SwitchingDataPlaneTokenValidatorController.java index be6599a3..7cb10e8c 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/edc/validation/SwitchingDataPlaneTokenValidatorController.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/validation/SwitchingDataPlaneTokenValidatorController.java @@ -14,7 +14,7 @@ // under the License. // // SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.edc.validation; +package org.eclipse.tractusx.agents.validation; import jakarta.ws.rs.GET; import jakarta.ws.rs.HeaderParam; @@ -25,8 +25,8 @@ import jakarta.ws.rs.core.Response; import okhttp3.OkHttpClient; import okhttp3.Request; -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.tractusx.agents.edc.AgentConfig; +import org.eclipse.tractusx.agents.AgentConfig; +import org.eclipse.tractusx.agents.utils.Monitor; import java.io.IOException; diff --git a/matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/ConformingAgentTest.java b/matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/ConformingAgentTest.java deleted file mode 100644 index 2a7675cb..00000000 --- a/matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/ConformingAgentTest.java +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.eclipse.tractusx.agents.conforming.api.JsonProvider; -import org.eclipse.tractusx.agents.conforming.api.SparqlProvider; -import org.eclipse.tractusx.agents.conforming.api.XmlProvider; -import org.glassfish.jersey.client.ClientConfig; -import org.glassfish.jersey.media.multipart.MultiPartFeature; -import org.glassfish.jersey.media.multipart.internal.MultiPartReaderClientSide; -import org.glassfish.jersey.test.DeploymentContext; -import org.glassfish.jersey.test.JerseyTest; -import org.junit.jupiter.api.Test; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -import java.io.IOException; -import java.io.StringReader; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.core.Response; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -/** - * Tests the conforming agents themselves - * common test setup and tests shared by KA-MATCH and KA-BIND profiles - */ -public abstract class ConformingAgentTest extends JerseyTest { - - protected ObjectMapper objectMapper = new ObjectMapper(); - - /** - * you cannot invoke without query or skill asset definition - */ - @Test - public void testUnderspecifiedGet() { - final Response response = target(getPath()).request().get(); - assertTrue(response.getStatus() >= 400 && response.getStatus() < 500, "KA-BIND/KA-MATCH: Should not be possible to get information without query or skill asset"); - } - - /** - * you cannot invoke without query or skill asset definition - */ - @Test - public void testUnderspecifiedPost() { - final Response response = target(getPath()).request().post(Entity.entity("", "application/sparql-results+json")); - assertTrue(response.getStatus() >= 400 && response.getStatus() < 500, "KA-BIND/KA-MATCH: Should not be possible to post information without query or skill asset"); - } - - /** - * you can always get with a simple sparql - */ - @Test - public void testBindGet() throws IOException { - Response response = target(getPath()) - .queryParam("query", "SELECT%20%3Fsubject%20%3Fpredicate%20%3Fobject%20WHERE%20%7B%20%3Fsubject%20%20%3Fobject.%7D") - .request() - .get(); - assertTrue(response.getStatus() >= 200 && response.getStatus() < 300, "Successful get json request"); - testJsonResultSet(response); - } - - /** - * you can always get with a simple sparql - */ - @Test - public void testBindGetXml() throws IOException, ParserConfigurationException, SAXException { - Response response = target(getPath()) - .queryParam("query", "SELECT%20%3Fsubject%20%3Fpredicate%20%3Fobject%20WHERE%20%7B%20%3Fsubject%20%20%3Fobject.%7D") - .request() - .accept("application/sparql-results+xml") - .get(); - assertTrue(response.getStatus() >= 200 && response.getStatus() < 300, "Successful get xml request"); - testXmlResultSet(response); - } - - protected abstract String getPath(); - - @Override - protected DeploymentContext configureDeployment() { - DeploymentContext context = super.configureDeployment(); - context.getResourceConfig().register(JsonProvider.class); - context.getResourceConfig().register(XmlProvider.class); - context.getResourceConfig().register(SparqlProvider.class); - context.getResourceConfig().packages("org.glassfish.jersey.examples.multipart") - .register(MultiPartFeature.class); - return context; - } - - @Override - protected void configureClient(ClientConfig config) { - super.configureClient(config); - config.register(MultiPartReaderClientSide.class); - } - - protected String getEntity(Response response) { - return response.readEntity(String.class); - } - - protected int getNumberVars() { - return 3; - } - - protected void testJsonResultSet(Response response) throws IOException { - String content = getEntity(response); - JsonNode node = objectMapper.readTree(content); - assertEquals(getNumberVars(), node.get("head").get("vars").size(), "Got three variables"); - assertEquals(1, node.get("results").get("bindings").size(), "got one result"); - assertEquals(getNumberVars(), node.get("results").get("bindings").get(0).size(), "got 3 bindings"); - } - - protected void testXmlResultSet(Response response) throws IOException { - DocumentBuilder builder = null; - try { - builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - } catch (ParserConfigurationException e) { - throw new IOException("Could not get Xml parser", e); - } - String content = getEntity(response); - Document document = null; - try { - document = builder.parse(new InputSource(new StringReader(content))); - } catch (SAXException e) { - throw new IOException("Cannot parse XML", e); - } - assertEquals(getNumberVars(), ((Element) document.getDocumentElement().getElementsByTagName("head").item(0)).getElementsByTagName("variable").getLength(), "Got three variables"); - assertEquals(1, ((Element) document.getDocumentElement().getElementsByTagName("results").item(0)).getElementsByTagName("result").getLength(), "got one result"); - assertEquals(getNumberVars(), ((Element) ((Element) document.getDocumentElement().getElementsByTagName("results").item(0)).getElementsByTagName("result").item(0)).getElementsByTagName("binding").getLength(), "got 3 bindings"); - } - - /** - * you can always get with a simple sparql - */ - - -} \ No newline at end of file diff --git a/matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/MatchmakingAgentTest.java b/matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/MatchmakingAgentTest.java deleted file mode 100644 index 2d47535a..00000000 --- a/matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/MatchmakingAgentTest.java +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming; - -import org.glassfish.jersey.server.ResourceConfig; -import org.junit.jupiter.api.Test; - -import java.io.IOException; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.core.Application; -import jakarta.ws.rs.core.Response; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -/** - * Tests the standard matchmaking agent. this is not a test for conformance! + - * It is rather a test for "exactness" such that the implementation tested can serve - * as a conformance tool. - */ - -public class MatchmakingAgentTest extends ConformingAgentTest { - - @Test - public void testMatchSkillGet() throws IOException { - Response response = target(getPath()).queryParam("asset", "urn:cx:SkillAsset#Test").request().get(); - assertTrue(response.getStatus() >= 200 && response.getStatus() < 300, "Successful get json request"); - testJsonResultSet(response); - } - - @Test - public void testMatchSkillPost() throws IOException { - Response response = target(getPath()).queryParam("asset", "urn:cx:SkillAsset#Test").request(). - post(Entity.entity(ConformingAgent.emptyJson, "application/sparql-results+json")); - assertTrue(response.getStatus() >= 200 && response.getStatus() < 300, "Successful post skill request"); - testJsonResultSet(response); - } - - @Test - public void testMatchSkillPostXml() throws IOException { - Response response = target(getPath()).queryParam("asset", "urn:cx:SkillAsset#Test").request() - .accept("application/sparql-results+xml") - .post(Entity.entity(ConformingAgent.emptyXml, "application/sparql-results+xml")); - assertTrue(response.getStatus() >= 200 && response.getStatus() < 300, "Successful post skill xml request"); - testXmlResultSet(response); - } - - @Test - public void testMatchSkillPostJsonXml() throws IOException { - Response response = target(getPath()).queryParam("asset", "urn:cx:SkillAsset#Test").request() - .accept("application/sparql-results+json") - .post(Entity.entity(ConformingAgent.emptyXml, "application/sparql-results+xml")); - assertTrue(response.getStatus() >= 200 && response.getStatus() < 300, "Successful post skill json request"); - testJsonResultSet(response); - } - - @Test - public void testMatchSkillPostXmlJson() throws IOException { - Response response = target(getPath()).queryParam("asset", "urn:cx:SkillAsset#Test").request() - .accept("application/sparql-results+xml") - .post(Entity.entity(ConformingAgent.emptyJson, "application/sparql-results+json")); - assertTrue(response.getStatus() >= 200 && response.getStatus() < 300, "Successful post skill xml request"); - testXmlResultSet(response); - } - - @Override - protected String getPath() { - return "/match"; - } - - @Override - protected int getNumberVars() { - return 3; - } - - @Override - protected Application configure() { - return new ResourceConfig(MatchmakingAgent.class); - } - -} diff --git a/matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/TransferAgentTest.java b/matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/TransferAgentTest.java deleted file mode 100644 index 76224616..00000000 --- a/matchmaking/src/test/java/org/eclipse/tractusx/agents/conforming/TransferAgentTest.java +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2022,2024 Contributors to the Eclipse Foundation -// -// See the NOTICE file(s) distributed with this work for additional -// information regarding copyright ownership. -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0. -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. -// -// SPDX-License-Identifier: Apache-2.0 -package org.eclipse.tractusx.agents.conforming; - -import org.glassfish.jersey.media.multipart.FormDataMultiPart; -import org.glassfish.jersey.server.ResourceConfig; - -import jakarta.ws.rs.core.Application; -import jakarta.ws.rs.core.Response; - -/** - * Tests the standard transfer agent. this is not a test for conformance! + - * It is rather a test for "exactness" such that the implementation tested can serve - * as a conformance tool. - */ - -public class TransferAgentTest extends MatchmakingAgentTest { - - @Override - protected String getEntity(Response response) { - return response.readEntity(FormDataMultiPart.class).getBodyParts().get(0).getEntityAs(String.class); - } - - @Override - protected String getPath() { - return "/transfer"; - } - - @Override - protected Application configure() { - return new ResourceConfig(TransferAgent.class); - } - -} diff --git a/pom.xml b/pom.xml index 2aa8f0df..86d6a644 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,6 @@ 11 false - 0.2.1 5.9.0 4.6.1 3.2.4 From 0e976f0f74c9bc013ba991d1d756940e3e1fa31d Mon Sep 17 00:00:00 2001 From: Martin Date: Fri, 15 Mar 2024 13:38:38 +0100 Subject: [PATCH 03/15] amended pom and generated DEPENDENCIES for feature-97 --- DEPENDENCIES | 82 +++++++++++++++++++++++++++++++++++++++++++++ matchmaking/pom.xml | 2 +- 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/DEPENDENCIES b/DEPENDENCIES index 97e2a038..837423d9 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -1,8 +1,11 @@ maven/mavencentral/aopalliance/aopalliance/1.0, LicenseRef-Public-Domain, approved, CQ2918 maven/mavencentral/ch.qos.logback/logback-classic/1.2.13, EPL-1.0, approved, CQ13636 maven/mavencentral/ch.qos.logback/logback-classic/1.4.12, EPL-1.0 OR LGPL-2.1-only, approved, #3435 +maven/mavencentral/ch.qos.logback/logback-classic/1.4.8, EPL-1.0 OR LGPL-2.1-only, approved, #3435 maven/mavencentral/ch.qos.logback/logback-core/1.2.13, EPL-1.0, approved, CQ13635 maven/mavencentral/ch.qos.logback/logback-core/1.4.12, EPL-1.0 OR LGPL-2.1-only, approved, #3373 +maven/mavencentral/ch.qos.logback/logback-core/1.4.8, EPL-1.0 OR LGPL-2.1-only, approved, #3373 +maven/mavencentral/com.apicatalog/titanium-json-ld/1.3.2, Apache-2.0, approved, #8912 maven/mavencentral/com.fasterxml.jackson.core/jackson-annotations/2.13.5, Apache-2.0, approved, clearlydefined maven/mavencentral/com.fasterxml.jackson.core/jackson-annotations/2.15.2, Apache-2.0, approved, #7947 maven/mavencentral/com.fasterxml.jackson.core/jackson-core/2.13.5, Apache-2.0, approved, #2133 @@ -19,12 +22,16 @@ maven/mavencentral/com.fasterxml.jackson.datatype/jackson-datatype-jsr310/2.13.5 maven/mavencentral/com.fasterxml.jackson.datatype/jackson-datatype-jsr310/2.15.1, Apache-2.0, approved, #7930 maven/mavencentral/com.fasterxml.jackson.jaxrs/jackson-jaxrs-base/2.15.2, Apache-2.0, approved, #11061 maven/mavencentral/com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider/2.15.2, Apache-2.0, approved, #9101 +maven/mavencentral/com.fasterxml.jackson.module/jackson-module-jakarta-xmlbind-annotations/2.14.1, Apache-2.0, approved, #5308 maven/mavencentral/com.fasterxml.jackson.module/jackson-module-jaxb-annotations/2.15.2, Apache-2.0, approved, #9100 maven/mavencentral/com.fasterxml.jackson.module/jackson-module-parameter-names/2.13.5, Apache-2.0, approved, clearlydefined maven/mavencentral/com.fasterxml.woodstox/woodstox-core/6.5.1, Apache-2.0, approved, #7950 +maven/mavencentral/com.github.andrewoma.dexx/collection/0.7, MIT, approved, CQ22160 maven/mavencentral/com.github.jsonld-java/jsonld-java/0.13.4, BSD-3-Clause, approved, CQ22136 maven/mavencentral/com.github.jsqlparser/jsqlparser/4.4, LGPL-2.1 OR Apache-2.0, approved, clearlydefined +maven/mavencentral/com.github.stephenc.jcip/jcip-annotations/1.0-1, Apache-2.0, approved, CQ21949 maven/mavencentral/com.google.code.findbugs/jsr305/3.0.2, Apache-2.0, approved, #20 +maven/mavencentral/com.google.code.gson/gson/2.8.8, Apache-2.0, approved, CQ23496 maven/mavencentral/com.google.errorprone/error_prone_annotations/2.18.0, Apache-2.0, approved, clearlydefined maven/mavencentral/com.google.guava/failureaccess/1.0.1, Apache-2.0, approved, CQ22654 maven/mavencentral/com.google.guava/guava/32.1.2-jre, Apache-2.0 AND CC0-1.0 AND LicenseRef-Public-Domain, approved, #9229 @@ -32,10 +39,16 @@ maven/mavencentral/com.google.guava/listenablefuture/9999.0-empty-to-avoid-confl maven/mavencentral/com.google.inject.extensions/guice-assistedinject/5.0.1, Apache-2.0, approved, clearlydefined maven/mavencentral/com.google.inject/guice/5.0.1, Apache-2.0, approved, clearlydefined maven/mavencentral/com.google.j2objc/j2objc-annotations/2.8, Apache-2.0, approved, clearlydefined +maven/mavencentral/com.google.protobuf/protobuf-java/3.22.2, BSD-3-Clause, approved, #8370 maven/mavencentral/com.jayway.jsonpath/json-path/2.7.0, Apache-2.0, approved, clearlydefined +maven/mavencentral/com.nimbusds/nimbus-jose-jwt/9.31, Apache-2.0, approved, clearlydefined maven/mavencentral/com.opencsv/opencsv/5.3, Apache-2.0, approved, clearlydefined +maven/mavencentral/com.squareup.okhttp3/okhttp/4.9.3, Apache-2.0 AND MPL-2.0, approved, #3225 +maven/mavencentral/com.squareup.okio/okio-jvm/3.4.0, Apache-2.0, approved, clearlydefined +maven/mavencentral/com.squareup.okio/okio/3.4.0, Apache-2.0, approved, clearlydefined maven/mavencentral/com.vaadin.external.google/android-json/0.0.20131108.vaadin1, Apache-2.0, approved, CQ21310 maven/mavencentral/commons-beanutils/commons-beanutils/1.9.4, Apache-2.0, approved, CQ12654 +maven/mavencentral/commons-cli/commons-cli/1.5.0, Apache-2.0, approved, clearlydefined maven/mavencentral/commons-codec/commons-codec/1.14, Apache-2.0, approved, clearlydefined maven/mavencentral/commons-codec/commons-codec/1.15, Apache-2.0 AND BSD-3-Clause AND LicenseRef-Public-Domain, approved, CQ22641 maven/mavencentral/commons-collections/commons-collections/3.2.2, Apache-2.0, approved, CQ10385 @@ -44,7 +57,11 @@ maven/mavencentral/commons-lang/commons-lang/2.6, Apache-2.0, approved, CQ6183 maven/mavencentral/commons-logging/commons-logging/1.2, Apache-2.0, approved, CQ10162 maven/mavencentral/io.github.classgraph/classgraph/4.8.154, MIT, approved, CQ22530 maven/mavencentral/io.github.solf/nullanno/3.0.0, EPL-1.0, approved, #11625 +maven/mavencentral/io.micrometer/micrometer-commons/1.10.5, Apache-2.0 AND (Apache-2.0 AND MIT), approved, #7333 +maven/mavencentral/io.micrometer/micrometer-core/1.10.5, Apache-2.0 AND (Apache-2.0 AND MIT), approved, #6977 maven/mavencentral/io.micrometer/micrometer-core/1.9.17, Apache-2.0 AND (Apache-2.0 AND MIT), approved, #7711 +maven/mavencentral/io.micrometer/micrometer-observation/1.10.5, Apache-2.0, approved, #7331 +maven/mavencentral/io.micrometer/micrometer-registry-prometheus/1.10.5, Apache-2.0, approved, #4721 maven/mavencentral/io.mikael/urlbuilder/2.0.9, Apache-2.0, approved, #9815 maven/mavencentral/io.netty/netty-buffer/4.1.94.Final, Apache-2.0, approved, CQ21842 maven/mavencentral/io.netty/netty-codec/4.1.94.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 @@ -55,6 +72,11 @@ maven/mavencentral/io.netty/netty-transport-classes-epoll/4.1.94.Final, Apache-2 maven/mavencentral/io.netty/netty-transport-native-epoll/4.1.94.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 maven/mavencentral/io.netty/netty-transport-native-unix-common/4.1.94.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 maven/mavencentral/io.netty/netty-transport/4.1.94.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 +maven/mavencentral/io.prometheus/simpleclient/0.16.0, Apache-2.0, approved, clearlydefined +maven/mavencentral/io.prometheus/simpleclient_common/0.16.0, Apache-2.0, approved, clearlydefined +maven/mavencentral/io.prometheus/simpleclient_tracer_common/0.16.0, Apache-2.0, approved, clearlydefined +maven/mavencentral/io.prometheus/simpleclient_tracer_otel/0.16.0, Apache-2.0, approved, clearlydefined +maven/mavencentral/io.prometheus/simpleclient_tracer_otel_agent/0.16.0, Apache-2.0, approved, clearlydefined maven/mavencentral/io.sgr/s2-geometry-library-java/1.0.0, Apache-2.0, approved, CQ22121 maven/mavencentral/io.swagger.core.v3/swagger-annotations/2.2.12, Apache-2.0, approved, #11362 maven/mavencentral/io.swagger.core.v3/swagger-core/2.2.12, Apache-2.0, approved, #9265 @@ -65,14 +87,22 @@ maven/mavencentral/it.unibz.inf.ontop/ontop-model/5.1.2, Apache-2.0, approved, # maven/mavencentral/it.unibz.inf.ontop/ontop-obda-core/5.1.2, Apache-2.0, approved, #11623 maven/mavencentral/it.unibz.inf.ontop/ontop-rdb/5.1.2, Apache-2.0, approved, #11626 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 +maven/mavencentral/jakarta.activation/jakarta.activation-api/2.1.0, EPL-2.0 OR BSD-3-Clause OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jaf maven/mavencentral/jakarta.annotation/jakarta.annotation-api/1.3.5, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.ca +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 +maven/mavencentral/jakarta.inject/jakarta.inject-api/2.0.1, Apache-2.0, approved, ee4j.cdi maven/mavencentral/jakarta.servlet/jakarta.servlet-api/4.0.4, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.servlet +maven/mavencentral/jakarta.servlet/jakarta.servlet-api/6.0.0, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.servlet maven/mavencentral/jakarta.validation/jakarta.validation-api/2.0.2, Apache-2.0, approved, ee4j.validation +maven/mavencentral/jakarta.validation/jakarta.validation-api/3.0.2, Apache-2.0, approved, ee4j.validation maven/mavencentral/jakarta.ws.rs/jakarta.ws.rs-api/2.1.6, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.rest +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 maven/mavencentral/jakarta.xml.bind/jakarta.xml.bind-api/2.3.3, BSD-3-Clause, approved, ee4j.jaxb +maven/mavencentral/jakarta.xml.bind/jakarta.xml.bind-api/4.0.0, BSD-3-Clause, approved, ee4j.jaxb maven/mavencentral/javax.activation/javax.activation-api/1.2.0, (CDDL-1.1 OR GPL-2.0 WITH Classpath-exception-2.0) AND Apache-2.0, approved, CQ18740 maven/mavencentral/javax.inject/javax.inject/1, Apache-2.0, approved, CQ3555 maven/mavencentral/javax.servlet/javax.servlet-api/3.1.0, (CDDL-1.1 OR GPL-2.0-only WITH Classpath-exception-2.0) AND Apache-2.0, approved, CQ7248 +maven/mavencentral/javax.servlet/javax.servlet-api/4.0.1, (CDDL-1.1 OR GPL-2.0-only WITH Classpath-exception-2.0) AND Apache-2.0, approved, CQ16125 maven/mavencentral/javax.servlet/servlet-api/2.5, Apache-2.0, approved, CQ1961 maven/mavencentral/javax.validation/validation-api/2.0.1.Final, Apache-2.0, approved, CQ15302 maven/mavencentral/javax.xml.bind/jaxb-api/2.3.1, CDDL-1.1 OR GPL-2.0-only WITH Classpath-exception-2.0, approved, CQ16911 @@ -82,6 +112,8 @@ maven/mavencentral/net.bytebuddy/byte-buddy/1.12.21, Apache-2.0 AND BSD-3-Clause maven/mavencentral/net.minidev/accessors-smart/2.4.7, Apache-2.0, approved, #7515 maven/mavencentral/net.minidev/json-smart/2.4.7, Apache-2.0, approved, #3288 maven/mavencentral/org.apache.commons/commons-collections4/4.4, Apache-2.0, approved, clearlydefined +maven/mavencentral/org.apache.commons/commons-compress/1.23.0, Apache-2.0 AND BSD-3-Clause, approved, #7506 +maven/mavencentral/org.apache.commons/commons-csv/1.10.0, Apache-2.0, approved, clearlydefined maven/mavencentral/org.apache.commons/commons-lang3/3.12.0, Apache-2.0, approved, clearlydefined maven/mavencentral/org.apache.commons/commons-math3/3.6.1, Apache-2.0 AND BSD-3-Clause AND BSD-2-Clause, approved, CQ22025 maven/mavencentral/org.apache.commons/commons-rdf-api/0.5.0, Apache-2.0, approved, clearlydefined @@ -99,6 +131,23 @@ maven/mavencentral/org.apache.httpcomponents/httpcore/4.4.14, Apache-2.0, approv maven/mavencentral/org.apache.httpcomponents/httpcore/4.4.16, Apache-2.0, approved, CQ23528 maven/mavencentral/org.apache.httpcomponents/httpmime/4.5.13, Apache-2.0, approved, CQ11718 maven/mavencentral/org.apache.httpcomponents/httpmime/4.5.14, Apache-2.0, approved, CQ11718 +maven/mavencentral/org.apache.jena/jena-arq/4.8.0, Apache-2.0 AND (Apache-2.0 AND EPL-2.0) AND (Apache-2.0 AND EPL-1.0), approved, #8883 +maven/mavencentral/org.apache.jena/jena-base/4.8.0, Apache-2.0, approved, #8887 +maven/mavencentral/org.apache.jena/jena-core/4.8.0, Apache-2.0 AND (Apache-2.0 AND BSD-3-Clause), approved, #8873 +maven/mavencentral/org.apache.jena/jena-dboe-base/4.8.0, Apache-2.0, approved, #8884 +maven/mavencentral/org.apache.jena/jena-dboe-index/4.8.0, Apache-2.0, approved, #8879 +maven/mavencentral/org.apache.jena/jena-dboe-storage/4.8.0, Apache-2.0, approved, #8907 +maven/mavencentral/org.apache.jena/jena-dboe-trans-data/4.8.0, Apache-2.0, approved, #8874 +maven/mavencentral/org.apache.jena/jena-dboe-transaction/4.8.0, Apache-2.0, approved, #8892 +maven/mavencentral/org.apache.jena/jena-fuseki-core/4.8.0, Apache-2.0 AND (EPL-2.0 OR Apache-2.0), approved, #9841 +maven/mavencentral/org.apache.jena/jena-iri/4.8.0, Apache-2.0, approved, clearlydefined +maven/mavencentral/org.apache.jena/jena-rdfconnection/4.8.0, Apache-2.0, approved, #8897 +maven/mavencentral/org.apache.jena/jena-rdfpatch/4.8.0, Apache-2.0, approved, #8903 +maven/mavencentral/org.apache.jena/jena-shacl/4.8.0, Apache-2.0 AND W3C-20150513, approved, #8905 +maven/mavencentral/org.apache.jena/jena-shaded-guava/4.8.0, Apache-2.0 AND CC0-1.0 AND LicenseRef-Public-Domain, approved, #8877 +maven/mavencentral/org.apache.jena/jena-shex/4.8.0, Apache-2.0, approved, #8908 +maven/mavencentral/org.apache.jena/jena-tdb/4.8.0, Apache-2.0, approved, #8909 +maven/mavencentral/org.apache.jena/jena-tdb2/4.8.0, Apache-2.0, approved, #8881 maven/mavencentral/org.apache.logging.log4j/log4j-api/2.17.2, Apache-2.0, approved, clearlydefined maven/mavencentral/org.apache.logging.log4j/log4j-to-slf4j/2.17.2, Apache-2.0, approved, #2163 maven/mavencentral/org.apache.lucene/lucene-analyzers-common/8.9.0, Apache-2.0 AND BSD-3-Clause AND LicenseRef-scancode-iso-8879, approved, #6152 @@ -112,6 +161,7 @@ maven/mavencentral/org.apache.lucene/lucene-sandbox/8.9.0, Apache-2.0, approved, maven/mavencentral/org.apache.lucene/lucene-spatial-extras/8.9.0, Apache-2.0, approved, #6138 maven/mavencentral/org.apache.lucene/lucene-spatial3d/8.9.0, Apache-2.0, approved, #6140 maven/mavencentral/org.apache.solr/solr-solrj/8.9.0, Apache-2.0 AND (Apache-2.0 AND MIT), approved, #6141 +maven/mavencentral/org.apache.thrift/libthrift/0.18.1, Apache-2.0, approved, #8911 maven/mavencentral/org.apache.tomcat.embed/tomcat-embed-core/9.0.83, Apache-2.0 AND (CDDL-1.0 OR GPL-2.0 WITH Classpath-exception-2.0), approved, CQ20188 maven/mavencentral/org.apache.tomcat.embed/tomcat-embed-el/9.0.83, Apache-2.0, approved, CQ20193 maven/mavencentral/org.apache.tomcat.embed/tomcat-embed-websocket/9.0.83, Apache-2.0, approved, CQ20194 @@ -130,11 +180,19 @@ maven/mavencentral/org.eclipse.jetty.http2/http2-client/9.4.52.v20230823, EPL-2. maven/mavencentral/org.eclipse.jetty.http2/http2-common/9.4.52.v20230823, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty.http2/http2-hpack/9.4.53.v20231009, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty.http2/http2-http-client-transport/9.4.52.v20230823, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty.toolchain/jetty-jakarta-servlet-api/5.0.2, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty/jetty-alpn-client/9.4.53.v20231009, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty/jetty-alpn-java-client/9.4.53.v20231009, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty/jetty-client/9.4.53.v20231009, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-http/11.0.15, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty/jetty-http/9.4.53.v20231009, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-io/11.0.15, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty/jetty-io/9.4.53.v20231009, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-security/11.0.20, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-server/11.0.15, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-servlet/11.0.20, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-servlets/10.0.14, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-util/11.0.15, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty/jetty-util/9.4.53.v20231009, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.rdf4j/rdf4j-client/4.3.8, BSD-3-Clause, approved, technology.rdf4j maven/mavencentral/org.eclipse.rdf4j/rdf4j-collection-factory-api/4.3.8, BSD-3-Clause, approved, technology.rdf4j @@ -212,25 +270,49 @@ maven/mavencentral/org.eclipse.rdf4j/rdf4j-sparqlbuilder/4.3.8, BSD-3-Clause, ap maven/mavencentral/org.eclipse.rdf4j/rdf4j-spin/4.3.8, BSD-3-Clause, approved, technology.rdf4j maven/mavencentral/org.eclipse.rdf4j/rdf4j-storage/4.3.8, BSD-3-Clause, approved, technology.rdf4j maven/mavencentral/org.glassfish.hk2.external/aopalliance-repackaged/2.6.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish +maven/mavencentral/org.glassfish.hk2.external/aopalliance-repackaged/3.0.4, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish maven/mavencentral/org.glassfish.hk2.external/jakarta.inject/2.6.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish maven/mavencentral/org.glassfish.hk2/hk2-api/2.6.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish +maven/mavencentral/org.glassfish.hk2/hk2-api/3.0.4, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish maven/mavencentral/org.glassfish.hk2/hk2-locator/2.6.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish +maven/mavencentral/org.glassfish.hk2/hk2-locator/3.0.4, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish maven/mavencentral/org.glassfish.hk2/hk2-utils/2.6.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish +maven/mavencentral/org.glassfish.hk2/hk2-utils/3.0.4, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish maven/mavencentral/org.glassfish.hk2/osgi-resource-locator/1.0.3, CDDL-1.0, approved, CQ10889 +maven/mavencentral/org.glassfish.jersey.containers/jersey-container-jetty-http/3.1.3, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey maven/mavencentral/org.glassfish.jersey.containers/jersey-container-servlet-core/2.40, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey +maven/mavencentral/org.glassfish.jersey.containers/jersey-container-servlet-core/3.1.3, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey +maven/mavencentral/org.glassfish.jersey.containers/jersey-container-servlet/3.1.3, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey maven/mavencentral/org.glassfish.jersey.containers/jersey-container-simple-http/2.40, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey +maven/mavencentral/org.glassfish.jersey.containers/jersey-container-simple-http/3.1.3, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey maven/mavencentral/org.glassfish.jersey.core/jersey-client/2.40, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey +maven/mavencentral/org.glassfish.jersey.core/jersey-client/3.1.3, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey maven/mavencentral/org.glassfish.jersey.core/jersey-common/2.40, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey +maven/mavencentral/org.glassfish.jersey.core/jersey-common/3.1.3, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey maven/mavencentral/org.glassfish.jersey.core/jersey-server/2.40, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey +maven/mavencentral/org.glassfish.jersey.core/jersey-server/3.1.3, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey +maven/mavencentral/org.glassfish.jersey.ext/jersey-entity-filtering/3.1.3, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey maven/mavencentral/org.glassfish.jersey.inject/jersey-hk2/2.40, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey +maven/mavencentral/org.glassfish.jersey.inject/jersey-hk2/3.1.3, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey maven/mavencentral/org.glassfish.jersey.media/jersey-media-jaxb/2.40, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey +maven/mavencentral/org.glassfish.jersey.media/jersey-media-jaxb/3.1.3, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey +maven/mavencentral/org.glassfish.jersey.media/jersey-media-json-jackson/3.1.3, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey maven/mavencentral/org.glassfish.jersey.media/jersey-media-multipart/2.40, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey +maven/mavencentral/org.glassfish.jersey.media/jersey-media-multipart/3.1.3, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey maven/mavencentral/org.glassfish.jersey.test-framework.providers/jersey-test-framework-provider-simple/2.40, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey +maven/mavencentral/org.glassfish.jersey.test-framework.providers/jersey-test-framework-provider-simple/3.1.3, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey maven/mavencentral/org.glassfish.jersey.test-framework/jersey-test-framework-core/2.40, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey +maven/mavencentral/org.glassfish.jersey.test-framework/jersey-test-framework-core/3.1.3, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey +maven/mavencentral/org.glassfish/jakarta.json/2.0.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jsonp maven/mavencentral/org.hamcrest/hamcrest/2.2, BSD-3-Clause, approved, clearlydefined maven/mavencentral/org.hdrhistogram/HdrHistogram/2.1.12, BSD-2-Clause OR LicenseRef-Public-Domain, approved, CQ13192 maven/mavencentral/org.javabits.jgrapht/jgrapht-core/0.9.3, EPL-2.0 OR LGPL-2.1-or-later, approved, #9816 maven/mavencentral/org.javassist/javassist/3.29.2-GA, Apache-2.0 AND LGPL-2.1-or-later AND MPL-1.1, approved, #6023 +maven/mavencentral/org.jetbrains.kotlin/kotlin-stdlib-common/1.8.0, Apache-2.0, approved, #8910 +maven/mavencentral/org.jetbrains.kotlin/kotlin-stdlib-jdk7/1.8.0, Apache-2.0, approved, #8807 +maven/mavencentral/org.jetbrains.kotlin/kotlin-stdlib-jdk8/1.8.0, Apache-2.0, approved, #8919 +maven/mavencentral/org.jetbrains.kotlin/kotlin-stdlib/1.4.10, Apache-2.0, approved, clearlydefined +maven/mavencentral/org.jetbrains/annotations/24.1.0, Apache-2.0, approved, clearlydefined maven/mavencentral/org.junit.jupiter/junit-jupiter-api/5.9.2, EPL-2.0, approved, #3133 maven/mavencentral/org.junit.jupiter/junit-jupiter-engine/5.9.2, EPL-2.0, approved, #3125 maven/mavencentral/org.junit.jupiter/junit-jupiter-params/5.9.2, EPL-2.0, approved, #3134 diff --git a/matchmaking/pom.xml b/matchmaking/pom.xml index 72176bd3..b2978aa0 100644 --- a/matchmaking/pom.xml +++ b/matchmaking/pom.xml @@ -27,7 +27,7 @@ org.eclipse.tractusx agents - 1.10.15-SNAPSHOT + 1.12.17-SNAPSHOT ../pom.xml From bc77fef1994d462ef61a0bab3e461bd043a269c4 Mon Sep 17 00:00:00 2001 From: "Dr. Christoph \"Schorsch\" Jung" Date: Tue, 2 Apr 2024 13:29:28 +0200 Subject: [PATCH 04/15] chore: minimize dependencies to different versions in submodules. --- .github/workflows/build.yml | 2 +- charts/matchmaking-agent/Chart.yaml | 4 +-- conforming/pom.xml | 15 +++++----- matchmaking/README.md | 6 ++-- matchmaking/pom.xml | 29 +++++++------------ .../JakartaServletInputStreamAdapter.java | 5 ++-- .../JakartaServletOutputStreamAdapter.java | 5 ++-- pom.xml | 19 +++++++++--- provisioning/pom.xml | 6 ++++ remoting/pom.xml | 10 +++---- 10 files changed, 53 insertions(+), 48 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9c7af9a9..d8fef415 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -275,6 +275,6 @@ jobs: type=semver,pattern={{version}} type=semver,pattern={{major}} type=semver,pattern={{major}}.{{minor}} - type=raw,value=1.10.15-SNAPSHOT,enable=${{ github.event.inputs.deploy_docker == 'true' || github.ref == format('refs/heads/{0}', 'main') }} + type=raw,value=1.12.17-SNAPSHOT,enable=${{ github.event.inputs.deploy_docker == 'true' || github.ref == format('refs/heads/{0}', 'main') }} type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }} diff --git a/charts/matchmaking-agent/Chart.yaml b/charts/matchmaking-agent/Chart.yaml index 1c192caa..8ac74b1d 100644 --- a/charts/matchmaking-agent/Chart.yaml +++ b/charts/matchmaking-agent/Chart.yaml @@ -28,7 +28,7 @@ home: https://github.com/eclipse-tractusx/knowledge-agents/ sources: - https://github.com/eclipse-tractusx/knowledge-agents/tree/main/matchmaking type: application -appVersion: "1.10.15-SNAPSHOT" -version: 1.10.15-SNAPSHOT +appVersion: "1.12.17-SNAPSHOT" +version: 1.12.17-SNAPSHOT maintainers: - name: 'Tractus-X Knowledge Agents Team' diff --git a/conforming/pom.xml b/conforming/pom.xml index dc6bc251..c69ec2a6 100644 --- a/conforming/pom.xml +++ b/conforming/pom.xml @@ -50,12 +50,6 @@ ${symbolic.name}-${project.version} true false - 2.2.12 - 2.40 - 4.13.1 - 1.4.12 - 2.5 - 2.0.1.Final @@ -69,15 +63,20 @@ ch.qos.logback logback-classic - ${logback-version} + ${logback.version} compile ch.qos.logback logback-core - ${logback-version} + ${logback.version} compile + + org.slf4j + slf4j-api + ${slf4j.version} + javax.servlet servlet-api diff --git a/matchmaking/README.md b/matchmaking/README.md index 264593e9..46f6d3b3 100644 --- a/matchmaking/README.md +++ b/matchmaking/README.md @@ -66,10 +66,10 @@ This will generate ### Run Locally -The [standalone jar](target/matchmaking-agent-1.10.15-SNAPSHOT.jar) may be started as follows +The [standalone jar](target/matchmaking-agent-1.12.17-SNAPSHOT.jar) may be started as follows ```console -java -Dproperty.file.location="dataplane.properties" -cp ../matchmaking-agent-1.10.15-SNAPSHOT.jar org.eclipse.tractusx.agents.conforming.Bootstrap +java -Dproperty.file.location="dataplane.properties" -cp ../matchmaking-agent-1.12.17-SNAPSHOT.jar org.eclipse.tractusx.agents.conforming.Bootstrap ``` Make sure that jar file, properties file and dataspace.ttl are in the same directory Then you should be able to reach the /graph endpoint @@ -126,7 +126,7 @@ It can be added to your umbrella chart.yaml by the following snippet dependencies: - name: matchmaking-agent repository: https://eclipse-tractusx.github.io/charts/dev - version: 1.10.15-SNAPSHOT + version: 1.12.17-SNAPSHOT alias: my-matchmmaking-agent ``` diff --git a/matchmaking/pom.xml b/matchmaking/pom.xml index b2978aa0..2d061ea4 100644 --- a/matchmaking/pom.xml +++ b/matchmaking/pom.xml @@ -46,28 +46,14 @@ ${symbolic.name}-${project.version} true false - 2.2.12 - 3.1.3 - 4.13.1 - 1.4.8 - 4.8.0 - 3.4.0 - 2.5 - 2.0.1.Final - 24.1.0 - - org.jetbrains - annotations - ${jetbrain-annotation} - com.google.code.gson gson - 2.8.8 + ${gson.version} io.swagger.core.v3 @@ -78,16 +64,21 @@ ch.qos.logback logback-classic - ${logback-version} + ${logback.version} compile ch.qos.logback logback-core - ${logback-version} + ${logback.version} compile - + + org.slf4j + slf4j-api + ${slf4j.version} + + javax.servlet javax.servlet-api ${javax.servlet-api.version} @@ -169,7 +160,7 @@ org.eclipse.jetty jetty-servlet - 11.0.20 + ${jetty-servlet.version} org.eclipse.jetty.toolchain diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaServletInputStreamAdapter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaServletInputStreamAdapter.java index b17e2f4d..5f0e6066 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaServletInputStreamAdapter.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaServletInputStreamAdapter.java @@ -18,7 +18,6 @@ import jakarta.servlet.ServletInputStream; import org.eclipse.tractusx.agents.utils.Monitor; -import org.jetbrains.annotations.NotNull; import java.io.IOException; import javax.servlet.ReadListener; @@ -68,12 +67,12 @@ public int read() throws IOException { } @Override - public int read(byte @NotNull [] buf) throws IOException { + public int read(byte[] buf) throws IOException { return jakartaDelegate.read(buf); } @Override - public int read(byte @NotNull [] b, int off, int len) throws IOException { + public int read(byte[] b, int off, int len) throws IOException { return jakartaDelegate.read(b, off, len); } diff --git a/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaServletOutputStreamAdapter.java b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaServletOutputStreamAdapter.java index 06469130..a56aed1b 100644 --- a/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaServletOutputStreamAdapter.java +++ b/matchmaking/src/main/java/org/eclipse/tractusx/agents/http/JakartaServletOutputStreamAdapter.java @@ -18,7 +18,6 @@ import jakarta.servlet.ServletOutputStream; import org.eclipse.tractusx.agents.utils.Monitor; -import org.jetbrains.annotations.NotNull; import java.io.IOException; import javax.servlet.WriteListener; @@ -63,12 +62,12 @@ public void write(int b) throws IOException { } @Override - public void write(byte @NotNull [] b) throws IOException { + public void write(byte[] b) throws IOException { jakartaDelegate.write(b); } @Override - public void write(byte @NotNull [] b, int off, int len) throws IOException { + public void write(byte[] b, int off, int len) throws IOException { jakartaDelegate.write(b, off, len); } diff --git a/pom.xml b/pom.xml index d65172c6..a04ab1ef 100644 --- a/pom.xml +++ b/pom.xml @@ -42,10 +42,8 @@ 3.2.4 4.9.3 4.3.8 - 2.0.7 4.5.14 1.2 - 1.2.13 2.15.2 2.15.2 2.13.5 @@ -55,8 +53,6 @@ 4.0.1 2.3.1 5.1.2 - - UTF-8 3.1.0 5.3.31 2.7.18 @@ -68,6 +64,21 @@ 1.1.10.5 42.6.0 3.7.2 + 2.2.12 + 2.40 + 3.1.3 + 11.0.15 + 4.8.0 + 3.4.0 + 2.5 + 2.0.1.Final + 2.10.1 + 1.2.13 + 2.0.7 + + + UTF-8 + tractusx/ linux/amd64 diff --git a/provisioning/pom.xml b/provisioning/pom.xml index eefa00ac..b3f17c58 100644 --- a/provisioning/pom.xml +++ b/provisioning/pom.xml @@ -113,6 +113,12 @@ ${logback.version} test + + org.slf4j + slf4j-api + ${slf4j.version} + test + org.springframework.boot spring-boot-actuator diff --git a/remoting/pom.xml b/remoting/pom.xml index cb12db57..bd56fc68 100644 --- a/remoting/pom.xml +++ b/remoting/pom.xml @@ -89,11 +89,11 @@ ${logback.version} - - org.slf4j - slf4j-simple - ${slf4j.version} - + + org.slf4j + slf4j-api + ${slf4j.version} + org.junit.jupiter From da02a50ff0a1f79a286ee1a52db84d8f9474ff59 Mon Sep 17 00:00:00 2001 From: "Dr. Christoph \"Schorsch\" Jung" Date: Tue, 2 Apr 2024 14:18:37 +0200 Subject: [PATCH 05/15] chore: more version streamlining --- DEPENDENCIES | 31 ++++++++++--------------------- conforming/pom.xml | 15 +++++++++++++++ matchmaking/pom.xml | 20 ++++++++++++++++++++ pom.xml | 2 -- provisioning/pom.xml | 30 +++++++++++++++++++++++++++--- remoting/pom.xml | 29 ++++++++++++++++++++++++++++- 6 files changed, 100 insertions(+), 27 deletions(-) diff --git a/DEPENDENCIES b/DEPENDENCIES index 837423d9..c5ca6413 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -1,37 +1,28 @@ maven/mavencentral/aopalliance/aopalliance/1.0, LicenseRef-Public-Domain, approved, CQ2918 maven/mavencentral/ch.qos.logback/logback-classic/1.2.13, EPL-1.0, approved, CQ13636 -maven/mavencentral/ch.qos.logback/logback-classic/1.4.12, EPL-1.0 OR LGPL-2.1-only, approved, #3435 -maven/mavencentral/ch.qos.logback/logback-classic/1.4.8, EPL-1.0 OR LGPL-2.1-only, approved, #3435 maven/mavencentral/ch.qos.logback/logback-core/1.2.13, EPL-1.0, approved, CQ13635 -maven/mavencentral/ch.qos.logback/logback-core/1.4.12, EPL-1.0 OR LGPL-2.1-only, approved, #3373 -maven/mavencentral/ch.qos.logback/logback-core/1.4.8, EPL-1.0 OR LGPL-2.1-only, approved, #3373 maven/mavencentral/com.apicatalog/titanium-json-ld/1.3.2, Apache-2.0, approved, #8912 -maven/mavencentral/com.fasterxml.jackson.core/jackson-annotations/2.13.5, Apache-2.0, approved, clearlydefined maven/mavencentral/com.fasterxml.jackson.core/jackson-annotations/2.15.2, Apache-2.0, approved, #7947 -maven/mavencentral/com.fasterxml.jackson.core/jackson-core/2.13.5, Apache-2.0, approved, #2133 maven/mavencentral/com.fasterxml.jackson.core/jackson-core/2.15.2, MIT AND Apache-2.0, approved, #7932 -maven/mavencentral/com.fasterxml.jackson.core/jackson-databind/2.13.5, Apache-2.0, approved, #2134 -maven/mavencentral/com.fasterxml.jackson.core/jackson-databind/2.15.1, Apache-2.0, approved, #7934 maven/mavencentral/com.fasterxml.jackson.core/jackson-databind/2.15.2, Apache-2.0, approved, #7934 maven/mavencentral/com.fasterxml.jackson.dataformat/jackson-dataformat-xml/2.15.2, Apache-2.0, approved, #9237 -maven/mavencentral/com.fasterxml.jackson.dataformat/jackson-dataformat-yaml/2.15.1, Apache-2.0, approved, #8802 -maven/mavencentral/com.fasterxml.jackson.datatype/jackson-datatype-guava/2.13.2, Apache-2.0, approved, clearlydefined -maven/mavencentral/com.fasterxml.jackson.datatype/jackson-datatype-jdk8/2.13.5, Apache-2.0, approved, clearlydefined +maven/mavencentral/com.fasterxml.jackson.dataformat/jackson-dataformat-yaml/2.15.2, Apache-2.0, approved, #8802 +maven/mavencentral/com.fasterxml.jackson.datatype/jackson-datatype-guava/2.15.2, Apache-2.0, approved, #11060 +maven/mavencentral/com.fasterxml.jackson.datatype/jackson-datatype-jdk8/2.15.2, Apache-2.0, approved, #8808 maven/mavencentral/com.fasterxml.jackson.datatype/jackson-datatype-joda/2.15.2, Apache-2.0, approved, #11369 -maven/mavencentral/com.fasterxml.jackson.datatype/jackson-datatype-jsr310/2.13.5, Apache-2.0, approved, clearlydefined -maven/mavencentral/com.fasterxml.jackson.datatype/jackson-datatype-jsr310/2.15.1, Apache-2.0, approved, #7930 +maven/mavencentral/com.fasterxml.jackson.datatype/jackson-datatype-jsr310/2.15.2, Apache-2.0, approved, #7930 maven/mavencentral/com.fasterxml.jackson.jaxrs/jackson-jaxrs-base/2.15.2, Apache-2.0, approved, #11061 maven/mavencentral/com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider/2.15.2, Apache-2.0, approved, #9101 -maven/mavencentral/com.fasterxml.jackson.module/jackson-module-jakarta-xmlbind-annotations/2.14.1, Apache-2.0, approved, #5308 +maven/mavencentral/com.fasterxml.jackson.module/jackson-module-jakarta-xmlbind-annotations/2.15.2, Apache-2.0, approved, #9241 maven/mavencentral/com.fasterxml.jackson.module/jackson-module-jaxb-annotations/2.15.2, Apache-2.0, approved, #9100 -maven/mavencentral/com.fasterxml.jackson.module/jackson-module-parameter-names/2.13.5, Apache-2.0, approved, clearlydefined +maven/mavencentral/com.fasterxml.jackson.module/jackson-module-parameter-names/2.15.2, Apache-2.0, approved, #8803 maven/mavencentral/com.fasterxml.woodstox/woodstox-core/6.5.1, Apache-2.0, approved, #7950 maven/mavencentral/com.github.andrewoma.dexx/collection/0.7, MIT, approved, CQ22160 maven/mavencentral/com.github.jsonld-java/jsonld-java/0.13.4, BSD-3-Clause, approved, CQ22136 maven/mavencentral/com.github.jsqlparser/jsqlparser/4.4, LGPL-2.1 OR Apache-2.0, approved, clearlydefined maven/mavencentral/com.github.stephenc.jcip/jcip-annotations/1.0-1, Apache-2.0, approved, CQ21949 maven/mavencentral/com.google.code.findbugs/jsr305/3.0.2, Apache-2.0, approved, #20 -maven/mavencentral/com.google.code.gson/gson/2.8.8, Apache-2.0, approved, CQ23496 +maven/mavencentral/com.google.code.gson/gson/2.10.1, Apache-2.0, approved, #6159 maven/mavencentral/com.google.errorprone/error_prone_annotations/2.18.0, Apache-2.0, approved, clearlydefined maven/mavencentral/com.google.guava/failureaccess/1.0.1, Apache-2.0, approved, CQ22654 maven/mavencentral/com.google.guava/guava/32.1.2-jre, Apache-2.0 AND CC0-1.0 AND LicenseRef-Public-Domain, approved, #9229 @@ -188,9 +179,9 @@ maven/mavencentral/org.eclipse.jetty/jetty-http/11.0.15, EPL-2.0 OR Apache-2.0, maven/mavencentral/org.eclipse.jetty/jetty-http/9.4.53.v20231009, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty/jetty-io/11.0.15, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty/jetty-io/9.4.53.v20231009, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty/jetty-security/11.0.20, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-security/11.0.15, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty/jetty-server/11.0.15, EPL-2.0 OR Apache-2.0, approved, rt.jetty -maven/mavencentral/org.eclipse.jetty/jetty-servlet/11.0.20, EPL-2.0 OR Apache-2.0, approved, rt.jetty +maven/mavencentral/org.eclipse.jetty/jetty-servlet/11.0.15, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty/jetty-servlets/10.0.14, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty/jetty-util/11.0.15, EPL-2.0 OR Apache-2.0, approved, rt.jetty maven/mavencentral/org.eclipse.jetty/jetty-util/9.4.53.v20231009, EPL-2.0 OR Apache-2.0, approved, rt.jetty @@ -312,7 +303,7 @@ maven/mavencentral/org.jetbrains.kotlin/kotlin-stdlib-common/1.8.0, Apache-2.0, maven/mavencentral/org.jetbrains.kotlin/kotlin-stdlib-jdk7/1.8.0, Apache-2.0, approved, #8807 maven/mavencentral/org.jetbrains.kotlin/kotlin-stdlib-jdk8/1.8.0, Apache-2.0, approved, #8919 maven/mavencentral/org.jetbrains.kotlin/kotlin-stdlib/1.4.10, Apache-2.0, approved, clearlydefined -maven/mavencentral/org.jetbrains/annotations/24.1.0, Apache-2.0, approved, clearlydefined +maven/mavencentral/org.jetbrains/annotations/13.0, Apache-2.0, approved, clearlydefined maven/mavencentral/org.junit.jupiter/junit-jupiter-api/5.9.2, EPL-2.0, approved, #3133 maven/mavencentral/org.junit.jupiter/junit-jupiter-engine/5.9.2, EPL-2.0, approved, #3125 maven/mavencentral/org.junit.jupiter/junit-jupiter-params/5.9.2, EPL-2.0, approved, #3134 @@ -340,9 +331,7 @@ maven/mavencentral/org.skyscreamer/jsonassert/1.5.1, Apache-2.0, approved, clear maven/mavencentral/org.slf4j/jcl-over-slf4j/1.7.32, Apache-2.0, approved, CQ12843 maven/mavencentral/org.slf4j/jcl-over-slf4j/1.7.36, Apache-2.0, approved, CQ12843 maven/mavencentral/org.slf4j/jul-to-slf4j/1.7.36, MIT, approved, CQ12842 -maven/mavencentral/org.slf4j/slf4j-api/1.7.36, MIT, approved, CQ13368 maven/mavencentral/org.slf4j/slf4j-api/2.0.7, MIT, approved, #5915 -maven/mavencentral/org.slf4j/slf4j-simple/2.0.7, MIT, approved, #10372 maven/mavencentral/org.springframework.boot/spring-boot-actuator-autoconfigure/2.7.18, Apache-2.0, approved, #3273 maven/mavencentral/org.springframework.boot/spring-boot-actuator/2.7.18, Apache-2.0, approved, #4316 maven/mavencentral/org.springframework.boot/spring-boot-autoconfigure/2.7.18, Apache-2.0, approved, #4314 diff --git a/conforming/pom.xml b/conforming/pom.xml index c69ec2a6..2864f9df 100644 --- a/conforming/pom.xml +++ b/conforming/pom.xml @@ -108,6 +108,11 @@ jackson-datatype-joda ${jackson.version} + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson.version} + com.fasterxml.jackson.dataformat jackson-dataformat-xml @@ -123,6 +128,16 @@ jackson-annotations ${jackson.version} + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + ${jackson.version} + javax.xml.bind jaxb-api diff --git a/matchmaking/pom.xml b/matchmaking/pom.xml index 2d061ea4..7f30c382 100644 --- a/matchmaking/pom.xml +++ b/matchmaking/pom.xml @@ -142,11 +142,31 @@ jackson-jaxrs-json-provider ${jackson.version} + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + ${jackson.version} + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson.version} + com.fasterxml.jackson.core jackson-annotations ${jackson.version} + + com.fasterxml.jackson.module + jackson-module-jakarta-xmlbind-annotations + ${jackson.version} + javax.xml.bind jaxb-api diff --git a/pom.xml b/pom.xml index a04ab1ef..498da771 100644 --- a/pom.xml +++ b/pom.xml @@ -45,8 +45,6 @@ 4.5.14 1.2 2.15.2 - 2.15.2 - 2.13.5 3.1.0 9.31 5.0.2 diff --git a/provisioning/pom.xml b/provisioning/pom.xml index b3f17c58..8cae1c2e 100644 --- a/provisioning/pom.xml +++ b/provisioning/pom.xml @@ -153,19 +153,43 @@ com.fasterxml.jackson.core jackson-annotations - ${jackson.annotation.version} + ${jackson.version} test com.fasterxml.jackson.core jackson-core - ${jackson.annotation.version} + ${jackson.version} test com.fasterxml.jackson.core jackson-databind - ${jackson.annotation.version} + ${jackson.version} + test + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + ${jackson.version} + test + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson.version} + test + + + com.fasterxml.jackson.datatype + jackson-datatype-guava + ${jackson.version} + test + + + com.fasterxml.jackson.module + jackson-module-parameter-names + ${jackson.version} test diff --git a/remoting/pom.xml b/remoting/pom.xml index bd56fc68..2dc6f2eb 100644 --- a/remoting/pom.xml +++ b/remoting/pom.xml @@ -127,7 +127,34 @@ com.fasterxml.jackson.core jackson-databind - ${jackson.databind.version} + ${jackson.version} + + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + ${jackson.version} + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson.version} + + + com.fasterxml.jackson.datatype + jackson-datatype-guava + ${jackson.version} + + + com.fasterxml.jackson.module + jackson-module-parameter-names + ${jackson.version} From 3c0bf3f8689ac104844558d32732ca59a0c3bb44 Mon Sep 17 00:00:00 2001 From: "Dr. Christoph \"Schorsch\" Jung" Date: Tue, 2 Apr 2024 14:20:49 +0200 Subject: [PATCH 06/15] chore: adjust copyright of new chart --- charts/matchmaking-agent/.helmignore | 2 +- charts/matchmaking-agent/Chart.yaml | 2 +- charts/matchmaking-agent/README.md | 2 +- charts/matchmaking-agent/README.md.gotmpl | 2 +- charts/matchmaking-agent/templates/NOTES.txt | 2 +- charts/matchmaking-agent/templates/_helpers.tpl | 2 +- charts/matchmaking-agent/templates/configmap-env.yaml | 2 +- charts/matchmaking-agent/templates/configmap.yaml | 2 +- charts/matchmaking-agent/templates/deployment.yaml | 2 +- charts/matchmaking-agent/templates/hpa.yaml | 2 +- charts/matchmaking-agent/templates/ingress.yaml | 2 +- charts/matchmaking-agent/templates/service.yaml | 2 +- charts/matchmaking-agent/templates/serviceaccount.yaml | 2 +- charts/matchmaking-agent/values.yaml | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/charts/matchmaking-agent/.helmignore b/charts/matchmaking-agent/.helmignore index 9a12504f..49603135 100644 --- a/charts/matchmaking-agent/.helmignore +++ b/charts/matchmaking-agent/.helmignore @@ -1,4 +1,4 @@ -# Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +# Copyright (c) 2022,2024 Contributors to the Eclipse Foundation # # See the NOTICE file(s) distributed with this work for additional # information regarding copyright ownership. diff --git a/charts/matchmaking-agent/Chart.yaml b/charts/matchmaking-agent/Chart.yaml index 8ac74b1d..3364e84c 100644 --- a/charts/matchmaking-agent/Chart.yaml +++ b/charts/matchmaking-agent/Chart.yaml @@ -1,5 +1,5 @@ --- -# Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +# Copyright (c) 2022,2024 Contributors to the Eclipse Foundation # # See the NOTICE file(s) distributed with this work for additional # information regarding copyright ownership. diff --git a/charts/matchmaking-agent/README.md b/charts/matchmaking-agent/README.md index 3198024d..86d547e7 100644 --- a/charts/matchmaking-agent/README.md +++ b/charts/matchmaking-agent/README.md @@ -1,5 +1,5 @@