├── .ci ├── check-version.sh └── updatecli.d │ └── bump-version.yml ├── .dockerignore ├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ ├── create-tag.yml │ ├── release.yml │ ├── test-reporter.yml │ ├── test.yml │ └── updatecli.yml ├── .gitignore ├── .gitmodules ├── .version ├── CODE_OF_CONDUCT.md ├── Dockerfile ├── LICENSE ├── LICENSE.txt ├── Makefile ├── README.md ├── docker-compose-elastic-cloud.yml ├── docker-compose.yml ├── opbeans ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── co │ │ │ └── elastic │ │ │ └── apm │ │ │ └── opbeans │ │ │ ├── OpbeansApplication.java │ │ │ ├── controllers │ │ │ ├── APIRestController.java │ │ │ ├── DTInterceptor.java │ │ │ ├── IndexController.java │ │ │ └── WebMvcConfig.java │ │ │ ├── model │ │ │ ├── Customer.java │ │ │ ├── Order.java │ │ │ ├── OrderLine.java │ │ │ ├── OrderLineId.java │ │ │ ├── Product.java │ │ │ └── ProductType.java │ │ │ └── repositories │ │ │ ├── CustomerRepository.java │ │ │ ├── Numbers.java │ │ │ ├── OrderDetail.java │ │ │ ├── OrderList.java │ │ │ ├── OrderRepository.java │ │ │ ├── ProductDetail.java │ │ │ ├── ProductList.java │ │ │ ├── ProductRepository.java │ │ │ ├── Stats.java │ │ │ └── TopProduct.java │ └── resources │ │ ├── application-customdb.properties │ │ ├── application.properties │ │ ├── application_old.properties │ │ ├── logback.xml │ │ ├── public │ │ ├── apple-touch-icon-precomposed.png │ │ ├── apple-touch-icon.png │ │ ├── css │ │ │ └── opbeans.css │ │ ├── error │ │ │ ├── 404.html │ │ │ ├── 422.html │ │ │ └── 500.html │ │ ├── favicon.ico │ │ ├── images │ │ │ └── products │ │ │ │ ├── OP-DRC-C1.jpg │ │ │ │ ├── OP-DRC-C6.jpg │ │ │ │ ├── OP-DRC-C9.jpg │ │ │ │ ├── OP-LRC-C3.jpg │ │ │ │ ├── OP-LRC-C4.jpg │ │ │ │ ├── OP-LRC-C8.jpg │ │ │ │ ├── OP-MRC-C2.jpg │ │ │ │ ├── OP-MRC-C5.jpg │ │ │ │ └── OP-MRC-C7.jpg │ │ ├── index.html │ │ ├── js │ │ │ └── opbeans.js │ │ └── static │ │ │ └── media │ │ │ └── icons.97493d3f.woff2 │ │ └── schema-H2.sql │ └── test │ └── java │ └── co │ └── elastic │ └── apm │ └── opbeans │ └── OpbeansApplicationTests.java ├── start.sh └── tests ├── test_helpers.bash └── tests.bats /.ci/check-version.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | current_version=$(cat .version) 6 | test "$current_version" != "$1" 7 | -------------------------------------------------------------------------------- /.ci/updatecli.d/bump-version.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://www.updatecli.io/schema/latest/config.json 3 | ## Workflow to periodically check if there is an available newer APM agent version, e.g. 4 | ## "1.2.3". If so, then update to it. 5 | name: Bump apm-agent-java to latest version 6 | 7 | scms: 8 | githubConfig: 9 | kind: github 10 | spec: 11 | user: '{{ requiredEnv "GITHUB_ACTOR" }}' 12 | owner: elastic 13 | repository: opbeans-java 14 | token: '{{ requiredEnv "GITHUB_TOKEN" }}' 15 | username: '{{ requiredEnv "GITHUB_ACTOR" }}' 16 | branch: main 17 | commitusingapi: true 18 | 19 | actions: 20 | opbeans-java: 21 | kind: github/pullrequest 22 | scmid: githubConfig 23 | title: 'deps(apm-agent-java): Update APM Agent Java to {{ source "elastic-apm-agent-java" }}' 24 | spec: 25 | automerge: false 26 | labels: 27 | - dependencies 28 | description: | 29 | @elastic/apm-agent-java, can you please approve and merge this PR? 30 | 31 | sources: 32 | elastic-apm-agent-java: 33 | kind: githubrelease 34 | spec: 35 | owner: elastic 36 | repository: apm-agent-java 37 | token: '{{ requiredEnv "GITHUB_TOKEN" }}' 38 | username: '{{ requiredEnv "GITHUB_ACTOR" }}' 39 | versionfilter: 40 | kind: semver 41 | transformers: 42 | - trimprefix: "v" 43 | 44 | conditions: 45 | check-version: 46 | sourceid: elastic-apm-agent-java 47 | kind: shell 48 | spec: 49 | command: .ci/check-version.sh 50 | 51 | targets: 52 | version: 53 | name: Update .version file 54 | sourceid: elastic-apm-agent-java 55 | scmid: githubConfig 56 | kind: file 57 | spec: 58 | file: .version 59 | forcecreate: true 60 | pom_xml: 61 | name: Update maven package version 62 | sourceid: elastic-apm-agent-java 63 | scmid: githubConfig 64 | kind: xml 65 | spec: 66 | file: opbeans/pom.xml 67 | path: "/project/properties/version.apm-agent-java" 68 | value: '{{ source "elastic-apm-agent-java" }}' 69 | dockerfile_schema_version: 70 | name: Set org.label-schema.version in Dockerfile 71 | sourceid: elastic-apm-agent-java 72 | scmid: githubConfig 73 | kind: file 74 | spec: 75 | file: Dockerfile 76 | matchpattern: 'org\.label-schema\.version="(\d+.\d+.\d+)"' 77 | replacepattern: org.label-schema.version="{{ source `elastic-apm-agent-java` }}" 78 | dockerfile_agent_version: 79 | name: Set apm-agent version in Dockerfile 80 | sourceid: elastic-apm-agent-java 81 | scmid: githubConfig 82 | kind: file 83 | dependson: 84 | - pom_xml 85 | spec: 86 | file: Dockerfile 87 | matchpattern: docker\.elastic\.co\/observability\/apm-agent-java\:(\d+\.\d+\.\d+) 88 | replacepattern: docker.elastic.co/observability/apm-agent-java:{{ source `elastic-apm-agent-java` }} 89 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .ci 2 | .dockerignore 3 | .git 4 | .gitignore 5 | .gitmodules 6 | docker-compose*.yml 7 | Dockerfile 8 | Makefile 9 | README.md 10 | tests 11 | bats 12 | target 13 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @elastic/apm-agent-java -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | # Enable version updates for maven 5 | - package-ecosystem: "maven" 6 | # Look for `pom.xml` file in the `opbeans` directory 7 | directory: "/opbeans/" 8 | # Check for updates once a week 9 | schedule: 10 | interval: "weekly" 11 | day: "sunday" 12 | time: "22:00" 13 | reviewers: 14 | - "elastic/apm-agent-java" 15 | 16 | # Enable version updates for Docker 17 | - package-ecosystem: "docker" 18 | directory: "/" 19 | # Check for updates once a week 20 | schedule: 21 | interval: "weekly" 22 | day: "sunday" 23 | time: "22:00" 24 | reviewers: 25 | - "elastic/apm-agent-java" 26 | 27 | # GitHub actions 28 | - package-ecosystem: "github-actions" 29 | directory: "/" 30 | reviewers: 31 | - "elastic/observablt-ci" 32 | schedule: 33 | interval: "weekly" 34 | day: "sunday" 35 | time: "22:00" 36 | groups: 37 | github-actions: 38 | patterns: 39 | - "*" -------------------------------------------------------------------------------- /.github/workflows/create-tag.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Creates a new GitHub release if the version in .version changed in the main branch. 3 | name: create-tag 4 | 5 | on: 6 | push: 7 | branches: 8 | - main 9 | paths: 10 | - .version 11 | 12 | permissions: 13 | contents: read 14 | 15 | jobs: 16 | tag: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | with: 21 | fetch-depth: 0 # also fetch tags 22 | 23 | - name: Get token 24 | id: get_token 25 | uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2.1.0 26 | with: 27 | app_id: ${{ secrets.OBS_AUTOMATION_APP_ID }} 28 | private_key: ${{ secrets.OBS_AUTOMATION_APP_PEM }} 29 | permissions: >- 30 | { 31 | "contents": "write" 32 | } 33 | 34 | - run: make create-release 35 | env: 36 | GH_TOKEN: ${{ steps.get_token.outputs.token }} 37 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | tags: [ "v*" ] 7 | 8 | permissions: 9 | contents: read 10 | 11 | env: 12 | DOCKER_IMAGE_NAME: opbeans/opbeans-java 13 | 14 | jobs: 15 | 16 | release: 17 | runs-on: ubuntu-latest 18 | permissions: 19 | attestations: write 20 | contents: read 21 | id-token: write 22 | steps: 23 | - uses: actions/checkout@v4 24 | 25 | - name: Set up Docker Buildx 26 | uses: docker/setup-buildx-action@v3 27 | 28 | - name: Log in to the Container registry 29 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 30 | with: 31 | registry: ${{ secrets.DOCKERHUB_REGISTRY }} 32 | username: ${{ secrets.DOCKERHUB_USERNAME }} 33 | password: ${{ secrets.DOCKERHUB_PASSWORD }} 34 | 35 | - name: Extract metadata (tags, labels) 36 | id: docker-meta 37 | uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 38 | with: 39 | images: ${{ env.DOCKER_IMAGE_NAME }} 40 | tags: | 41 | type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }} 42 | # tag event 43 | type=ref,enable=true,prefix=,suffix=,event=tag 44 | 45 | - name: Build and push image 46 | id: docker-push 47 | uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 48 | with: 49 | context: . 50 | provenance: mode=max 51 | push: true 52 | sbom: true 53 | tags: ${{ steps.docker-meta.outputs.tags }} 54 | labels: ${{ steps.docker-meta.outputs.labels }} 55 | 56 | - name: Attest image 57 | uses: actions/attest-build-provenance@db473fddc028af60658334401dc6fa3ffd8669fd # v2.3.0 58 | with: 59 | subject-name: index.docker.io/${{ env.DOCKER_IMAGE_NAME }} 60 | subject-digest: ${{ steps.docker-push.outputs.digest }} 61 | push-to-registry: true 62 | -------------------------------------------------------------------------------- /.github/workflows/test-reporter.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ## Workflow to process the JUnit test results and add a report to the checks. 3 | name: test-reporter 4 | on: 5 | workflow_run: 6 | workflows: 7 | - test 8 | types: 9 | - completed 10 | 11 | permissions: 12 | contents: read 13 | actions: read 14 | checks: write 15 | 16 | jobs: 17 | report: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: elastic/oblt-actions/test-report@v1 21 | with: 22 | artifact: /test-results(.*)/ # artifact name pattern 23 | name: 'Test Report $1' # Name of the check run which will be created 24 | path: "**/*.xml" # Path to test results (inside artifact .zip) 25 | reporter: java-junit # Format of test results 26 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | test: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | - name: Run build 21 | run: make build 22 | 23 | - name: Run test 24 | run: make test 25 | 26 | - name: Store test results 27 | if: success() || failure() 28 | uses: actions/upload-artifact@v4 29 | with: 30 | name: test-results 31 | path: target/*.xml 32 | -------------------------------------------------------------------------------- /.github/workflows/updatecli.yml: -------------------------------------------------------------------------------- 1 | name: updatecli 2 | 3 | on: 4 | workflow_dispatch: ~ 5 | schedule: 6 | - cron: '0 6 * * *' 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | bump: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: actions/setup-java@v4 17 | with: 18 | java-version: 11 19 | distribution: temurin 20 | 21 | - name: Get token 22 | id: get_token 23 | uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2.1.0 24 | with: 25 | app_id: ${{ secrets.OBS_AUTOMATION_APP_ID }} 26 | private_key: ${{ secrets.OBS_AUTOMATION_APP_PEM }} 27 | permissions: >- 28 | { 29 | "contents": "write", 30 | "pull_requests": "write" 31 | } 32 | 33 | - uses: elastic/oblt-actions/updatecli/run@v1 34 | with: 35 | command: "--experimental apply --config .ci/updatecli.d" 36 | env: 37 | GITHUB_TOKEN: ${{ steps.get_token.outputs.token }} 38 | 39 | - if: failure() 40 | uses: elastic/oblt-actions/slack/send@v1 41 | with: 42 | bot-token: ${{ secrets.SLACK_BOT_TOKEN }} 43 | channel-id: "#apm-agent-java" 44 | message: ":traffic_cone: updatecli failed for `${{ github.repository }}@${{ github.ref_name }}`, @robots-ci please look what's going on " 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Build products 5 | target 6 | 7 | # Log file 8 | *.log 9 | 10 | # BlueJ files 11 | *.ctxt 12 | 13 | # Mobile Tools for Java (J2ME) 14 | .mtj.tmp/ 15 | 16 | # Package Files # 17 | *.jar 18 | *.war 19 | *.nar 20 | *.ear 21 | *.zip 22 | *.tar.gz 23 | *.rar 24 | 25 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 26 | hs_err_pid* 27 | 28 | # IntelliJ IDEA stuff 29 | .idea/ 30 | *.iml 31 | 32 | # Mac 33 | .DS_Store 34 | 35 | # For the BATS testing 36 | bats/ 37 | target/ 38 | pom.xml.versionsBackup 39 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tests/test_helper/bats-assert"] 2 | path = tests/test_helper/bats-assert 3 | url = https://github.com/ztombol/bats-assert 4 | [submodule "tests/test_helper/bats-support"] 5 | path = tests/test_helper/bats-support 6 | url = https://github.com/ztombol/bats-support 7 | -------------------------------------------------------------------------------- /.version: -------------------------------------------------------------------------------- 1 | 1.54.0 -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 303 See Other 2 | 3 | Location: https://www.elastic.co/community/codeofconduct 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | #Multi-Stage build 2 | 3 | #Build application stage 4 | #We need maven. 5 | FROM maven:3.9.8-eclipse-temurin-22 6 | WORKDIR /usr/src/java-app 7 | 8 | #build the application 9 | ADD . /usr/src/java-code 10 | WORKDIR /usr/src/java-code/opbeans 11 | 12 | #Bring the latest frontend code 13 | COPY --from=opbeans/opbeans-frontend:latest /app src/main/resources/public 14 | 15 | RUN mvn -q --batch-mode package \ 16 | -DskipTests \ 17 | -Dmaven.repo.local=.m2 \ 18 | --no-transfer-progress \ 19 | -Dmaven.wagon.http.retryHandler.count=3 \ 20 | -Dhttps.protocols=TLSv1.2 \ 21 | -Dhttp.keepAlive=false \ 22 | -Dmaven.javadoc.skip=true \ 23 | -Dmaven.gitcommitid.skip=true 24 | RUN cp -v /usr/src/java-code/opbeans/target/*.jar /usr/src/java-app/app.jar 25 | 26 | #Run application Stage 27 | #We only need java 28 | FROM eclipse-temurin:17 AS base 29 | 30 | RUN export 31 | RUN apt-get -qq update \ 32 | && apt-get install --no-install-recommends -y -qq curl \ 33 | && rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true 34 | 35 | WORKDIR /app 36 | COPY --from=0 /usr/src/java-app/*.jar ./ 37 | 38 | # Copy Elastic agent from docker image 39 | # updated by .ci/bump-version.sh 40 | COPY --from=docker.elastic.co/observability/apm-agent-java:1.52.1 /usr/agent/elastic-apm-agent.jar /app/elastic-apm-agent.jar 41 | 42 | #Download the opentelemetry agent 43 | RUN curl -L https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v1.10.1/opentelemetry-javaagent.jar --output /app/opentelemetry-javaagent.jar 44 | 45 | # updated by .ci/bump-version.sh 46 | LABEL \ 47 | org.label-schema.schema-version="1.0" \ 48 | org.label-schema.vendor="Elastic" \ 49 | org.label-schema.name="opbeans-java" \ 50 | org.label-schema.version="1.53.0" \ 51 | org.label-schema.url="https://hub.docker.com/r/opbeans/opbeans-java" \ 52 | org.label-schema.vcs-url="https://github.com/elastic/opbeans-java" \ 53 | org.label-schema.license="MIT" 54 | 55 | COPY ./start.sh . 56 | RUN chmod +x ./start.sh 57 | CMD ["./start.sh"] 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 elastic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2018 Elastic Inc. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PORT ?= 8000 2 | IMAGE ?= opbeans/opbeans-java 3 | VERSION ?= latest 4 | LTS_ALPINE ?= 12-alpine 5 | AGENT_VERSION=$(shell cat .version) 6 | 7 | .PHONY: help 8 | .DEFAULT_GOAL := help 9 | 10 | help: ## Display this help text 11 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' 12 | 13 | all: build test 14 | 15 | build: ## Build docker image 16 | @docker build --file Dockerfile --tag=${IMAGE}:${VERSION} . 17 | 18 | bats: ## Install bats in the project itself 19 | @git clone https://github.com/sstephenson/bats.git 20 | 21 | prepare-test: bats ## Prepare the bats dependencies 22 | @docker pull node:${LTS_ALPINE} 23 | @mkdir -p target 24 | @git submodule sync 25 | @git submodule update --init --recursive 26 | 27 | test: prepare-test ## Run the tests 28 | @echo "Tests are in progress, please be patient" 29 | @PORT=${PORT} bats/bin/bats --tap tests | tee target/results.tap 30 | @docker run --rm -v "${PWD}":/usr/src/app -w /usr/src/app node:${LTS_ALPINE} \ 31 | sh -c "npm install tap-xunit -g && cat target/results.tap | tap-xunit --package='co.elastic.opbeans' > target/junit-results.xml" 32 | 33 | publish: build ## Publish docker image 34 | @docker push "${IMAGE}:${VERSION}" 35 | 36 | clean: ## Clean autogenerated files/folders 37 | @rm -rf bats 38 | @rm -rf target 39 | 40 | create-release: ## Create git tag given the APM Agent version 41 | @if [ -z "$(shell git tag -l v$(AGENT_VERSION))" ]; then \ 42 | echo "creating tag v$(AGENT_VERSION)"; \ 43 | gh release create "v$(AGENT_VERSION)" --title="$(AGENT_VERSION)" --generate-notes; \ 44 | else \ 45 | echo "git tag v$(AGENT_VERSION) already exists"; \ 46 | fi 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://github.com/elastic/opbeans-java/actions/workflows/test.yml/badge.svg)](https://github.com/elastic/opbeans-java/actions/workflows/test.yml) 2 | 3 | # opbeans-java 4 | This is an implementation of the [Opbeans Demo app](http://opbeans.com) in Java as an [Spring Boot](https://projects.spring.io/spring-boot/) application . It uses the same 5 | database schema as the [Node](https://github.com/opbeat/opbeans) version. 6 | 7 | By default it will use a pre-populated in memory H2 database. 8 | 9 | To run the application run the following command from the `opbeans` folder: 10 | 11 | ./mvnw spring-boot:run 12 | 13 | ## Run locally 14 | To run locally, including Server, Kibana and Elasticsearch, use the provided docker compose file by running the command 15 | ```bash 16 | docker compose up 17 | ``` 18 | 19 | ## Run with Elastic Cloud 20 | 21 | 0. Start Elastic Cloud [trial](https://www.elastic.co/cloud/elasticsearch-service/signup) (if you don't have it yet) 22 | 1. Add environmental variables `ELASTIC_CLOUD_ID` and `ELASTIC_CLOUD_CREDENTIALS` (in format `login:password`) 23 | 2. Add environmental variable `STACK_VERSION` to match your deployed Elasticsearch version. 24 | 3. Run 25 | ```bash 26 | docker compose -f docker-compose-elastic-cloud.yml up 27 | ``` 28 | 29 | ## Testing locally 30 | 31 | The simplest way to test this demo is by running: 32 | 33 | ```bash 34 | make test 35 | ``` 36 | 37 | Tests are written using [bats](https://github.com/sstephenson/bats) under the tests dir 38 | 39 | ## Publishing to dockerhub locally 40 | 41 | Publish the docker image with 42 | 43 | ```bash 44 | VERSION=1.2.3 make publish 45 | ``` 46 | 47 | NOTE: VERSION refers to the tag for the docker image which will be published in the registry 48 | 49 | ## Customize Database 50 | 51 | Database can be overridden by using system properties and overriding values from the application property files: 52 | 53 | ./mvnw spring-boot:run -Dspring.jpa.database=POSTGRESQL -Dspring.datasource.driverClassName=org.postgresql.Driver -Dspring.datasource.url=jdbc:postgresql://localhost/opbeans?user=postgres&password=verysecure 54 | 55 | Another possible way is to create a different property file like application-customdb.properties and enabling it with a profile: 56 | 57 | ./mvnw spring-boot:run -Dspring.profiles.active=customdb 58 | 59 | ## Demo notes 60 | 61 | The application has a built-in bug that you can trigger by 62 | navigating to the path `/is-it-coffee-time`. 63 | 64 | ## Agent mode (elasticapm/opentelemetry) 65 | 66 | The Opbeans Java can use the APM Agent Java or the OpenTelemetry java implementation 67 | in order to choose one of other you have to set the environment variable APM_AGENT_TYPE 68 | to `elasticapm` when you use the APM Agent Java and `opentelemetry` to use OpenTelemetry java implementation. 69 | Finally, there is also the `none` value that will make Opbeans run without any instrumentation agent. 70 | 71 | When OpenTelemetry agent is enabled, the OpenTelemetry environment variables should be properly set to allow the application to send spans created through manual instrumentation. 72 | see the [docker-compose](./docker-compose.yml) file for more details about the environment variables, and [OpenTelemetry SDK Autoconfigure](https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md) for more details. 73 | 74 | -------------------------------------------------------------------------------- /docker-compose-elastic-cloud.yml: -------------------------------------------------------------------------------- 1 | version: "2.1" 2 | services: 3 | opbeans-java: 4 | build: . 5 | image: opbeans/opbeans-java:latest 6 | container_name: opbeans-java 7 | ports: 8 | - "127.0.0.1:${OPBEANS_SERVER_PORT:-8000}:8000" 9 | logging: 10 | driver: 'json-file' 11 | options: 12 | max-size: '2m' 13 | max-file: '5' 14 | environment: 15 | - ELASTIC_APM_SERVICE_NAME=${ELASTIC_APM_SERVICE_NAME:-opbeans-java} 16 | - ELASTIC_APM_SERVER_URL=${ELASTIC_APM_SERVER_URL:-http://apm-server:8200} 17 | - ELASTIC_APM_APPLICATION_PACKAGES=co.elastic.apm.opbeans 18 | - ELASTIC_APM_JS_SERVER_URL=${ELASTIC_APM_JS_SERVER_URL:-http://localhost:8200} 19 | - OPBEANS_SERVER_PORT=${OPBEANS_SERVER_PORT:-8000} 20 | - ELASTIC_APM_ENABLE_LOG_CORRELATION=true 21 | - ELASTIC_APM_ENVIRONMENT=production 22 | - OTEL_RESOURCE_ATTRIBUTES=service.name=${ELASTIC_APM_SERVICE_NAME:-opbeans-java},deployment.environment=production 23 | - OTEL_TRACES_EXPORTER=otlp 24 | - OTEL_METRICS_EXPORTER=otlp 25 | - OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-http://apm-server:8200} 26 | - OTEL_EXPORTER_OTLP_PROTOCOL=grpc 27 | - APM_AGENT_TYPE=${APM_AGENT_TYPE:-elasticapm} 28 | depends_on: 29 | apm-server: 30 | condition: service_healthy 31 | healthcheck: 32 | test: ["CMD", "curl", "--write-out", "'HTTP %{http_code}'", "--silent", "--output", "/dev/null", "http://opbeans-java:8000/"] 33 | interval: 10s 34 | retries: 10 35 | 36 | apm-server: 37 | image: docker.elastic.co/apm/apm-server:${STACK_VERSION:-7.3.0} 38 | ports: 39 | - "127.0.0.1:${APM_SERVER_PORT:-8200}:8200" 40 | - "127.0.0.1:${APM_SERVER_MONITOR_PORT:-6060}:6060" 41 | command: > 42 | apm-server -e 43 | -E apm-server.frontend.enabled=true 44 | -E apm-server.frontend.rate_limit=100000 45 | -E apm-server.host=0.0.0.0:8200 46 | -E apm-server.read_timeout=1m 47 | -E apm-server.shutdown_timeout=2m 48 | -E apm-server.write_timeout=1m 49 | -E apm-server.rum.enabled=true 50 | -E setup.kibana.host=kibana:5601 51 | -E setup.template.settings.index.number_of_replicas=0 52 | -E xpack.monitoring.elasticsearch=true 53 | -E cloud.id=${ELASTIC_CLOUD_ID} 54 | -E cloud.auth=${ELASTIC_CLOUD_CREDENTIALS} 55 | -E output.elasticsearch.enabled=${APM_SERVER_ELASTICSEARCH_OUTPUT_ENABLED:-true} 56 | cap_drop: 57 | - ALL 58 | cap_add: 59 | - CHOWN 60 | - DAC_OVERRIDE 61 | - SETGID 62 | - SETUID 63 | logging: 64 | driver: 'json-file' 65 | options: 66 | max-size: '2m' 67 | max-file: '5' 68 | healthcheck: 69 | test: ["CMD", "curl", "--write-out", "'HTTP %{http_code}'", "--silent", "--output", "/dev/null", "http://apm-server:8200/"] 70 | retries: 10 71 | interval: 10s 72 | 73 | wait: 74 | image: busybox 75 | depends_on: 76 | opbeans-java: 77 | condition: service_healthy 78 | 79 | volumes: 80 | esdata: 81 | driver: local 82 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2.1" 2 | services: 3 | opbeans-java: 4 | build: . 5 | image: opbeans/opbeans-java:latest 6 | container_name: opbeans-java 7 | ports: 8 | - "127.0.0.1:${OPBEANS_SERVER_PORT:-8000}:8000" 9 | logging: 10 | driver: 'json-file' 11 | options: 12 | max-size: '2m' 13 | max-file: '5' 14 | environment: 15 | - ELASTIC_APM_SERVICE_NAME=${ELASTIC_APM_SERVICE_NAME:-opbeans-java} 16 | - ELASTIC_APM_SERVER_URL=${ELASTIC_APM_SERVER_URL:-http://apm-server:8200} 17 | - ELASTIC_APM_APPLICATION_PACKAGES=co.elastic.apm.opbeans 18 | - ELASTIC_APM_JS_SERVER_URL=${ELASTIC_APM_JS_SERVER_URL:-http://localhost:8200} 19 | - OPBEANS_SERVER_PORT=${OPBEANS_SERVER_PORT:-8000} 20 | - ELASTIC_APM_ENABLE_LOG_CORRELATION=true 21 | - ELASTIC_APM_ENVIRONMENT=production 22 | - OTEL_RESOURCE_ATTRIBUTES=service.name=${ELASTIC_APM_SERVICE_NAME:-opbeans-java},deployment.environment=production 23 | - OTEL_TRACES_EXPORTER=otlp 24 | - OTEL_METRICS_EXPORTER=otlp 25 | - OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-http://apm-server:8200} 26 | - OTEL_EXPORTER_OTLP_PROTOCOL=grpc 27 | - APM_AGENT_TYPE=${APM_AGENT_TYPE:-elasticapm} 28 | depends_on: 29 | apm-server: 30 | condition: service_healthy 31 | healthcheck: 32 | test: ["CMD", "curl", "--write-out", "'HTTP %{http_code}'", "--silent", "--output", "/dev/null", "http://opbeans-java:8000/"] 33 | interval: 10s 34 | retries: 10 35 | 36 | apm-server: 37 | image: docker.elastic.co/apm/apm-server:${STACK_VERSION:-7.3.0} 38 | ports: 39 | - "127.0.0.1:${APM_SERVER_PORT:-8200}:8200" 40 | - "127.0.0.1:${APM_SERVER_MONITOR_PORT:-6060}:6060" 41 | command: > 42 | apm-server -e 43 | -E apm-server.frontend.enabled=true 44 | -E apm-server.frontend.rate_limit=100000 45 | -E apm-server.host=0.0.0.0:8200 46 | -E apm-server.read_timeout=1m 47 | -E apm-server.shutdown_timeout=2m 48 | -E apm-server.write_timeout=1m 49 | -E apm-server.rum.enabled=true 50 | -E setup.kibana.host=kibana:5601 51 | -E setup.template.settings.index.number_of_replicas=0 52 | -E xpack.monitoring.elasticsearch=true 53 | -E output.elasticsearch.enabled=${APM_SERVER_ELASTICSEARCH_OUTPUT_ENABLED:-true} 54 | cap_drop: 55 | - ALL 56 | cap_add: 57 | - CHOWN 58 | - DAC_OVERRIDE 59 | - SETGID 60 | - SETUID 61 | logging: 62 | driver: 'json-file' 63 | options: 64 | max-size: '2m' 65 | max-file: '5' 66 | depends_on: 67 | elasticsearch: 68 | condition: service_healthy 69 | healthcheck: 70 | test: ["CMD", "curl", "--write-out", "'HTTP %{http_code}'", "--silent", "--output", "/dev/null", "http://apm-server:8200/"] 71 | retries: 10 72 | interval: 10s 73 | 74 | elasticsearch: 75 | image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION:-7.3.0} 76 | environment: 77 | - cluster.name=docker-cluster 78 | - xpack.security.enabled=false 79 | - bootstrap.memory_lock=true 80 | - network.host=0.0.0.0 81 | - discovery.type=single-node 82 | - "ES_JAVA_OPTS=-Xms1g -Xmx1g" 83 | - "path.data=/usr/share/elasticsearch/data/${STACK_VERSION:-7.3.0}" 84 | ulimits: 85 | memlock: 86 | soft: -1 87 | hard: -1 88 | mem_limit: 2g 89 | logging: 90 | driver: 'json-file' 91 | options: 92 | max-size: '2m' 93 | max-file: '5' 94 | ports: 95 | - "127.0.0.1:${ELASTICSEARCH_PORT:-9200}:9200" 96 | healthcheck: 97 | test: ["CMD-SHELL", "curl -s http://localhost:9200/_cluster/health | grep -vq '\"status\":\"red\"'"] 98 | retries: 10 99 | interval: 20s 100 | volumes: 101 | - esdata:/usr/share/elasticsearch/data 102 | 103 | kibana: 104 | image: docker.elastic.co/kibana/kibana:${STACK_VERSION:-7.3.0} 105 | environment: 106 | SERVER_NAME: kibana.example.org 107 | ELASTICSEARCH_URL: http://elasticsearch:9200 108 | ports: 109 | - "127.0.0.1:${KIBANA_PORT:-5601}:5601" 110 | logging: 111 | driver: 'json-file' 112 | options: 113 | max-size: '2m' 114 | max-file: '5' 115 | healthcheck: 116 | test: ["CMD", "curl", "--write-out", "'HTTP %{http_code}'", "--silent", "--output", "/dev/null", "http://kibana:5601/"] 117 | retries: 10 118 | interval: 10s 119 | depends_on: 120 | elasticsearch: 121 | condition: service_healthy 122 | 123 | wait: 124 | image: busybox 125 | depends_on: 126 | opbeans-java: 127 | condition: service_healthy 128 | 129 | volumes: 130 | esdata: 131 | driver: local 132 | -------------------------------------------------------------------------------- /opbeans/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/opbeans-java/52370623e61d38c8c5273afccbe1f8272cfd3dea/opbeans/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /opbeans/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip 2 | -------------------------------------------------------------------------------- /opbeans/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Migwn, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 204 | echo $MAVEN_PROJECTBASEDIR 205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 206 | 207 | # For Cygwin, switch paths to Windows format before running java 208 | if $cygwin; then 209 | [ -n "$M2_HOME" ] && 210 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 211 | [ -n "$JAVA_HOME" ] && 212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 213 | [ -n "$CLASSPATH" ] && 214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 215 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 217 | fi 218 | 219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 220 | 221 | exec "$JAVACMD" \ 222 | $MAVEN_OPTS \ 223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 226 | -------------------------------------------------------------------------------- /opbeans/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /opbeans/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | co.elastic.apm 6 | opbeans 7 | 0.0.1-SNAPSHOT 8 | 9 | opbeans 10 | This is an implementation of the Opbeans Demo app in Java 11 | 12 | 13 | 14 | The Apache Software License, Version 2.0 15 | http://www.apache.org/licenses/LICENSE-2.0.txt 16 | 17 | 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-parent 22 | 3.5.0 23 | 24 | 25 | 26 | UTF-8 27 | UTF-8 28 | 8.15.0 29 | 17 30 | 31 | 1.54.0 32 | 33 | 34 | 35 | 36 | 37 | 38 | io.opentelemetry 39 | opentelemetry-bom 40 | 1.50.0 41 | pom 42 | import 43 | 44 | 45 | io.opentelemetry 46 | opentelemetry-bom-alpha 47 | 1.50.0-alpha 48 | pom 49 | import 50 | 51 | 52 | 53 | org.jetbrains.kotlin 54 | kotlin-stdlib 55 | 2.1.21 56 | 57 | 58 | org.jetbrains.kotlin 59 | kotlin-stdlib-common 60 | 2.0.21 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | co.elastic.apm 70 | apm-agent-api 71 | ${version.apm-agent-java} 72 | 73 | 74 | 75 | 76 | io.opentelemetry 77 | opentelemetry-api 78 | 79 | 80 | io.opentelemetry 81 | opentelemetry-sdk 82 | runtime 83 | 84 | 85 | io.opentelemetry 86 | opentelemetry-sdk-extension-autoconfigure 87 | runtime 88 | 89 | 90 | io.opentelemetry 91 | opentelemetry-exporter-otlp 92 | runtime 93 | 94 | 95 | 96 | 97 | co.elastic.logging 98 | logback-ecs-encoder 99 | 1.7.0 100 | 101 | 102 | org.springframework.boot 103 | spring-boot-starter-data-jpa 104 | 105 | 106 | org.springframework.boot 107 | spring-boot-starter-jersey 108 | 109 | 110 | org.springframework.boot 111 | spring-boot-starter-web 112 | 113 | 114 | org.postgresql 115 | postgresql 116 | 117 | 118 | com.h2database 119 | h2 120 | 121 | 122 | jakarta.xml.bind 123 | jakarta.xml.bind-api 124 | 125 | 126 | org.springframework.boot 127 | spring-boot-starter-test 128 | test 129 | 130 | 131 | org.javassist 132 | javassist 133 | 3.30.2-GA 134 | 135 | 136 | 137 | 138 | 139 | 140 | org.springframework.boot 141 | spring-boot-maven-plugin 142 | 143 | 144 | 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/OpbeansApplication.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Opbeans Java Demo Application 4 | * %% 5 | * Copyright (C) 2018 the original author or authors 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package co.elastic.apm.opbeans; 21 | 22 | import org.springframework.boot.SpringApplication; 23 | import org.springframework.boot.autoconfigure.SpringBootApplication; 24 | 25 | @SpringBootApplication 26 | public class OpbeansApplication { 27 | 28 | public static void main(String[] args) { 29 | SpringApplication.run(OpbeansApplication.class, args); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/controllers/APIRestController.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Opbeans Java Demo Application 4 | * %% 5 | * Copyright (C) 2018 the original author or authors 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package co.elastic.apm.opbeans.controllers; 21 | 22 | import co.elastic.apm.api.CaptureSpan; 23 | import co.elastic.apm.api.ElasticApm; 24 | import co.elastic.apm.opbeans.model.Customer; 25 | import co.elastic.apm.opbeans.model.Order; 26 | import co.elastic.apm.opbeans.repositories.CustomerRepository; 27 | import co.elastic.apm.opbeans.repositories.OrderDetail; 28 | import co.elastic.apm.opbeans.repositories.OrderList; 29 | import co.elastic.apm.opbeans.repositories.OrderRepository; 30 | import co.elastic.apm.opbeans.repositories.ProductDetail; 31 | import co.elastic.apm.opbeans.repositories.ProductList; 32 | import co.elastic.apm.opbeans.repositories.ProductRepository; 33 | import co.elastic.apm.opbeans.repositories.Stats; 34 | import co.elastic.apm.opbeans.repositories.TopProduct; 35 | import com.fasterxml.jackson.databind.JsonNode; 36 | import io.opentelemetry.api.GlobalOpenTelemetry; 37 | import io.opentelemetry.api.trace.Span; 38 | import io.opentelemetry.api.trace.StatusCode; 39 | import io.opentelemetry.api.trace.Tracer; 40 | import io.opentelemetry.context.Scope; 41 | import org.slf4j.Logger; 42 | import org.slf4j.LoggerFactory; 43 | import org.springframework.beans.factory.annotation.Autowired; 44 | import org.springframework.data.domain.PageRequest; 45 | import org.springframework.http.HttpStatus; 46 | import org.springframework.web.bind.annotation.GetMapping; 47 | import org.springframework.web.bind.annotation.PathVariable; 48 | import org.springframework.web.bind.annotation.PostMapping; 49 | import org.springframework.web.bind.annotation.RequestBody; 50 | import org.springframework.web.bind.annotation.RequestMapping; 51 | import org.springframework.web.bind.annotation.RestController; 52 | import org.springframework.web.server.ResponseStatusException; 53 | 54 | import java.sql.Date; 55 | import java.time.Instant; 56 | import java.util.Collection; 57 | import java.util.List; 58 | import java.util.Optional; 59 | import java.util.function.Supplier; 60 | 61 | @RestController 62 | @RequestMapping("/api") 63 | class APIRestController { 64 | 65 | private static final Logger logger = LoggerFactory.getLogger(APIRestController.class); 66 | private static final int TOP_SALES_SIZE = 3; 67 | 68 | private static final Tracer tracer = GlobalOpenTelemetry.get().getTracer("co.elastic.apm:opbeans"); 69 | 70 | private final ProductRepository productRepository; 71 | private final CustomerRepository customerRepository; 72 | private final OrderRepository orderRepository; 73 | 74 | @Autowired 75 | APIRestController(ProductRepository productRepository, CustomerRepository customerRepository, OrderRepository orderRepository) { 76 | this.productRepository = productRepository; 77 | this.customerRepository = customerRepository; 78 | this.orderRepository = orderRepository; 79 | } 80 | 81 | @GetMapping(value = "/products") 82 | @CaptureSpan("Annotation products span") 83 | Collection products() { 84 | ElasticApm.currentSpan().setLabel("foo", "bar"); 85 | return productRepository.findAllList(); 86 | } 87 | 88 | @GetMapping("/products/{productId}") 89 | ProductDetail product(@PathVariable long productId) { 90 | Optional result; 91 | 92 | Span span = tracer.spanBuilder("OpenTelemetry product span") 93 | .setAttribute("product.id", productId) 94 | .startSpan(); 95 | 96 | try (Scope scope = span.makeCurrent()) { 97 | result = productRepository.getOneDetail(productId); 98 | } finally { 99 | span.end(); 100 | } 101 | 102 | // Spring MVC uses exceptions to return a 404, thus we keep that out of the OTel span to avoid 103 | // any confusion as it's not an actual server error but a way to return a client error. 104 | return result.orElseThrow(notFound()); 105 | } 106 | 107 | @GetMapping("/products/{productId}/customers") 108 | List customerWhoBought(@PathVariable long productId) { 109 | return customerRepository.findCustomerWhoBoughtProduct(productId); 110 | } 111 | 112 | @GetMapping("/products/top") 113 | Collection topProducts() { 114 | logger.info("Finding top {} sales", TOP_SALES_SIZE); 115 | return productRepository.findTopSales(PageRequest.of(0, TOP_SALES_SIZE)); 116 | } 117 | 118 | @GetMapping("/customers") 119 | Collection customers() { 120 | return customerRepository.findAll(); 121 | } 122 | 123 | @GetMapping("/customers/{customerId}") 124 | Customer customer(@PathVariable long customerId) { 125 | return customerRepository.findById(customerId) 126 | .orElseThrow(notFound()); 127 | } 128 | 129 | @GetMapping("/orders") 130 | Collection orders() { 131 | Span span = tracer.spanBuilder("OpenTelemetry orders") 132 | .startSpan(); 133 | try (Scope scope = span.makeCurrent()) { 134 | return orderRepository.findAllList(); 135 | } finally { 136 | span.end(); 137 | } 138 | } 139 | 140 | @GetMapping("/orders/{orderId}") 141 | OrderDetail order(@PathVariable long orderId) { 142 | Span span = tracer.spanBuilder("OpenTelemetry get order") 143 | .setAttribute("order.id", orderId) 144 | .startSpan(); 145 | try (Scope scope = span.makeCurrent()) { 146 | return orderRepository.getOneDetail(orderId) 147 | .orElseThrow(notFound()); 148 | } finally { 149 | span.end(); 150 | } 151 | 152 | } 153 | 154 | @PostMapping("/orders/") 155 | OrderDetail createOrder(@RequestBody JsonNode orderJson) { 156 | long customerId = orderJson.get("customer_id").asLong(); 157 | Span span = tracer.spanBuilder("OpenTelemetry create order") 158 | .setAttribute("customer.id", customerId) 159 | .startSpan(); 160 | 161 | try (Scope scope = span.makeCurrent()) { 162 | // The "not found" error will be captured by the active span 163 | // While it is an error on the client side, we use it to showcase implicit error capture. 164 | Customer customer = customerRepository.findById(customerId) 165 | .orElseThrow(notFound()); 166 | 167 | Order savedOrder = saveOrder(customer); 168 | return order(savedOrder.getId()); 169 | } catch (Exception e) { 170 | span.setStatus(StatusCode.ERROR); 171 | span.recordException(e); 172 | throw e; 173 | } finally { 174 | span.end(); 175 | } 176 | } 177 | 178 | private Order saveOrder(Customer customer) { 179 | Span span = tracer.spanBuilder("OpenTelemetry save order") 180 | .startSpan(); 181 | try (Scope scope = span.makeCurrent()) { 182 | Order order = new Order(); 183 | order.setCreatedAt(Date.from(Instant.now())); 184 | order.setCustomer(customer); 185 | 186 | return orderRepository.save(order); 187 | } finally { 188 | span.end(); 189 | } 190 | 191 | } 192 | 193 | @GetMapping("/stats") 194 | Stats stats() { 195 | return new Stats(productRepository.count(), customerRepository.count(), orderRepository.count(), productRepository.getFinancial()); 196 | } 197 | 198 | private Supplier notFound() { 199 | return () -> new ResponseStatusException(HttpStatus.NOT_FOUND); 200 | } 201 | 202 | } -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/controllers/DTInterceptor.java: -------------------------------------------------------------------------------- 1 | package co.elastic.apm.opbeans.controllers; 2 | 3 | import java.io.IOException; 4 | import java.util.Arrays; 5 | import java.util.Random; 6 | 7 | import jakarta.servlet.http.HttpServletRequest; 8 | import jakarta.servlet.http.HttpServletResponse; 9 | 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import org.springframework.core.env.Environment; 13 | import org.springframework.http.HttpStatus; 14 | import org.springframework.http.client.ClientHttpResponse; 15 | import org.springframework.web.client.ResponseErrorHandler; 16 | import org.springframework.web.client.RestClientException; 17 | import org.springframework.web.client.RestTemplate; 18 | import org.springframework.web.servlet.HandlerInterceptor; 19 | 20 | /** 21 | * Interceptor that simulates DT call by delegating some of the API call to other services, obtained 22 | * from the environment variable OPBEANS_SERVICES 23 | * The probability to delegate the call is obtained from the environment variable OPBEANS_DT_PROBABILITY 24 | * If the probability is 0 or the list of services is empty, the redirection will be disabled 25 | * 26 | */ 27 | public class DTInterceptor implements HandlerInterceptor { 28 | 29 | private static Logger log = LoggerFactory.getLogger(DTInterceptor.class); 30 | 31 | private float dtProb; 32 | private String[] hostList; 33 | private RestTemplate restTemplate; 34 | private Random random = new Random(); 35 | 36 | public DTInterceptor(Environment env) { 37 | 38 | hostList = env.getProperty("OPBEANS_SERVICES", "").split(","); 39 | hostList = Arrays.stream(hostList).filter(s -> !s.equals("")).toArray(String[]::new); 40 | try { 41 | dtProb = Float.parseFloat(env.getProperty("OPBEANS_DT_PROBABILITY", "0.5")); 42 | } catch (NumberFormatException ex) { 43 | dtProb = 0.5f; 44 | } 45 | 46 | // Disable DT if we don't have any hosts 47 | if (hostList.length == 0) { 48 | dtProb = 0f; 49 | } else { 50 | // pre-process urls for simplicity 51 | for (int i = 0; i < hostList.length; i++) { 52 | if (!hostList[i].startsWith("http")) { //make sure we have a protocol 53 | hostList[i] = "http://" + hostList[i]+":3000"; 54 | } 55 | if (hostList[i].endsWith("/")) { // remove trailing / 56 | hostList[i] = hostList[i].substring(0, hostList[i].length()-1); 57 | } 58 | } 59 | } 60 | restTemplate = new RestTemplate(); 61 | restTemplate.setErrorHandler(new RestTemplateResponseErrorHandler()); 62 | log.debug("DT Probability: {}",dtProb); 63 | log.debug("DT Services: {}",Arrays.toString(hostList)); 64 | } 65 | 66 | @Override 67 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 68 | log.debug("Received request to {}",request.getRequestURI()); 69 | if (random.nextFloat() <= dtProb) { 70 | String destination = hostList[random.nextInt(hostList.length)]; 71 | log.debug("Executing remote call to {}{}",destination,request.getRequestURI()); 72 | try { 73 | String json = restTemplate.getForObject(destination + request.getRequestURI(), String.class); 74 | response.setContentType("application/json"); 75 | response.setStatus(HttpServletResponse.SC_OK); 76 | response.getWriter().write(json); 77 | } catch (RestClientException e) { 78 | Throwable cause = e.getCause(); 79 | if (cause instanceof RestCallException) { 80 | RestCallException rce = (RestCallException) cause; 81 | response.sendError(rce.statusCode, rce.statusText); 82 | log.debug("Returned error {},{}",rce.statusCode, rce.statusText); 83 | } else { 84 | log.error("Returned unknown error 500 ",e); 85 | response.sendError(500, "Internal error while executing remote DT call"); 86 | } 87 | } 88 | return false; 89 | } 90 | log.debug("Proceeding to local service"); 91 | return true; 92 | } 93 | 94 | private static class RestTemplateResponseErrorHandler implements ResponseErrorHandler { 95 | 96 | @Override 97 | public boolean hasError(ClientHttpResponse httpResponse) throws IOException { 98 | return (httpResponse.getStatusCode().is4xxClientError() 99 | || httpResponse.getStatusCode().is5xxServerError()); 100 | } 101 | 102 | @Override 103 | public void handleError(ClientHttpResponse httpResponse) throws IOException { 104 | throw new RestCallException(httpResponse.getStatusCode().value(), httpResponse.getStatusText()); 105 | } 106 | } 107 | 108 | private static class RestCallException extends IOException { 109 | private static final long serialVersionUID = 1L; 110 | private int statusCode; 111 | private String statusText; 112 | 113 | public RestCallException(int statusCode, String statusText) { 114 | this.statusCode = statusCode; 115 | this.statusText = statusText; 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/controllers/IndexController.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Opbeans Java Demo Application 4 | * %% 5 | * Copyright (C) 2018 the original author or authors 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package co.elastic.apm.opbeans.controllers; 21 | 22 | import jakarta.servlet.http.HttpServletResponse; 23 | 24 | import org.springframework.beans.factory.annotation.Autowired; 25 | import org.springframework.core.env.Environment; 26 | import org.springframework.stereotype.Controller; 27 | import org.springframework.web.bind.annotation.RequestMapping; 28 | import org.springframework.web.bind.annotation.ResponseBody; 29 | 30 | @Controller 31 | public class IndexController { 32 | 33 | @Autowired 34 | Environment env; 35 | 36 | @RequestMapping({ "/{path:[^\\\\.]*}", "/dashboard", "/products/*", "/orders/*", "/customers/*" }) 37 | public String redirect() { 38 | return "forward:/"; 39 | } 40 | 41 | @RequestMapping({ "/is-it-coffee-time" }) 42 | public String error() { 43 | throw new RuntimeException("Demo exception", new RuntimeException("root cause")); 44 | } 45 | 46 | @RequestMapping(value = { "/rum-config.js" }) 47 | @ResponseBody 48 | public String rumConfig(HttpServletResponse response) { 49 | response.setContentType("text/javascript"); 50 | return String.format("window.elasticApmJsBaseServerUrl = '%s'", 51 | env.getProperty("ELASTIC_APM_JS_SERVER_URL", "http://localhost:" + env.getProperty("local.server.port", "80"))); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/controllers/WebMvcConfig.java: -------------------------------------------------------------------------------- 1 | package co.elastic.apm.opbeans.controllers; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.core.env.Environment; 6 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 7 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 8 | 9 | @Configuration 10 | public class WebMvcConfig implements WebMvcConfigurer { 11 | 12 | @Autowired 13 | Environment env; 14 | 15 | @Override 16 | public void addInterceptors(InterceptorRegistry registry) { 17 | // Add interceptor to simulate distributed tracing for /api 18 | registry.addInterceptor(new DTInterceptor(env)).addPathPatterns("/api/*"); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/model/Customer.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Opbeans Java Demo Application 4 | * %% 5 | * Copyright (C) 2018 the original author or authors 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package co.elastic.apm.opbeans.model; 21 | 22 | import jakarta.persistence.Entity; 23 | import jakarta.persistence.GeneratedValue; 24 | import jakarta.persistence.GenerationType; 25 | import jakarta.persistence.Id; 26 | 27 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 28 | import com.fasterxml.jackson.annotation.JsonProperty; 29 | 30 | @Entity(name = "customers") 31 | public class Customer { 32 | 33 | @Id 34 | @GeneratedValue(strategy = GenerationType.IDENTITY) 35 | private long id; 36 | 37 | @JsonProperty("full_name") 38 | private String fullName; 39 | 40 | @JsonProperty("company_name") 41 | private String companyName; 42 | 43 | private String email; 44 | 45 | private String address; 46 | 47 | @JsonProperty("postal_code") 48 | private String postalCode; 49 | 50 | private String city; 51 | 52 | private String country; 53 | 54 | public long getId() { 55 | return id; 56 | } 57 | 58 | public void setId(long id) { 59 | this.id = id; 60 | } 61 | 62 | public String getFullName() { 63 | return fullName; 64 | } 65 | 66 | public void setFullName(String fullName) { 67 | this.fullName = fullName; 68 | } 69 | 70 | public String getCompanyName() { 71 | return companyName; 72 | } 73 | 74 | public void setCompanyName(String companyName) { 75 | this.companyName = companyName; 76 | } 77 | 78 | public String getEmail() { 79 | return email; 80 | } 81 | 82 | public void setEmail(String email) { 83 | this.email = email; 84 | } 85 | 86 | public String getAddress() { 87 | return address; 88 | } 89 | 90 | public void setAddress(String address) { 91 | this.address = address; 92 | } 93 | 94 | public String getPostalCode() { 95 | return postalCode; 96 | } 97 | 98 | public void setPostalCode(String postalCode) { 99 | this.postalCode = postalCode; 100 | } 101 | 102 | public String getCity() { 103 | return city; 104 | } 105 | 106 | public void setCity(String city) { 107 | this.city = city; 108 | } 109 | 110 | public String getCountry() { 111 | return country; 112 | } 113 | 114 | public void setCountry(String country) { 115 | this.country = country; 116 | } 117 | 118 | } -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/model/Order.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Opbeans Java Demo Application 4 | * %% 5 | * Copyright (C) 2018 the original author or authors 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package co.elastic.apm.opbeans.model; 21 | 22 | import java.util.Date; 23 | 24 | import jakarta.persistence.Entity; 25 | import jakarta.persistence.GeneratedValue; 26 | import jakarta.persistence.GenerationType; 27 | import jakarta.persistence.Id; 28 | import jakarta.persistence.ManyToOne; 29 | 30 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 31 | 32 | @Entity(name = "orders") 33 | public class Order { 34 | 35 | @Id 36 | @GeneratedValue(strategy = GenerationType.IDENTITY) 37 | private long id; 38 | 39 | @ManyToOne 40 | private Customer customer; 41 | 42 | private Date createdAt; 43 | 44 | public long getId() { 45 | return id; 46 | } 47 | 48 | public void setId(long id) { 49 | this.id = id; 50 | } 51 | 52 | public Date getCreatedAt() { 53 | return createdAt; 54 | } 55 | 56 | public void setCreatedAt(Date createdAt) { 57 | this.createdAt = createdAt; 58 | } 59 | 60 | public Customer getCustomer() { 61 | return customer; 62 | } 63 | 64 | public void setCustomer(Customer customer) { 65 | this.customer = customer; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/model/OrderLine.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Opbeans Java Demo Application 4 | * %% 5 | * Copyright (C) 2018 the original author or authors 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package co.elastic.apm.opbeans.model; 21 | 22 | import java.io.Serializable; 23 | 24 | import jakarta.persistence.Column; 25 | import jakarta.persistence.Embeddable; 26 | import jakarta.persistence.EmbeddedId; 27 | import jakarta.persistence.Entity; 28 | import jakarta.persistence.JoinColumn; 29 | import jakarta.persistence.ManyToOne; 30 | import jakarta.persistence.MapsId; 31 | 32 | @Entity(name = "order_lines") 33 | public class OrderLine { 34 | 35 | @EmbeddedId 36 | private OrderLineId orderId; 37 | 38 | @ManyToOne 39 | @MapsId("orderId") 40 | @JoinColumn(name = "order_id", nullable = false) 41 | private Order order; 42 | 43 | @ManyToOne 44 | @MapsId("productId") 45 | @JoinColumn(name = "product_id", nullable = false) 46 | private Product product; 47 | 48 | private int amount; 49 | 50 | public OrderLineId getOrderId() { 51 | return orderId; 52 | } 53 | 54 | public void setOrderId(OrderLineId orderId) { 55 | this.orderId = orderId; 56 | } 57 | 58 | public int getAmount() { 59 | return amount; 60 | } 61 | 62 | public void setAmount(int amount) { 63 | this.amount = amount; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/model/OrderLineId.java: -------------------------------------------------------------------------------- 1 | package co.elastic.apm.opbeans.model; 2 | 3 | import java.io.Serializable; 4 | 5 | import jakarta.persistence.Column; 6 | import jakarta.persistence.Embeddable; 7 | 8 | @Embeddable 9 | public class OrderLineId implements Serializable { 10 | private static final long serialVersionUID = 1L; 11 | 12 | @Column(name = "order_id") 13 | private long orderId; 14 | 15 | @Column(name = "product_id") 16 | private long productId; 17 | 18 | public long getOrderId() { 19 | return orderId; 20 | } 21 | 22 | public void setOrderId(long orderId) { 23 | this.orderId = orderId; 24 | } 25 | 26 | public long getProductId() { 27 | return productId; 28 | } 29 | 30 | public void setProductId(long productId) { 31 | this.productId = productId; 32 | } 33 | 34 | @Override 35 | public int hashCode() { 36 | final int prime = 31; 37 | int result = 1; 38 | result = prime * result + (int) (orderId ^ (orderId >>> 32)); 39 | result = prime * result + (int) (productId ^ (productId >>> 32)); 40 | return result; 41 | } 42 | 43 | @Override 44 | public boolean equals(Object obj) { 45 | if (this == obj) 46 | return true; 47 | if (obj == null) 48 | return false; 49 | if (getClass() != obj.getClass()) 50 | return false; 51 | OrderLineId other = (OrderLineId) obj; 52 | if (orderId != other.orderId) 53 | return false; 54 | if (productId != other.productId) 55 | return false; 56 | return true; 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/model/Product.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Opbeans Java Demo Application 4 | * %% 5 | * Copyright (C) 2018 the original author or authors 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package co.elastic.apm.opbeans.model; 21 | 22 | import jakarta.persistence.Column; 23 | import jakarta.persistence.Entity; 24 | import jakarta.persistence.GeneratedValue; 25 | import jakarta.persistence.Id; 26 | import jakarta.persistence.ManyToOne; 27 | 28 | @Entity(name = "products") 29 | public class Product { 30 | 31 | @Id 32 | @GeneratedValue 33 | private long id; 34 | 35 | private String sku; 36 | 37 | private String name; 38 | 39 | private String description; 40 | 41 | @ManyToOne 42 | private ProductType type; 43 | 44 | @Column(name = "selling_price") 45 | private double sellingPrice; 46 | 47 | private int stock; 48 | 49 | private double cost; 50 | 51 | public long getId() { 52 | return id; 53 | } 54 | 55 | public void setId(long id) { 56 | this.id = id; 57 | } 58 | 59 | public String getSku() { 60 | return sku; 61 | } 62 | 63 | public void setSku(String sku) { 64 | this.sku = sku; 65 | } 66 | 67 | public String getName() { 68 | return name; 69 | } 70 | 71 | public void setName(String name) { 72 | this.name = name; 73 | } 74 | 75 | public String getDescription() { 76 | return description; 77 | } 78 | 79 | public void setDescription(String description) { 80 | this.description = description; 81 | } 82 | 83 | public ProductType getType() { 84 | return type; 85 | } 86 | 87 | public void setType(ProductType type) { 88 | this.type = type; 89 | } 90 | 91 | public double getSellingPrice() { 92 | return sellingPrice; 93 | } 94 | 95 | public void setSellingPrice(double sellingPrice) { 96 | this.sellingPrice = sellingPrice; 97 | } 98 | 99 | public int getStock() { 100 | return stock; 101 | } 102 | 103 | public void setStock(int stock) { 104 | this.stock = stock; 105 | } 106 | 107 | public double getCost() { 108 | return cost; 109 | } 110 | 111 | public void setCost(double cost) { 112 | this.cost = cost; 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/model/ProductType.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Opbeans Java Demo Application 4 | * %% 5 | * Copyright (C) 2018 the original author or authors 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package co.elastic.apm.opbeans.model; 21 | 22 | import jakarta.persistence.Entity; 23 | import jakarta.persistence.GeneratedValue; 24 | import jakarta.persistence.Id; 25 | 26 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 27 | 28 | @Entity(name = "product_types") 29 | public class ProductType { 30 | 31 | @Id 32 | @GeneratedValue 33 | private long id; 34 | 35 | private String name; 36 | 37 | public long getId() { 38 | return id; 39 | } 40 | 41 | public void setId(long id) { 42 | this.id = id; 43 | } 44 | 45 | public String getName() { 46 | return name; 47 | } 48 | 49 | public void setName(String name) { 50 | this.name = name; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/repositories/CustomerRepository.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Opbeans Java Demo Application 4 | * %% 5 | * Copyright (C) 2018 the original author or authors 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package co.elastic.apm.opbeans.repositories; 21 | 22 | import java.util.List; 23 | 24 | import org.springframework.data.jpa.repository.JpaRepository; 25 | import org.springframework.data.jpa.repository.Query; 26 | 27 | import co.elastic.apm.opbeans.model.Customer; 28 | 29 | public interface CustomerRepository extends JpaRepository { 30 | 31 | @Query("SELECT distinct o.customer FROM order_lines ol left join ol.order o where ol.product.id=?1") 32 | List findCustomerWhoBoughtProduct(long productId); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/repositories/Numbers.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Opbeans Java Demo Application 4 | * %% 5 | * Copyright (C) 2018 the original author or authors 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package co.elastic.apm.opbeans.repositories; 21 | 22 | import com.fasterxml.jackson.annotation.JsonProperty; 23 | 24 | public interface Numbers { 25 | 26 | @JsonProperty("revenue") 27 | Double getRevenue(); 28 | 29 | @JsonProperty("cost") 30 | Double getCost(); 31 | 32 | @JsonProperty("profit") 33 | Double getProfit(); 34 | } -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/repositories/OrderDetail.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Opbeans Java Demo Application 4 | * %% 5 | * Copyright (C) 2018 the original author or authors 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package co.elastic.apm.opbeans.repositories; 21 | 22 | import java.util.Date; 23 | 24 | import com.fasterxml.jackson.annotation.JsonProperty; 25 | 26 | public interface OrderDetail { 27 | long getId(); 28 | 29 | @JsonProperty("customer_name") 30 | String getCustomerName(); 31 | 32 | @JsonProperty("customer_id") 33 | Long getCustomerId(); 34 | 35 | @JsonProperty("created_at") 36 | Date getCreatedAt(); 37 | } -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/repositories/OrderList.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Opbeans Java Demo Application 4 | * %% 5 | * Copyright (C) 2018 the original author or authors 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package co.elastic.apm.opbeans.repositories; 21 | 22 | import java.util.Date; 23 | 24 | import com.fasterxml.jackson.annotation.JsonProperty; 25 | 26 | public interface OrderList { 27 | 28 | @JsonProperty("id") 29 | Long getId(); 30 | 31 | @JsonProperty("customer_name") 32 | String getCustomerName(); 33 | 34 | @JsonProperty("created_at") 35 | Date getCreatedAt(); 36 | } -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/repositories/OrderRepository.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Opbeans Java Demo Application 4 | * %% 5 | * Copyright (C) 2018 the original author or authors 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package co.elastic.apm.opbeans.repositories; 21 | 22 | import java.util.List; 23 | import java.util.Optional; 24 | 25 | import org.springframework.data.jpa.repository.JpaRepository; 26 | import org.springframework.data.jpa.repository.Query; 27 | 28 | import co.elastic.apm.opbeans.model.Order; 29 | 30 | public interface OrderRepository extends JpaRepository { 31 | @Query("SELECT o.id as id, o.createdAt as createdAt, c.fullName as customerName FROM orders o LEFT JOIN o.customer as c") 32 | List findAllList(); 33 | 34 | @Query("SELECT o.id as id, o.createdAt as createdAt, c.fullName as customerName, c.id as customerId FROM orders o LEFT JOIN o.customer as c where o.id=?1") 35 | Optional getOneDetail(long id); 36 | } 37 | -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/repositories/ProductDetail.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Opbeans Java Demo Application 4 | * %% 5 | * Copyright (C) 2018 the original author or authors 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package co.elastic.apm.opbeans.repositories; 21 | 22 | import com.fasterxml.jackson.annotation.JsonProperty; 23 | 24 | public interface ProductDetail { 25 | 26 | @JsonProperty("id") 27 | Long getId(); 28 | 29 | @JsonProperty("sku") 30 | String getSku(); 31 | 32 | @JsonProperty("name") 33 | String getName(); 34 | 35 | @JsonProperty("description") 36 | String getDescription(); 37 | 38 | @JsonProperty("cost") 39 | Double getCost(); 40 | 41 | @JsonProperty("selling_price") 42 | double getSellingPrice(); 43 | 44 | @JsonProperty("stock") 45 | Long getStock(); 46 | 47 | @JsonProperty("type_id") 48 | long getTypeId(); 49 | 50 | @JsonProperty("type_name") 51 | String getTypeName(); 52 | 53 | @JsonProperty("sold") 54 | Long getSold(); 55 | } -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/repositories/ProductList.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Opbeans Java Demo Application 4 | * %% 5 | * Copyright (C) 2018 the original author or authors 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package co.elastic.apm.opbeans.repositories; 21 | 22 | import com.fasterxml.jackson.annotation.JsonProperty; 23 | 24 | public interface ProductList { 25 | 26 | @JsonProperty("id") 27 | Long getId(); 28 | 29 | @JsonProperty("sku") 30 | String getSku(); 31 | 32 | @JsonProperty("name") 33 | String getName(); 34 | 35 | @JsonProperty("stock") 36 | Long getStock(); 37 | 38 | @JsonProperty("type_name") 39 | String getTypeName(); 40 | } -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/repositories/ProductRepository.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Opbeans Java Demo Application 4 | * %% 5 | * Copyright (C) 2018 the original author or authors 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package co.elastic.apm.opbeans.repositories; 21 | 22 | import java.util.List; 23 | import java.util.Optional; 24 | 25 | import org.springframework.data.domain.Pageable; 26 | import org.springframework.data.jpa.repository.JpaRepository; 27 | import org.springframework.data.jpa.repository.Query; 28 | 29 | import co.elastic.apm.opbeans.model.Product; 30 | 31 | public interface ProductRepository extends JpaRepository { 32 | @Query("SELECT p.id as id, p.sku as sku, p.name as name, p.stock as stock, sum(o.amount) as sold FROM order_lines o LEFT JOIN o.product p GROUP BY p.id order by sold desc") 33 | List findTopSales(Pageable pageable); 34 | 35 | @Query("SELECT p.id as id, p.sku as sku, p.name as name, p.stock as stock, t.name AS typeName FROM products p LEFT JOIN p.type as t") 36 | List findAllList(); 37 | 38 | @Query("SELECT sum(o.amount*p.sellingPrice) as revenue,sum(o.amount*p.cost) as cost, sum(o.amount*(p.sellingPrice-p.cost)) as profit FROM order_lines o LEFT JOIN o.product p") 39 | Numbers getFinancial(); 40 | 41 | @Query("select p.id as id, p.sku as sku, p.name as name, p.description as description, p.cost as cost, p.sellingPrice as sellingPrice, p.stock as stock, t.id as typeId, t.name as typeName, (select sum(o.amount) from order_lines o where o.product=p) as sold from products as p LEFT JOIN p.type as t where p.id=?1") 42 | Optional getOneDetail(long id); 43 | } 44 | -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/repositories/Stats.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Opbeans Java Demo Application 4 | * %% 5 | * Copyright (C) 2018 the original author or authors 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package co.elastic.apm.opbeans.repositories; 21 | 22 | import com.fasterxml.jackson.annotation.JsonProperty; 23 | 24 | public class Stats { 25 | 26 | private final Long products; 27 | 28 | private final Long customers; 29 | 30 | private final Long orders; 31 | 32 | private final Numbers numbers; 33 | 34 | public Stats(Long products, Long customers, Long orders, Numbers numbers) { 35 | this.products = products; 36 | this.customers = customers; 37 | this.orders = orders; 38 | this.numbers = numbers; 39 | } 40 | 41 | @JsonProperty("products") 42 | public Long getProducts() { 43 | return products; 44 | } 45 | 46 | @JsonProperty("customers") 47 | public Long getCustomers() { 48 | return customers; 49 | } 50 | 51 | @JsonProperty("orders") 52 | public Long getOrders() { 53 | return orders; 54 | } 55 | 56 | @JsonProperty("numbers") 57 | public Numbers getNumbers() { 58 | return numbers; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /opbeans/src/main/java/co/elastic/apm/opbeans/repositories/TopProduct.java: -------------------------------------------------------------------------------- 1 | /*- 2 | * #%L 3 | * Opbeans Java Demo Application 4 | * %% 5 | * Copyright (C) 2018 the original author or authors 6 | * %% 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * #L% 19 | */ 20 | package co.elastic.apm.opbeans.repositories; 21 | 22 | import com.fasterxml.jackson.annotation.JsonProperty; 23 | 24 | public interface TopProduct { 25 | 26 | @JsonProperty("id") 27 | Long getId(); 28 | 29 | @JsonProperty("sku") 30 | String getSku(); 31 | 32 | @JsonProperty("name") 33 | String getName(); 34 | 35 | @JsonProperty("stock") 36 | Long getStock(); 37 | 38 | @JsonProperty("sold") 39 | Long getSold(); 40 | } -------------------------------------------------------------------------------- /opbeans/src/main/resources/application-customdb.properties: -------------------------------------------------------------------------------- 1 | # Allow Thymeleaf templates to be reloaded at dev time 2 | spring.thymeleaf.cache: false 3 | server.tomcat.basedir: target/tomcat 4 | 5 | # Prevent errors with jackson object mapper and hibernate entities 6 | spring.jackson.default-property-inclusion=NON_NULL 7 | 8 | # JPA 9 | spring.jpa.show-sql=false 10 | spring.jpa.hibernate.ddl-auto=none 11 | 12 | # Datasource 13 | spring.jpa.database=POSTGRESQL 14 | spring.datasource.driverClassName=org.postgresql.Driver 15 | spring.datasource.url=jdbc:postgresql://localhost/opbeans?user=postgres&password=verysecure 16 | 17 | # Prevent error with postgres initialization see: https://github.com/spring-projects/spring-boot/issues/12007 18 | spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true 19 | 20 | 21 | -------------------------------------------------------------------------------- /opbeans/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Allow Thymeleaf templates to be reloaded at dev time 2 | spring.thymeleaf.cache: false 3 | server.tomcat.basedir: target/tomcat 4 | 5 | # Prevent errors with jackson object mapper and hibernate entities 6 | spring.jackson.default-property-inclusion=NON_NULL 7 | spring.jackson.serialization.fail-on-empty-beans=false 8 | 9 | # JPA 10 | spring.jpa.show-sql=false 11 | spring.jpa.hibernate.ddl-auto=none 12 | 13 | # Datasource 14 | spring.jpa.database=H2 15 | spring.datasource.driverClassName=org.h2.Driver 16 | spring.datasource.url=jdbc:h2:mem:opbeans 17 | 18 | # H2 19 | spring.h2.console.enabled=true 20 | spring.h2.console.path=/h2 21 | 22 | # H2 platform for import scripts 23 | spring.sql.init.platform=H2 24 | -------------------------------------------------------------------------------- /opbeans/src/main/resources/application_old.properties: -------------------------------------------------------------------------------- 1 | spring.jpa.database=POSTGRESQL 2 | spring.jpa.show-sql=false 3 | spring.datasource.driverClassName=org.postgresql.Driver 4 | spring.datasource.url=jdbc:postgresql://postgres/opbeans?user=postgres&password=verysecure 5 | 6 | # Allow Thymeleaf templates to be reloaded at dev time 7 | spring.thymeleaf.cache: false 8 | server.tomcat.basedir: target/tomcat 9 | 10 | # Prevent error with postgress initialization see: https://github.com/spring-projects/spring-boot/issues/12007 11 | spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true 12 | 13 | 14 | # Prevent errors with jackson object mapper and hibernate entities 15 | spring.jackson.default-property-inclusion=NON_NULL -------------------------------------------------------------------------------- /opbeans/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ${ELASTIC_APM_SERVICE_NAME:-opbeans-java} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /opbeans/src/main/resources/public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/opbeans-java/52370623e61d38c8c5273afccbe1f8272cfd3dea/opbeans/src/main/resources/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /opbeans/src/main/resources/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/opbeans-java/52370623e61d38c8c5273afccbe1f8272cfd3dea/opbeans/src/main/resources/public/apple-touch-icon.png -------------------------------------------------------------------------------- /opbeans/src/main/resources/public/error/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /opbeans/src/main/resources/public/error/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /opbeans/src/main/resources/public/error/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /opbeans/src/main/resources/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/opbeans-java/52370623e61d38c8c5273afccbe1f8272cfd3dea/opbeans/src/main/resources/public/favicon.ico -------------------------------------------------------------------------------- /opbeans/src/main/resources/public/images/products/OP-DRC-C1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/opbeans-java/52370623e61d38c8c5273afccbe1f8272cfd3dea/opbeans/src/main/resources/public/images/products/OP-DRC-C1.jpg -------------------------------------------------------------------------------- /opbeans/src/main/resources/public/images/products/OP-DRC-C6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/opbeans-java/52370623e61d38c8c5273afccbe1f8272cfd3dea/opbeans/src/main/resources/public/images/products/OP-DRC-C6.jpg -------------------------------------------------------------------------------- /opbeans/src/main/resources/public/images/products/OP-DRC-C9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/opbeans-java/52370623e61d38c8c5273afccbe1f8272cfd3dea/opbeans/src/main/resources/public/images/products/OP-DRC-C9.jpg -------------------------------------------------------------------------------- /opbeans/src/main/resources/public/images/products/OP-LRC-C3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/opbeans-java/52370623e61d38c8c5273afccbe1f8272cfd3dea/opbeans/src/main/resources/public/images/products/OP-LRC-C3.jpg -------------------------------------------------------------------------------- /opbeans/src/main/resources/public/images/products/OP-LRC-C4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/opbeans-java/52370623e61d38c8c5273afccbe1f8272cfd3dea/opbeans/src/main/resources/public/images/products/OP-LRC-C4.jpg -------------------------------------------------------------------------------- /opbeans/src/main/resources/public/images/products/OP-LRC-C8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/opbeans-java/52370623e61d38c8c5273afccbe1f8272cfd3dea/opbeans/src/main/resources/public/images/products/OP-LRC-C8.jpg -------------------------------------------------------------------------------- /opbeans/src/main/resources/public/images/products/OP-MRC-C2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/opbeans-java/52370623e61d38c8c5273afccbe1f8272cfd3dea/opbeans/src/main/resources/public/images/products/OP-MRC-C2.jpg -------------------------------------------------------------------------------- /opbeans/src/main/resources/public/images/products/OP-MRC-C5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/opbeans-java/52370623e61d38c8c5273afccbe1f8272cfd3dea/opbeans/src/main/resources/public/images/products/OP-MRC-C5.jpg -------------------------------------------------------------------------------- /opbeans/src/main/resources/public/images/products/OP-MRC-C7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/opbeans-java/52370623e61d38c8c5273afccbe1f8272cfd3dea/opbeans/src/main/resources/public/images/products/OP-MRC-C7.jpg -------------------------------------------------------------------------------- /opbeans/src/main/resources/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | OpBeans 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /opbeans/src/main/resources/public/static/media/icons.97493d3f.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elastic/opbeans-java/52370623e61d38c8c5273afccbe1f8272cfd3dea/opbeans/src/main/resources/public/static/media/icons.97493d3f.woff2 -------------------------------------------------------------------------------- /opbeans/src/test/java/co/elastic/apm/opbeans/OpbeansApplicationTests.java: -------------------------------------------------------------------------------- 1 | package co.elastic.apm.opbeans; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.test.web.servlet.MockMvc; 8 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 9 | import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; 10 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; 11 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 12 | 13 | @SpringBootTest 14 | @AutoConfigureMockMvc 15 | public class OpbeansApplicationTests { 16 | 17 | @Autowired 18 | private MockMvc mockMvc; 19 | 20 | @Test 21 | public void databasePopulated() throws Exception { 22 | this.mockMvc.perform(get("/api/products")).andDo(print()).andExpect(status().isOk()) 23 | .andExpect(jsonPath("$").isArray()) 24 | .andExpect(jsonPath("$").isNotEmpty()); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | JAVA_AGENT='' 6 | 7 | APP_OPTS="" 8 | if [ "" != "${DEBUG_ADDRESS:-}" ]; then 9 | APP_OPTS="-agentlib:jdwp=transport=dt_socket,server=n,address=${DEBUG_ADDRESS},suspend=y" 10 | fi 11 | 12 | APP_OPTS="${APP_OPTS} -Dspring.profiles.active=${OPBEANS_JAVA_PROFILE:-}" 13 | APP_OPTS="${APP_OPTS} -Dserver.port=${OPBEANS_SERVER_PORT:-}" 14 | APP_OPTS="${APP_OPTS} -Dserver.address=${OPBEANS_SERVER_ADDRESS:-0.0.0.0}" 15 | APP_OPTS="${APP_OPTS} -Dspring.datasource.url=${DATABASE_URL:-}" 16 | APP_OPTS="${APP_OPTS} -Dspring.datasource.driverClassName=${DATABASE_DRIVER:-}" 17 | APP_OPTS="${APP_OPTS} -Dspring.jpa.database=${DATABASE_DIALECT:-}" 18 | 19 | case "${APM_AGENT_TYPE:-none}" in 20 | "opentelemetry") 21 | JAVA_AGENT="-javaagent:/app/opentelemetry-javaagent.jar" 22 | APP_OPTS="${APP_OPTS} -Dotel.instrumentation.runtime-metrics.enabled=true" 23 | ;; 24 | "elasticapm") 25 | JAVA_AGENT="-javaagent:/app/elastic-apm-agent.jar" 26 | ;; 27 | "none") 28 | JAVA_AGENT="" 29 | ;; 30 | *) 31 | echo "unknown agent type $APM_AGENT_TYPE" 32 | exit 1 33 | ;; 34 | esac 35 | 36 | java \ 37 | ${JAVA_AGENT} \ 38 | ${APP_OPTS} \ 39 | -jar ./app.jar 40 | -------------------------------------------------------------------------------- /tests/test_helpers.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | # check dependencies 4 | ( 5 | type docker &>/dev/null || ( echo "docker is not available"; exit 1 ) 6 | type curl &>/dev/null || ( echo "curl is not available"; exit 1 ) 7 | )>&2 8 | -------------------------------------------------------------------------------- /tests/tests.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | load 'test_helper/bats-support/load' 4 | load 'test_helper/bats-assert/load' 5 | load test_helpers 6 | 7 | IMAGE="bats-opbeans" 8 | CONTAINER="opbeans-java" 9 | 10 | @test "build image" { 11 | cd $BATS_TEST_DIRNAME/.. 12 | run docker compose build 13 | assert_success 14 | } 15 | 16 | @test "create test container" { 17 | run docker compose up -d 18 | assert_success 19 | } 20 | 21 | @test "test container is running" { 22 | run docker inspect -f {{.State.Running}} $CONTAINER 23 | assert_output --partial 'true' 24 | } 25 | 26 | @test "opbeans is running in port ${PORT}" { 27 | sleep 50 28 | URL="http://127.0.0.1:$(docker port "$CONTAINER" ${PORT} | cut -d: -f2)" 29 | run curl -v --fail --connect-timeout 10 --max-time 30 "${URL}/" 30 | assert_success 31 | assert_output --partial 'HTTP/1.1 200' 32 | } 33 | 34 | @test "clean test containers" { 35 | run docker compose down 36 | assert_success 37 | } 38 | --------------------------------------------------------------------------------