Merge branch 'master' into bug5774

This commit is contained in:
Axel Uhl committed 2024-05-03 17:37:32 +02:00
commit f37e057e4b
310 files changed
+3051 -1837

No files matched your search

+48
View File
@@ -0,0 +1,48 @@
on: workflow_dispatch
name: Test release creation
jobs:
build:
name: Test uploading release asset
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Build project # This would actually build your project, using zip for an example artifact
run: |
RELEASE_DATE=$( date +%Y%m%d%H%M )
echo "RELEASE_DATE=${RELEASE_DATE}" >>${GITHUB_ENV}
mkdir -p dist/build-${RELEASE_DATE}
echo "humba" >dist/build-${RELEASE_DATE}/build-${RELEASE_DATE}.tar.gz
echo "trala" >dist/build-${RELEASE_DATE}/release-notes.txt
echo "SIMPLE_VERSION_INFO=$( basename dist/* )" >>${GITHUB_ENV}
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ env.SIMPLE_VERSION_INFO }}
release_name: ${{ env.SIMPLE_VERSION_INFO }}
draft: false
prerelease: false
- name: Upload Release Asset tar.gz
id: upload-release-asset-tar-gz
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ./dist/${{ env.SIMPLE_VERSION_INFO }}/${{ env.SIMPLE_VERSION_INFO }}.tar.gz
asset_name: ${{ env.SIMPLE_VERSION_INFO }}.tar.gz
asset_content_type: application/x-tar
- name: Upload Release Asset release_notes.txt
id: upload-release-asset-release-notes-txt
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ./dist/${{ env.SIMPLE_VERSION_INFO }}/release-notes.txt
asset_name: release-notes.txt
asset_content_type: text/plain
+47
View File
@@ -0,0 +1,47 @@
name: play-with-docker
on:
workflow_dispatch:
inputs:
release:
description: Release
default: ''
jobs:
play-with-docker-job:
#runs-on: ubuntu-latest-64cpu
#runs-on: ubuntu-latest-4cpu
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Login to docker.sapsailing.com
uses: docker/login-action@v3
with:
registry: docker.sapsailing.com
username: ${{ secrets.DOCKER_SAPSAILING_COM_USERNAME }}
password: ${{ secrets.DOCKER_SAPSAILING_COM_PASSWORD }}
- name: Copy a few files
shell: bash
run: |
cp "java/target/env.sh" docker/
cp "java/target/start" docker/
cp "java/target/configuration/JavaSE-11.profile" docker/
- name: Determine release
shell: bash
run: |
echo "RELEASE=$( if [ "${{ github.event.inputs.release }}" = "" ]; then
wget -O - https://releases.sapsailing.com/ 2>/dev/null | grep 'build-[0-9]\{10\}' | tail -1 | sed -e 's/^.*\(build-[0-9]*\).*$/\1/'
else
echo "${{ github.event.inputs.release }}"
fi )" >>${GITHUB_ENV}
- name: Build & push Docker image
uses: docker/build-push-action@v5
with:
build-args: RELEASE=${{ env.RELEASE }}
tags: docker.sapsailing.com/test:${{ env.RELEASE }}
file: docker/Dockerfile
context: docker/
push: true
- name: Clean up copied files
shell: bash
run: rm docker/start docker/env.sh docker/JavaSE-11.profile
+105
View File
@@ -0,0 +1,105 @@
name: release
on:
push:
paths-ignore:
- 'wiki/**'
- '.github/workflows/*'
- '**/*.md'
workflow_dispatch: {}
jobs:
build:
runs-on: ubuntu-latest-64cpu
#runs-on: ubuntu-latest-4cpu
steps:
- name: Check out the repository to the runner
uses: actions/checkout@v4
with:
fetch-depth: '500'
- name: Install JDK 8
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '8'
mvn-toolchain-id: 'JavaSE-1.8'
- name: Install JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
mvn-toolchain-id: 'JavaSE-17'
- name: Setup Android SDK
uses: android-actions/setup-android@v3
with:
log-accepted-android-sdk-licenses: 'false'
cmdline-tools-version: 9123335 # This corresponds to human-friendly version number 8.0
- name: Start MongoDB
uses: supercharge/mongodb-github-action@1.10.0
with:
mongodb-version: 4.4
- name: Start RabbitMQ
uses: namoshek/rabbitmq-github-action@v1
with:
version: '3.8.9'
ports: '5672:5672'
- shell: bash
env: # Or as an environment variable
APP_PARAMETERS: "-Daws.region=eu-west-1 -Dgoogle.maps.authenticationparams=${{ secrets.GOOGLE_MAPS_AUTHENTICATIONPARAMS }} -Daws.s3.test.s3AccessId=${{ secrets.AWS_S3_TEST_S3ACCESSID }} -Daws.s3.test.s3AccessKey=${{ secrets.AWS_S3_TEST_S3ACCESSKEY }}"
JAVA8_HOME: ${{env.JAVA_HOME_8_X64}}
run: |
./configuration/buildAndUpdateProduct.sh -x 60 build 2>&1 | tee build.log
- name: Collect Test Reports
uses: dorny/test-reporter@v1
if: always()
with:
name: Maven Tests
path: '**/TEST-*.xml'
max-annotations: '1'
list-suites: failed
list-tests: failed
reporter: java-junit
fail-on-error: true
- shell: bash
run: |
./configuration/buildAndUpdateProduct.sh -u -L release
- name: Determine release name
run: |
echo "SIMPLE_VERSION_INFO=$( basename dist/* )" >>${GITHUB_ENV}
- name: Upload distribution artifact
uses: actions/upload-artifact@v4
with:
name: ${{ env.SIMPLE_VERSION_INFO }}.zip
path: dist/**/*
retention-days: 90
- name: Create Release
id: create_release
if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/docker-17' || startsWith(github.ref, 'refs/heads/releases/') }}
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ env.SIMPLE_VERSION_INFO }}
release_name: ${{ env.SIMPLE_VERSION_INFO }}
draft: false
prerelease: false
- name: Upload Release Asset tar.gz
id: upload-release-asset-tar-gz
if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/docker-17' || startsWith(github.ref, 'refs/heads/releases/') }}
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ./dist/${{ env.SIMPLE_VERSION_INFO }}/${{ env.SIMPLE_VERSION_INFO }}.tar.gz
asset_name: ${{ env.SIMPLE_VERSION_INFO }}.tar.gz
asset_content_type: application/x-tar
- name: Upload Release Asset release_notes.txt
id: upload-release-asset-release-notes-txt
if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/docker-17' || startsWith(github.ref, 'refs/heads/releases/') }}
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ./dist/${{ env.SIMPLE_VERSION_INFO }}/release-notes.txt
asset_name: release-notes.txt
asset_content_type: text/plain
@@ -0,0 +1,15 @@
name: "Launch Metadata Creation Tool for REUSE"
on:
workflow_dispatch: ~
jobs:
create_metadata_proposal:
runs-on: ubuntu-latest
name: "Metadata Creation Tool"
steps:
- uses: SAP/metadata-creation-tool-for-reuse@main
with:
repository_url: "${{ github.server_url }}/${{ github.repository }}"
access_token: "${{ secrets.REUSE_ACCESS_TOKEN }}"
copyright_owner: "SAP SE or an SAP affiliate company"
upstream_contact: "Axel Uhl <axel.uhl@sap.com>"
+60
View File
@@ -0,0 +1,60 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: sailing-analytics
Upstream-Contact: SAP Open Source Program Office ospo@sap.com
Source: https://github.com/SAP/sailing-analytics
Files: java/com.google.gwt.servlet/*
Copyright: 2024 com.google.gwt.servlet contributors.
License: Apache-2.0
Files: java/net.sf.marineapi/doc/*
Copyright: 2024 doc contributors.
License: GPL-3.0-only
Files: java/com.google.gwt.user/*
Copyright: 2024 com.google.gwt.user contributors.
License: Apache-2.0
Files: java/com.googlecode.java-diff-utils.test/*
Copyright: 2024 com.googlecode.java-diff-utils.test contributors.
License: Apache-2.0
Files: *
Copyright: 2024 SAP SE or an SAP affiliate company and sailing-analytics contributors.
License: Apache-2.0
Files: java/com.google.gwt.dev/*
Copyright: 2024 com.google.gwt.dev contributors.
License: Apache-2.0
Files: java/org.mp4parser.isoparser/*
Copyright: 2024 org.mp4parser.isoparser contributors.
License: Apache-2.0
Files: java/elemental2/*
Copyright: 2024 elemental2 contributors.
License: Apache-2.0
Files: java/org.json.simple/*
Copyright: 2024 org.json.simple contributors.
License: MIT
Files: java/org.openqa.selenium.osgi/*
Copyright: 2024 org.openqa.selenium.osgi contributors.
License: Apache-2.0
Files: java/com.google.gwt.ajaxloader/*
Copyright: 2024 com.google.gwt.ajaxloader contributors.
License: Apache-2.0
Files: java/com.googlecode.java-diff-utils/*
Copyright: 2024 com.googlecode.java-diff-utils contributors.
License: Apache-2.0
Files: java/com.sap.sailing.gwt.ui/qrcode/*
Copyright: 2024 qrcode contributors.
License: MIT
Files: ios/SAPTracker/src/xcode/SAPTracker/flags/*
Copyright: 2024 flags contributors.
License: MIT
+171
View File
@@ -0,0 +1,171 @@
# Contributing to the Sailing Analytics
Thank you for your interest in the Sailing Analytics! We welcome contributions in all forms.
Here are some of the ways you can contribute to Sailing Analytics
Note: This is a living document. Like the Sailing Analytics, this document will be improved over time with the help of our community. Feedback welcome.
----
## Reporting Issues
Bug reports welcome! We are currently still using [Bugzilla](https://bugzilla.sapsailing.com) for tracking user stories and bugs.
### Determining if an Issue Should be Created
Analyzing reports is a bit of work, so please ask yourself these questions before creating an issue:
* Does the bug really apply to Sailing Analytics
There may be reasons the problem is occurring that have nothing to do with the Sailing Anlaytics code. Consider the following:
* The problem may be caused by code that is not part of Sailing Analytics.
* The problem may be caused by data being sent to Sailing Analytics through REST API calls.
* The behavior may be different from what you expect, but may be working as designed. Or the feature may need improvement. In this case, it would be an enhancement request. Feature requests can also be submitted to [Bugzilla](https://bugzilla.sapsailing.com).
* Is the problem reproducible in the latest release?
* If you are not using the latest libraries or source code, please try to reproduce with the latest code first.
* Make sure the problem is consistently reproducible using repeatable steps.
* Has this bug already been reported?
* Please search the issue tracker for a similar bug before reporting the issue as a new bug.
If the bug does indeed apply to Sailing Analytics code, please create an issue.
### Providing the Right Information for the Issue
* Summarize the issue well. The following are some guidelines:
* Precisely state what you expected as compared to the actual behavior you're seeing.
* Include only those details that apply to the issue.
* Be concise, but include details important for helping us in understanding the problem and finding the root cause.
* State the version you are testing, which browser you are using, and on which device.
If it is possible to indicate what you've seen in other browser and device combinations, that is even better! For example, does the issue occur in all browsers, or just one browser on one particular operating system? (For example, "only in Firefox on Windows 10.)
* If possible, include the last version where the bug was not present.
* If the bug is more visual, please attach a screenshot and mark up the problem.
* Generally, provide as much detail as necessary, but balance our need for information with how obvious the problem is.
* Provide detailed, step-by-step instructions for reproducing the issue with an example, including, if possible:
* A URL to your example
* Screenshots if it helps us understand better.
* Do not include more than one bug per issue created. This helps us to analyze bugs more easily.
Please report issues in English.
### About Reporting Security Issues
If you find a security issue, we'd like to encourage you to tell us directly instead of creating a public issue. This way we can fix it before it can be exploited.
* Researchers/non-Customers: please send the relevant information to support@sapsailing.com.
### How We Process Issues
New issues are reviewed regularly for validity and prioritization. Confirmed issues are given the "Approved" label, and the rest are either sent back to the reporter with a request for more details, or closed with an explanation.
Validated issues are then moved into one of these buckets:
* Priority issues will be assigned to one of our developers
* Issues that are less urgent will be left open as "contribution welcome"
* Certain issues may be moved to our internal issue tracking system if we don't think they belong to the Sailing Analytics.
Issues are closed when the fix is merged to develop. The release that contains the fix will be noted in the comments and the release changelog.
### How We Use Bugzilla Priorities
Our Bugzilla set-up supports five priorities (1-5):
* "1" is meant for show stoppers where, e.g., the website locks up, wrong data is being reported or the application crashes. Issues with thie priority need immediate action to unblock a live event using the solution.
* "2" is used for things that definitely need fixing but that are not necessarily holding up general operations at a live event.
* "3" identifies nice to have things we would like to see fixed at some point, but there is no specific urgency. Topics with this priority may be good candidates to start working on the project.
* "4" and "5" are what you use to make sure an idea is recorded and not forgotten, but other than when searching for a neat onboarding task for someone who would like to join the project, tasks with these priorities are hardly ever looked at.
### Issue Reporting Disclaimer
Feedback, especially bug reports, are always welcome. However, our capacity as a team is limited -- we cannot answer specific project or consultation requests, nor can we invest time in fleshing out what might be a bug. Because of this, we reserve the right to close or not process issue reports that do not contain enough information. We also do not guarantee that every well-documented issue will be fixed.
That being said, we will try our very best to ensure the Sailing Analytics codebase is of high quality.
----
## Contributing Code
We welcome contributions to the Sailing Analytics codebase. Before you start your first contribution, here are some things you should know:
1. You must be aware of the Apache License (which describes contributions), and you must agree to the [Contributors License Agreement](LICENSE.md). This is common practice for most open source projects.
* For company contributors, special rules apply. See the respective section below for details.
1. Contributions must be compliant with the project code style, quality, and standards. We also follow them :-)
The `Contribution Content Guidelines` section below gives more details on the coding guidelines.
1. Not all contributions will be accepted.
* The code you are submitting must fit the overall vision and direction of the Sailing Analytics and really improve it. Bug fixes are simple cases, for example, but new features may work better as third-party extensions.
* Major feature implementations should be discussed on the issue tracker.
### Contributor License Agreement
When you contribute anything to the Sailing Analytics (code, documentation, analysis, anything), be aware that your contribution is covered by the same [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0) that is applied to the Sailing Analytics itself.
This applies to all contributors, including those contributing on behalf of a company.
### Developer Certificate of Origin (DCO)
Due to legal reasons, contributors will be asked to accept a DCO when they create the first pull request to this project. This happens in an automated fashion during the submission process. SAP uses [the standard DCO text of the Linux Foundation](https://developercertificate.org/).
#### Company Contributors
If employees of a company contribute code, in **addition** to the individual agreement above, there needs to be one company agreement submitted. This is mainly for the protection of the contributing employees.
A company representative authorized to do so must fill out the following [Corporate Contributor License Agreement](/docs/SAP%20Corporate%20Contributor%20License%20Agreement.pdf) form. The form contains a list of employees who are authorized to contribute on behalf of your company. When this list changes, please let us know.
Submit the form to us through one of the following methods:
* Email to [opensource@sap.com](mailto:opensource@sap.com) and [support@sapsailing.com](mailto:support@sapsailing.com)
* Fax to +49 6227 78-45813
* Mail to:
Industry Standards & Open Source Team
Dietmar-Hopp-Allee 16
69190 Walldorf, Germany
### Contribution Content Guidelines
A contribution will be considered for inclusion in the Sailing Analytics if it meets the following criteria:
* The contribution fits the overall vision and direction of the Sailing Analytics
* The contribution truly improves the solution
* The contribution follows the applicable guidelines and standards.
The "guidelines and standards" requirement could fill entire books and still lack a 100% clear definition, but rest assured that you will receive feedback if something is not right. That being said, please consult the [Onboarding Document](https://wiki.sapsailing.com/wiki/howto/onboarding).
### Contribution Process
1. Make sure the change would be welcome, as described above.
1. Create a fork of the Sailing Analytics sources.
1. Work on the change in your fork (either on the `master` branch or on a feature branch, typically named after the Bugzilla issue, such as ``bug1234``).
1. Commit and push your changes.
1. Give reasonable commit messages; a short first line, and if you'd like to write additional, more verbose comments, finish the first line with a semicolon, add an empty line, then add more comments.
1. If your change fixes an issue reported in Bugzilla, add the following line to the commit message:
```bug{issueNumber}: ...```
1. Create a pull request so that we can review your change.
1. Wait for our code review and approval, possibly enhancing your change on request.
Note: This may take time, depending on the required effort for reviewing, testing, and clarification. Sailing Analytics developers are also working their regular duties.
1. After the change has been approved, we will inform you in a comment.
1. Due to internal SAP processes, your pull request cannot be merged directly into the branch. It will be merged internally, and will also immediately appear in the public repository.
1. We will close the pull request. At that point, you can delete your branch.
We look forward to hearing from you!
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [2024] [SAP SE or an SAP affiliate company and sailing-analytics contributors]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+73
View File
@@ -0,0 +1,73 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+9
View File
@@ -0,0 +1,9 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+53 -5
View File
@@ -1,15 +1,51 @@
# SAP Sailing Analytics
The SAP Sailing Analytics platform as seen on [sapsailing.com](https://sapsailing.com)
## About this Project
The Sailing Analytics, formerly known as the "SAP Sailing Analytics," are a solution for portraying and analyzing sailing regattas, supporting training scenarios, and powering the vast archive at https://sapsailing.com.
## Description
This is the software running the SAP Sailing Analytics platform as seen on [sapsailing.com](https://sapsailing.com)
Sailing provides the perfect platform for SAP to showcase solutions and help the sport run like never before. SAP’s involvement in the sport has transformed the sailing experience by providing tools, which:
Help sailors analyze performance and optimize strategy
Bring fans closer to the action
Provide the media with information and insights to deliver a greater informed commentary
- Help sailors analyze performance and optimize strategy
- Bring fans closer to the action
- Provide the media with information and insights to deliver a greater informed commentary
SAP has a longstanding involvement with sailing and has established a portfolio spanning across teams and regattas.
Start contributing: [https://wiki.sapsailing.com/wiki/howto/onboarding](https://wiki.sapsailing.com/wiki/howto/onboarding)
## Requirements
The software can be run on any Linux or Windows machine with ``bash`` installed; it has also been compiled successfully for the ARM platform and was deployed to a Raspberry Pi computer. As a database, MongoDB is required, tested with releases 4.4, 5.0, and 6.0. For use in a replicated scenario (scale-out, high availability), RabbitMQ is required. Docker Compose can be used to tie these three components together, as Docker images are produced on a regular basis.
Compute node and database sizing depends on several aspects of your workloads, such as whether live or replay data is to be served, how many different classes with separate leaderboard are racing concurrently, how many competitors are racing in each class, or how many concurrent viewers produce how many requests and which type (e.g., analytical, data mining, or watching a live race).
To quantify this at least approximately, here are a few examples for typical node sizes that can handle such types of events reasonably well:
- National sailing league event; six boats, 18 competitors, a single live leaderboard: 8GB of RAM and 4-8 CPUs
- Large multi-class event with 15 classes with their separate leaderboards, concurrently racing on six course areas: 16GB of RAM, 16 CPUs
- Archive of 30,000 races with a few thousand visitors per day with varying analytical and replay workloads: 64GB RAM, 2TB NVMe swap, 8 CPUs
A single node typically handles up to 500 concurrent viewers for live events. You will want to scale out accordingly, using the replication pattern offered by the solution which uses RabbitMQ for transaction log shipping.
## Contributing
To start contributing, read the onboarding document at the following URL: [https://wiki.sapsailing.com/wiki/howto/onboarding](https://wiki.sapsailing.com/wiki/howto/onboarding). The project welcomes contributions in the form of pull requests, for example, enhancements of the Data Mining functionality, including any sailing-specific metric or dimension you may think of and that you find is still missing so far; or additional features for the race viewer; or a map visualization that does not require a Google Map but uses Open Street Map / Open Layers; landscape automation; improved start sequence analytics; major UI improvements for the administrative layer ("AdminConsole"), etc.
The issue tracker at [https://bugzilla.sapsailing.com](https://bugzilla.sapsailing.com) is currently used for any sort of issue and enhancement request tracking. Help to migrate this smoothly to Github Issues would be much appreciated, ideally keeping issue numbers stable due to many references to those Bugzilla bug numbers, be it in the source code, the Wiki, or the build infrastructure.
## Code of Conduct
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone. By participating in this project, you agree to abide by its [Code of Conduct](https://github.com/SAP/.github/blob/main/CODE_OF_CONDUCT.md) at all times.
## Licensing
Copyright 2024 SAP SE or an SAP affiliate company and sailing-analytics contributors. Please see our [LICENSE](LICENSE) for copyright and license information. Detailed information including third-party components and their licensing/copyright information is available [via the REUSE tool](https://api.reuse.software/info/github.com/SAP/sailing-analytics).
See [here](https://www.sapsailing.com/gwt/Home.html#/imprint/:) for a list of components used by the project, as well as their licenses, also to be found in the file ``java/com.sap.sailing.gwt.ui/imprint.json``.
## Building and Running
@@ -33,8 +69,17 @@ At [https://releases.sapsailing.com](https://releases.sapsailing.com) you find o
cd sailinganalytics
echo "MONGODB_URI=mongodb://localhost/winddb" | ${GIT_ROOT}/java/target/refreshInstance.sh auto-install-from-stdin
```
This will download and install the latest release and configure it such that it will connect to a MongoDB server running locally (``localhost``) and listening on the default port ``27017``, using the database called ``winddb``.
In addition to the necessary ``MONGODB_URI`` variable you may need to inject a few secrets into your runtime environment:
- ``MANAGE2SAIL_ACCESS_TOKEN`` access token for result and regatta structure import from the Manage2Sail regatta management system
- ``IGTIMI_CLIENT_ID`` / ``IGTIMI_CLIENT_SECRET`` credentials for ``igtimi.com`` in case you have one or more WindBot devices that you would like to integrate with
- ``GOOGLE_MAPS_AUTHENTICATION_PARAMS`` as in ``"key=..."`` or ``"client=..."``, required to display the Google Map in the race viewer. Obtain a Google Maps key from the Google Cloud Developer console, e.g., [here](https://console.cloud.google.com/apis/dashboard).
In the ``configuration/mail.properties`` file make the necessary adjustments in case you would like to enable the application to send out e-mails, e.g., for user notifications or invitations.
Launch the server from the directory to which you just installed it:
```
./start
@@ -51,6 +96,9 @@ To build a docker image, try ``docker/makeImageForLatestRelease``. The upload to
```
docker run -d -e "MEMORY=4g" -e "MONGODB_URI=mongodb://my.mongohost.org?replicaSet=rs0&retryWrites=true" -P <yourimage>
```
As explained above for the non-Docker scenario, add any variable assignments for secrets you need to pass to the runtime by adding more ``-e`` arguments.
Do a "docker ps" to figure out the port exposing the web application:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 79f6faf19b6a docker.sapsailing.com/sapsailing:latest "/home/sailing/serve…" 33 seconds ago Up 32 seconds 0.0.0.0:32782->6666/tcp, 0.0.0.0:32781->7091/tcp, 0.0.0.0:32780->8000/tcp, 0.0.0.0:32779->8888/tcp, 0.0.0.0:32778->14888/tcp modest_dhawan
+21 -8
View File
@@ -127,6 +127,7 @@ if [ $# -eq 0 ]; then
echo "buildAndUpdateProduct [-b -u -g -t -a -r -o -c -p -v -m <config> -n <package> -l <port> -x <gwt-workers> -j <test-package>] [build|install|all|hot-deploy|remote-deploy|local-deploy|release]"
echo ""
echo "-g Disable GWT compile, no gwt files will be generated, old ones will be preserved."
echo "-G Build forked GWT and gwt-maven-plugin locally instead of downloading Github release."
echo "-b Build GWT permutation only for one browser and English language."
echo "-t Disable tests"
echo "-a Disable mobile projects (RaceCommittee App, e.g., in case no AndroidSDK is installed)"
@@ -140,6 +141,7 @@ if [ $# -eq 0 ]; then
echo " com.sap.sailing.monitoring. Only works if there is a fully built server available."
echo " This parameter can also hold the name of the release if you are using the release command."
echo "-l <telnet port> Telnet port the OSGi server is running. Optional but enables fully automatic hot-deploy."
echo "-L in conjunction with the release sub-command, build the release only locally to dist/ and do not upload"
echo "-s <target server> Name of server you want to use as target for install, hot-deploy or remote-reploy. This overrides default behaviour."
echo "-w <ssh target> Target for remote-deploy and release. Must comply with the following format: user@server."
echo "-u Run without confirmation messages. Use with extreme care."
@@ -182,11 +184,12 @@ echo SERVERS_HOME is $SERVERS_HOME
echo BRANCH is $active_branch
echo VERSION is $VERSION_INFO
options=':bgtocpaArvm:n:l:s:w:x:j:u'
options=':bgtocpaArvmLG:n:l:s:w:x:j:u'
while getopts $options option
do
case $option in
g) gwtcompile=0;;
G) BUILD_GWT_FORK=1;;
t) testing=0;;
b) onegwtpermutationonly=1;;
o) offline=1;;
@@ -199,6 +202,7 @@ do
m) MAVEN_SETTINGS=$OPTARG;;
n) OSGI_BUNDLE_NAME=$OPTARG;;
l) OSGI_TELNET_PORT=$OPTARG;;
L) LOCAL_RELEASE_ONLY=1;;
s) TARGET_SERVER_NAME=$OPTARG
HAS_OVERWRITTEN_TARGET=1;;
w) REMOTE_SERVER_LOGIN=$OPTARG;;
@@ -358,12 +362,16 @@ INSTALL_FROM_RELEASE=$SIMPLE_VERSION_INFO
echo "Packaged release $PROJECT_HOME/dist/$SIMPLE_VERSION_INFO.tar.gz! I've put an env.sh that matches the current branch to $PROJECT_HOME/dist/$SIMPLE_VERSION_INFO/env.sh!"
echo "Checking the remote connection..."
REMOTE_HOME=`ssh $REMOTE_SERVER_LOGIN 'echo $HOME/releases'`
echo "Now uploading release to $REMOTE_SERVER_LOGIN:$REMOTE_HOME. Can take quite a while!"
if [ "${LOCAL_RELEASE_ONLY}" != "1" ]; then
echo "Checking the remote connection..."
REMOTE_HOME=`ssh $REMOTE_SERVER_LOGIN 'echo $HOME/releases'`
echo "Now uploading release to $REMOTE_SERVER_LOGIN:$REMOTE_HOME. Can take quite a while!"
`which scp` -r $PROJECT_HOME/dist/$SIMPLE_VERSION_INFO $REMOTE_SERVER_LOGIN:$REMOTE_HOME/
echo "Uploaded release to $REMOTE_HOME! Make sure to also put an updated env.sh if needed to the right place ($REMOTE_HOME/environment in most cases)"
`which scp` -r $PROJECT_HOME/dist/$SIMPLE_VERSION_INFO $REMOTE_SERVER_LOGIN:$REMOTE_HOME/
echo "Uploaded release to $REMOTE_HOME! Make sure to also put an updated env.sh if needed to the right place ($REMOTE_HOME/environment in most cases)"
else
echo "Release available at $PROJECT_HOME/dist/$SIMPLE_VERSION_INFO/, tarball at $PROJECT_HOME/dist/$SIMPLE_VERSION_INFO/$SIMPLE_VERSION_INFO.tar.gz"
fi
fi
if [[ "$@" == "local-deploy" ]]; then
@@ -748,8 +756,13 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then
extra="$extra -P with-not-android-relevant,!with-mobile"
if [ $gwtcompile -eq 1 ]; then
echo "Building and installing forked GWT version..."
JAVA_HOME="${JAVA8_HOME}" `dirname $0`/install-gwt "${PROJECT_HOME}"
if [ "${BUILD_GWT_FORK}" = "1" ]; then
echo "Building and installing forked GWT version..."
JAVA_HOME="${JAVA8_HOME}" `dirname $0`/install-gwt "${PROJECT_HOME}"
else
echo "Downloading and installing forked GWT version..."
`dirname $0`/install-gwt-from-fork-releases https://github.com/SAP/gwt-forward-serialization-rpc https://github.com/SAP/gwt-maven-plugin-forward-serialization-rpc 2.11.0 .
fi
fi
echo "Using following command: mvn $extra -DargLine=\"$APP_PARAMETERS\" -fae -s $MAVEN_SETTINGS $clean install"
echo "Maven version used: `mvn --version`"
+30
View File
@@ -0,0 +1,30 @@
#!/bin/bash
# Downloads releases of GWT and the gwt-maven-plugin and installs them to the local Maven repo at ~/.m2
# as well as copies the GWT JARs to the sailing Git workspace
# Usage: install-gwt-from-fork-releases {gwt-repo-URL} {gwt-maven-plugin-repo-URL} {gwt-version} {sailing-git-root}
# Example: install-gwt-from-fork-releases https://github.com/axeluhl/gwt https://github.com/axeluhl/gwt-maven-plugin 2.11.0 .
GWT_REPO_URL="${1}"
GWT_MAVEN_PLUG_REPO_URL="${2}"
GWT_VERSION="${3}"
SAILING_GIT_ROOT="$( cd ${4}; pwd )"
GWT="`mktemp -t -d gwt.XXXXX`"
cd "${GWT}"
echo "GWT directory: ${GWT}"
curl -L "${GWT_REPO_URL}/releases/download/gwt-${GWT_VERSION}/gwt-${GWT_VERSION}.zip" -o "gwt-${GWT_VERSION}.zip"
curl -L "${GWT_MAVEN_PLUG_REPO_URL=}/releases/download/gwt-${GWT_VERSION}/gwt-maven-plugin-${GWT_VERSION}.jar" -o "gwt-maven-plugin-${GWT_VERSION}.jar"
curl -L "${GWT_MAVEN_PLUG_REPO_URL=}/releases/download/gwt-${GWT_VERSION}/gwt-maven-plugin-${GWT_VERSION}.pom" -o "gwt-maven-plugin-${GWT_VERSION}.pom"
unzip gwt-${GWT_VERSION}.zip
cd gwt-${GWT_VERSION}
cp gwt-dev.jar ${SAILING_GIT_ROOT}/java/com.google.gwt.dev/lib/gwt-dev.jar
cp gwt-user.jar ${SAILING_GIT_ROOT}/java/com.google.gwt.user/lib/gwt-user.jar
cp gwt-servlet.jar ${SAILING_GIT_ROOT}/java/com.google.gwt.servlet/lib/gwt-servlet.jar
cp gwt-servlet-deps.jar ${SAILING_GIT_ROOT}/java/com.google.gwt.servlet/lib/gwt-servlet-deps.jar
for i in dev user servlet; do
mvn --batch-mode install:install-file -Dfile=gwt-${i}.jar -DpomFile="${SAILING_GIT_ROOT}/configuration/gwt-poms/gwt-$i-${GWT_VERSION}.pom"
done
mvn --batch-mode install:install-file -Dpackaging=pom -Dfile="${SAILING_GIT_ROOT}/configuration/gwt-poms/gwt-${GWT_VERSION}.pom" -DpomFile="${SAILING_GIT_ROOT}/configuration/gwt-poms/gwt-${GWT_VERSION}.pom"
mvn --batch-mode install:install-file -Dpackaging=pom -Dfile="${SAILING_GIT_ROOT}/configuration/gwt-poms/requestfactory-${GWT_VERSION}.pom" -DpomFile="${SAILING_GIT_ROOT}/configuration/gwt-poms/requestfactory-${GWT_VERSION}.pom"
# gwt-maven-plugin:
cd ..
mvn --batch-mode install:install-file -Dfile="gwt-maven-plugin-${GWT_VERSION}.jar" -DpomFile="gwt-maven-plugin-${GWT_VERSION}.pom"
rm -rf "${GWT}"
+2
View File
@@ -513,6 +513,7 @@ https://event.tractrac.com/events/event_20230531_ERERFXNACR/jsonservice.php
https://event.tractrac.com/events/event_20230611_KielerWoch/jsonservice.php
https://event.tractrac.com/events/event_20230622_KielerWoch/jsonservice.php
https://event.tractrac.com/events/event_20240312_TrofeoPrin/jsonservice.php
https://event.tractrac.com/events/event_20240411_SemaineOly/jsonservice.php
http://skitrac.traclive.dk/events/event_20140821_ESSCardiff/jsonservice.php
http://skitrac.traclive.dk/events/event_20140909_ESSIstanbu/jsonservice.php
http://skitrac.traclive.dk/events/event_20141001_ESSNice/jsonservice.php
@@ -533,6 +534,7 @@ http://skitrac.traclive.dk/events/event_20160727_ESSHamburg/jsonservice.php
http://skitrac.traclive.dk/events/event_20160921_ESSInstanb/jsonservice.php
http://skitrac.traclive.dk/events/event_20161005_ESSLisbon/jsonservice.php
https://paris1.tractrac.com/events/event_20240312_TrofeoPrin/jsonservice.php
https://paris1.tractrac.com/events/event_20240411_SemaineOly/jsonservice.php
http://traclive.dk/events/event_20120905_erEuropean/jsonservice.php
http://traclive.dk/events/event_20130302_ESSMuscat/jsonservice.php
http://traclive.dk/events/event_20130401_STGTrainin/jsonservice.php
+2 -2
View File
@@ -1,4 +1,4 @@
FROM docker.sapsailing.com/sapjvm8:8.1.097
FROM docker.sapsailing.com/sapjvm8:8.1.098
ARG RELEASE
LABEL maintainer=axel.uhl@sap.com
# Download and extract the release
@@ -9,7 +9,7 @@ COPY vimrc /root/.vimrc
RUN wget -O /tmp/rds.pem https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem \
&& /opt/sapjvm_8/bin/keytool -importcert -alias AWSRDS -file /tmp/rds.pem -keystore /opt/sapjvm_8/jre/lib/security/cacerts -noprompt -storepass changeit \
&& rm /tmp/rds.pem
RUN wget -O /tmp/${RELEASE}.tar.gz http://releases.sapsailing.com/${RELEASE}/${RELEASE}.tar.gz \
RUN wget -O /tmp/${RELEASE}.tar.gz https://releases.sapsailing.com/${RELEASE}/${RELEASE}.tar.gz \
&& tar xzvpf /tmp/${RELEASE}.tar.gz \
&& rm /tmp/${RELEASE}.tar.gz
COPY env.sh .
+2 -2
View File
@@ -1,5 +1,5 @@
FROM buildpack-deps:bullseye
ARG SAPJVM_VERSION=8.1.097
ARG SAPJVM_VERSION=8.1.098
LABEL maintainer=axel.uhl@sap.com
# Download and extract the SAP JVM 8
ENV PATH=${PATH}:/opt/sapjvm_8/bin
@@ -8,7 +8,7 @@ WORKDIR /opt
RUN apt-get update \
&& apt-get install -y wget apt-utils unzip \
&& apt-get -y upgrade \
&& curl --cookie eula_3_1_agreed=tools.hana.ondemand.com/developer-license-3_1.txt "https://tools.hana.ondemand.com/additional/sapjvm-${SAPJVM_VERSION}-linux-x64.zip" --output sapjvm8-linux-x64.zip \
&& curl --cookie eula_3_2_agreed=tools.hana.ondemand.com/developer-license-3_2.txt "https://tools.hana.ondemand.com/additional/sapjvm-${SAPJVM_VERSION}-linux-x64.zip" --output sapjvm8-linux-x64.zip \
&& unzip sapjvm8-linux-x64.zip \
&& rm sapjvm8-linux-x64.zip \
&& echo "export JAVA_HOME=/opt/sapjvm_8; export PATH=\${PATH}:/opt/sapjvm_8/bin" > /etc/profile.d/javahome.sh
+1 -1
View File
@@ -1,4 +1,4 @@
ARG SAPJVM_VERSION=8.1.097
ARG SAPJVM_VERSION=8.1.098
FROM docker.sapsailing.com/sapjvm8:${SAPJVM_VERSION}
LABEL maintainer=axel.uhl@sap.com
# Download and extract the release
+2 -2
View File
@@ -2,7 +2,7 @@
release=$1
if [ "${release}" = "" ]; then
SET_LATEST=1
release=$(wget -O - http://releases.sapsailing.com/ 2>/dev/null | grep 'build-[0-9]\{10\}' | tail -1 | sed -e 's/^.*\(build-[0-9]*\).*$/\1/')
release=$(wget -O - https://releases.sapsailing.com/ 2>/dev/null | grep 'build-[0-9]\{10\}' | tail -1 | sed -e 's/^.*\(build-[0-9]*\).*$/\1/')
echo Latest release is ${release}
fi
GITROOT="`dirname $0`/.."
@@ -15,7 +15,7 @@ cp "$GITROOT/java/target/configuration/JavaSE-11.profile" "$DOCKERDIR"
cd "$DOCKERDIR"
docker build --build-arg RELEASE=${release} -t sapsailing:${release} .
echo "Cleaning up..."
rm start env.sh JavaSE-11.profile Dockerfile
rm start env.sh JavaSE-11.profile
docker tag sapsailing:${release} docker.sapsailing.com/sapsailing:${release}
docker push docker.sapsailing.com/sapsailing:${release}
if [ "$SET_LATEST" = "1" ]; then
@@ -101,7 +101,19 @@ public class SecuredDomainType extends HasPermissionsImpl {
"SWISS_TIMING_ARCHIVE_ACCOUNT");
public static final HasPermissions TRACTRAC_ACCOUNT = new SecuredDomainType("TRACTRAC_ACCOUNT");
public static final HasPermissions YELLOWBRICK_ACCOUNT = new SecuredDomainType("YELLOWBRICK_ACCOUNT");
/**
* The type-relative object identifier is expected to name the "SERVER" object to which the request to read
* or update the wind estimation models is sent.
*/
public static final HasPermissions WIND_ESTIMATION_MODELS = new SecuredDomainType("WIND_ESTIMATION_MODELS");
/**
* The type-relative object identifier is expected to name the "SERVER" object to which the request to read
* the polar data is sent.
*/
public static final HasPermissions POLAR_DATA = new SecuredDomainType("POLAR_DATA");
public static final HasPermissions MARK_PROPERTIES = new SecuredDomainType("MARK_PROPERTIES");
public static final HasPermissions MARK_TEMPLATE = new SecuredDomainType("MARK_TEMPLATE");
public static final HasPermissions COURSE_TEMPLATE = new SecuredDomainType("COURSE_TEMPLATE");
@@ -37,7 +37,8 @@ Require-Bundle: com.sap.sailing.domain,
org.apache.shiro.core;bundle-version="1.2.2",
org.hamcrest;bundle-version="2.2.0",
net.bytebuddy.byte-buddy;bundle-version="1.12.18",
net.bytebuddy.byte-buddy-agent;bundle-version="1.12.18"
net.bytebuddy.byte-buddy-agent;bundle-version="1.12.18",
com.sap.sse.operationaltransformation
Export-Package: com.sap.sailing.domain.test,
com.sap.sailing.domain.test.mock
Import-Package: org.apache.commons.math;version="2.1.0",
@@ -0,0 +1,14 @@
package com.sap.sailing.domain.test.tractrac;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class PasswordSuppressionTest {
@Test
public void testPasswordSuppression() {
assertEquals("https://em.paris1.tractrac.com/update_race_status?eventid=cbdd7370-daea-013c-d54d-342e996a9920&raceid=a90b8e50-e24a-013c-39f7-0eeb2fba6aa7&username=john.doe%40example.com&password=****&race_status=ABORTED",
"https://em.paris1.tractrac.com/update_race_status?eventid=cbdd7370-daea-013c-d54d-342e996a9920&raceid=a90b8e50-e24a-013c-39f7-0eeb2fba6aa7&username=john.doe%40example.com&password=Humba&race_status=ABORTED"
.replaceAll("password=([^&]*)&", "password=****&"));
}
}
@@ -13,6 +13,7 @@ import java.util.UUID;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentMatchers;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
@@ -23,26 +24,39 @@ import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.AbortingFlagFinder;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogFlagEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogPassChangeEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartTimeEventImpl;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.impl.BoatClassImpl;
import com.sap.sailing.domain.base.impl.BoatImpl;
import com.sap.sailing.domain.base.impl.CourseAreaImpl;
import com.sap.sailing.domain.base.impl.DynamicBoat;
import com.sap.sailing.domain.base.impl.NationalityImpl;
import com.sap.sailing.domain.base.impl.PersonImpl;
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
import com.sap.sailing.domain.common.LeaderboardNameConstants;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.MeterDistance;
import com.sap.sailing.domain.common.racelog.Flags;
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl;
import com.sap.sailing.domain.racelog.RaceLogAndTrackedRaceResolver;
import com.sap.sailing.domain.tractracadapter.DomainFactory;
import com.sap.sailing.domain.tractracadapter.impl.RaceAndCompetitorStatusWithRaceLogReconciler;
import com.sap.sailing.server.impl.RaceLogScoringReplicator;
import com.sap.sailing.server.interfaces.RacingEventService;
import com.sap.sailing.server.interfaces.RacingEventServiceOperation;
import com.sap.sse.common.Color;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.metering.CPUMeter;
import com.tractrac.model.lib.api.event.ICompetitor;
import com.tractrac.model.lib.api.event.IRace;
import com.tractrac.model.lib.api.event.IRaceCompetitor;
@@ -56,6 +70,8 @@ import com.tractrac.model.lib.api.event.RaceStatusType;
*
*/
public class TestTracTracRaceAndCompetitorStatusReconciler {
private static final String TEST_LEADERBOARD_NAME = "test";
private static final String R1 = "R1";
private AbstractLogEventAuthor author;
private TrackedRace trackedRace;
private IRace tractracRace;
@@ -65,7 +81,7 @@ public class TestTracTracRaceAndCompetitorStatusReconciler {
private IRaceCompetitor tractracRaceCompetitor;
private ICompetitor tractracCompetitor;
private Competitor competitor;
private FlexibleLeaderboard leaderboard;
private static class RaceAndCompetitorStatusWithRaceLogReconcilerWithPublicResultFetcher extends RaceAndCompetitorStatusWithRaceLogReconciler {
public RaceAndCompetitorStatusWithRaceLogReconcilerWithPublicResultFetcher(DomainFactory domainFactory,
RaceLogResolver raceLogResolver, IRace tractracRace) {
@@ -112,7 +128,15 @@ public class TestTracTracRaceAndCompetitorStatusReconciler {
/* dateOfBirth */null, "This is Rigo, the coach")),
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null, b, /* store */ false);
when(tractracCompetitor.getId()).thenReturn((UUID) competitor.getId());
raceLog = new RaceLogImpl("RaceLogID");
final RaceDefinition raceDefinition = mock(RaceDefinitionImpl.class);
when(raceDefinition.getCompetitors()).thenReturn(Collections.singleton(competitor));
when(trackedRace.getRace()).thenReturn(raceDefinition);
final TrackedRegatta trackedRegatta = mock(TrackedRegatta.class);
when(trackedRegatta.getCPUMeter()).thenReturn(CPUMeter.create());
when(trackedRace.getTrackedRegatta()).thenReturn(trackedRegatta);
leaderboard = new FlexibleLeaderboardImpl(TEST_LEADERBOARD_NAME, new ThresholdBasedResultDiscardingRuleImpl(new int[0]), new LowPoint(), new CourseAreaImpl("area A", new UUID(1200, 1200) , new DegreePosition(100, 100), new MeterDistance(100)));
leaderboard.addRace(trackedRace, R1, /* medalRace */ false);
raceLog = leaderboard.getRacelog(R1, LeaderboardNameConstants.DEFAULT_FLEET_NAME);
when(trackedRace.getAttachedRaceLogs()).thenReturn(Collections.singleton(raceLog));
reconciler = new RaceAndCompetitorStatusWithRaceLogReconcilerWithPublicResultFetcher(DomainFactory.INSTANCE, new RaceLogResolver() {
@Override
@@ -120,6 +144,16 @@ public class TestTracTracRaceAndCompetitorStatusReconciler {
return raceLog;
}
}, tractracRace);
final RacingEventService racingEventService = mock(RacingEventService.class);
when(racingEventService.getLeaderboardByName(TEST_LEADERBOARD_NAME)).thenReturn(leaderboard);
when(racingEventService.getBaseDomainFactory()).thenReturn(com.sap.sailing.domain.base.DomainFactory.INSTANCE);
when(racingEventService.apply(ArgumentMatchers.any(RacingEventServiceOperation.class))).thenAnswer(
invocation -> {
final RacingEventServiceOperation<?> operation = invocation.getArgument(0);
return operation.applyTo(racingEventService);
});
final RaceLogScoringReplicator raceLogScoringReplicator = new RaceLogScoringReplicator(racingEventService);
leaderboard.getRaceColumnByName(R1).addRaceColumnListener(raceLogScoringReplicator);
raceLog.add(new RaceLogPassChangeEventImpl(startOfPass, author, /* pPassId */ 1));
}
@@ -344,7 +378,36 @@ public class TestTracTracRaceAndCompetitorStatusReconciler {
assertEquals(yetNewerResultTimePoint, raceLogBasedResult.getB());
assertEquals(MaxPointsReason.NONE, raceLogBasedResult.getA().getMaxPointsReason());
assertEquals(0, raceLogBasedResult.getA().getOneBasedRank());
}
}
@Test
public void testOfficialNullFinishTimeAndZeroRank() {
final TimePoint resultTimePoint = startOfPass.plus(Duration.ONE_SECOND.times(1));
when(tractracRaceCompetitor.getStatus()).thenReturn(RaceCompetitorStatusType.NO_DATA);
when(tractracRaceCompetitor.getStatusLastChangedTime()).thenReturn(resultTimePoint.asMillis());
when(tractracRaceCompetitor.getOfficialRank()).thenReturn(0);
when(trackedRace.getFinishingTime()).thenReturn(null);
reconciler.reconcileCompetitorStatus(tractracRaceCompetitor, trackedRace);
{
// assert scorecorrection msg afterwards is unchanged.
assertNull(leaderboard.getScoreCorrection().getComment());
assertNull(leaderboard.getScoreCorrection().getTimePointOfLastCorrectionsValidity());
}
}
@Test
public void testOfficialFinishTimeAndValidRankUpdateScoreCorrectionMetadata() {
final TimePoint resultTimePoint = startOfPass.plus(Duration.ONE_SECOND.times(1));
when(tractracRaceCompetitor.getStatus()).thenReturn(RaceCompetitorStatusType.FINISH_CONFIRMED);
when(tractracRaceCompetitor.getStatusLastChangedTime()).thenReturn(resultTimePoint.asMillis());
when(tractracRaceCompetitor.getOfficialRank()).thenReturn(4);
when(trackedRace.getFinishingTime()).thenReturn(null);
reconciler.reconcileCompetitorStatus(tractracRaceCompetitor, trackedRace);
{
// assert scorecorrection msg afterwards is unchanged.
assertEquals("Results of race "+R1+" have been updated.", leaderboard.getScoreCorrection().getComment());
assertNotNull(leaderboard.getScoreCorrection().getTimePointOfLastCorrectionsValidity());
}
}
}
@@ -356,16 +356,7 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl<RaceTrackin
reconciler = null;
}
racesListener = new IRacesListener() {
@Override public void abandonRace(long timestamp, UUID raceId) {
if (raceId.equals(tractracRace.getId())) {
try {
onStop(/* stopReceiversPreemtively */ false, /* willBeRemoved */ false);
} catch (InterruptedException e) {
logger.log(Level.WARNING, "Problem when receiving abandonRace("+raceId+") for race "+tractracRace+
" in event "+tractracEvent+" while trying to stop the listeners", e);
}
}
}
@Override public void abandonRace(long timestamp, UUID raceId) {}
@Override public void addRace(long timestamp, IRace race) {}
@Override public void deleteRace(long timestamp, UUID raceId) {}
@Override public void reloadRace(long timestamp, UUID raceId) {
@@ -197,11 +197,11 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
@Override
public void reloadRaceLog(Fleet fleet) {
// FIXME bug3286: newOrLoadedRaceLog will have MongoRaceLogStoreListener attached; raceLogAvailable, result of de-serialization, will not; merging newOrLoadedRaceLog into raceLogAvailable will leave resulting log without persistence
RaceLogIdentifier identifier = getRaceLogIdentifier(fleet);
RaceLog newOrLoadedRaceLog = raceLogStore.getRaceLog(identifier, /* ignoreCache */true);
RaceLog raceLogAvailable = raceLogs.get(fleet);
final RaceLogIdentifier identifier = getRaceLogIdentifier(fleet);
final RaceLog newOrLoadedRaceLog = raceLogStore.getRaceLog(identifier, /* ignoreCache */true);
final RaceLog raceLogAvailable = raceLogs.get(fleet);
if (raceLogAvailable == null) {
RaceColumnRaceLogReplicator listener = new RaceColumnRaceLogReplicator(this, identifier);
final RaceColumnRaceLogReplicator listener = new RaceColumnRaceLogReplicator(this, identifier);
// FIXME Wouldn't this skip any listener notifications that a merge below would trigger if the race log already existed?
// FIXME For example, how about the race log-provided score corrections that need application to the leaderboard and replication?
newOrLoadedRaceLog.addListener(listener);
@@ -1,7 +1,17 @@
package com.sap.sailing.domain.leaderboard.impl;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.common.ScoringSchemeType;
/**
* The default score of all columns, including medal race columns, is defined as 1.0 for this
* scoring scheme. This way, the medal series races for quarter-final, semi-final and grand
* final do not need explicit column factors of 1.0 when (as is usual for this format) no
* doubling of these race scores is desired.
*
* @author Axel Uhl (d043530)
*
*/
public class LowPointWithEliminatingMedalSeriesPromotingOneToFinalAndTwoToSemifinal
extends LowPointWithEliminatingMedalSeriesWithPromotions {
private static final long serialVersionUID = -6753499035563730886L;
@@ -14,4 +24,14 @@ public class LowPointWithEliminatingMedalSeriesPromotingOneToFinalAndTwoToSemifi
public ScoringSchemeType getType() {
return ScoringSchemeType.LOW_POINT_WITH_ELIMINATING_MEDAL_SERIES_PROMOTING_ONE_TO_FINAL_AND_TWO_TO_SEMIFINAL;
}
@Override
public double getScoreFactor(RaceColumn raceColumn) {
Double factor = raceColumn.getExplicitFactor();
if (factor == null) {
factor = 1.0;
}
return factor;
}
}
@@ -48,7 +48,7 @@ public class CourseDesignUpdateHandler extends UpdateHandler implements CourseDe
JSONObject serializedCourseDesign = courseSerializer.serialize(newCourseDesignWithExistingControlPoints);
String payload = serializedCourseDesign.toJSONString();
URL currentCourseDesignURL = buildUpdateURL();
logger.info("Using " + currentCourseDesignURL.toString() + " for the course update!");
logger.info("Using " + eraseSecurityRelatedValuesFromURL(currentCourseDesignURL.toString()) + " for the course update!");
logger.info("Payload is " + payload);
HttpURLConnection connection = (HttpURLConnection) currentCourseDesignURL.openConnection();
try {
@@ -62,7 +62,8 @@ public class CourseDesignUpdateHandler extends UpdateHandler implements CourseDe
if (connection != null) {
connection.disconnect();
} else {
logger.severe("Connection to TracTrac Course Update URL " + currentCourseDesignURL.toString() + " could not be established");
logger.severe("Connection to TracTrac Course Update URL " +
eraseSecurityRelatedValuesFromURL(currentCourseDesignURL.toString()) + " could not be established");
}
}
}
@@ -265,7 +265,12 @@ public class DynamicGPSFixMovingTrackImpl<ItemType> extends GPSFixTrackImpl<Item
numberOfOutliersDueToCOGDiff++;
logger.finer(()->""+DynamicGPSFixMovingTrackImpl.this+": computed COG "+speedToNeighbor.getBearing()+" differs significantly (by "+
speedToNeighbor.getBearing().getDifferenceTo(takeCogAndSogFrom.getSpeed().getBearing()).abs()+
") from reported COG "+takeCogAndSogFrom.getSpeed().getBearing());
") from reported COG "+takeCogAndSogFrom.getSpeed().getBearing()+
"; time points: "+from.getTimePoint()+" / "+to.getTimePoint());
} else if (!foundValidPreviousFixInRange) {
logger.finer(()->""+DynamicGPSFixMovingTrackImpl.this+": invalid fix "+to+" due to smoothened speed ratio "+
getSmoothenedSpeedRatio(speedToNeighbor, takeCogAndSogFrom.getSpeed())+
" greater or equal threshold "+MAX_SPEED_FACTOR_COMPARED_TO_MEASURED_SPEED_FOR_FILTERING);
}
numberOfFixesCheckedForOutlier++;
return foundValidPreviousFixInRange;
@@ -63,7 +63,7 @@ public class FinishTimeUpdateHandler extends UpdateHandler {
final CloseableHttpClient client = HttpClientBuilder.create()
.setRedirectStrategy(new LaxRedirectStrategyForAllRedirectResponseCodes())
.build();
logger.info("Using " + stopTrackingURI.toString() + " to stop tracking");
logger.info("Using " + eraseSecurityRelatedValuesFromURL(stopTrackingURI.toString()) + " to stop tracking");
final HttpResponse response = client.execute(request);
try {
parseAndLogResponse(new BufferedReader(new InputStreamReader(response.getEntity().getContent(),
@@ -40,7 +40,7 @@ public class RaceAbortedHandler extends UpdateHandler implements RaceAbortedList
Map<String, String> additionalArgs = new HashMap<>();
additionalArgs.put("race_status", raceStatus);
URL raceAbortedURL = buildUpdateURL(additionalArgs);
logger.info("Using " + raceAbortedURL.toString() + " for the race aborted notification!");
logger.info("Using " + eraseSecurityRelatedValuesFromURL(raceAbortedURL.toString()) + " for the race aborted notification!");
HttpURLConnection connection = (HttpURLConnection) raceAbortedURL.openConnection();
try {
connection = setConnectionProperties(connection);
@@ -53,7 +53,8 @@ public class RaceAbortedHandler extends UpdateHandler implements RaceAbortedList
if (connection != null) {
connection.disconnect();
} else {
logger.severe("Connection to TracTrac race aborted URL " + raceAbortedURL.toString() + " could not be established");
logger.severe("Connection to TracTrac race aborted URL " +
eraseSecurityRelatedValuesFromURL(raceAbortedURL.toString()) + " could not be established");
}
}
}
@@ -29,7 +29,7 @@ public class StartTimeResetHandler extends UpdateHandler implements StartTimeCha
return;
}
URL startTimeUpdateURL = buildUpdateURL();
logger.info("Using " + startTimeUpdateURL.toString() + " for the start reset!");
logger.info("Using " + eraseSecurityRelatedValuesFromURL(startTimeUpdateURL.toString()) + " for the start reset!");
HttpURLConnection connection = (HttpURLConnection) startTimeUpdateURL.openConnection();
try {
connection = setConnectionProperties(connection);
@@ -42,7 +42,8 @@ public class StartTimeResetHandler extends UpdateHandler implements StartTimeCha
if (connection != null) {
connection.disconnect();
} else {
logger.severe("Connection to TracTrac start time reset URL " + startTimeUpdateURL.toString() + " could not be established");
logger.severe("Connection to TracTrac start time reset URL " +
eraseSecurityRelatedValuesFromURL(startTimeUpdateURL.toString()) + " could not be established");
}
}
}
@@ -68,7 +68,7 @@ public class StartTimeUpdateHandler extends UpdateHandler implements StartTimeCh
additionalParameters.put(FIELD_RACE_START_TIME, String.valueOf(newStartTime.asMillis()));
URL startTimeUpdateURL = buildUpdateURL(additionalParameters);
logger.info("Using " + startTimeUpdateURL.toString() + " for the start time update!");
logger.info("Using " + eraseSecurityRelatedValuesFromURL(startTimeUpdateURL.toString()) + " for the start time update!");
HttpURLConnection connection = (HttpURLConnection) startTimeUpdateURL.openConnection();
try {
connection = setConnectionProperties(connection);
@@ -81,7 +81,8 @@ public class StartTimeUpdateHandler extends UpdateHandler implements StartTimeCh
if (connection != null) {
connection.disconnect();
} else {
logger.severe("Connection to TracTrac Course Update URL " + startTimeUpdateURL.toString() + " could not be established");
logger.severe("Connection to TracTrac Course Update URL " +
eraseSecurityRelatedValuesFromURL(startTimeUpdateURL.toString()) + " could not be established");
}
}
if (regatta.isControlTrackingFromStartAndFinishTimes()) {
@@ -96,7 +97,7 @@ public class StartTimeUpdateHandler extends UpdateHandler implements StartTimeCh
final HttpClient client = HttpClientBuilder.create()
.setRedirectStrategy(new LaxRedirectStrategyForAllRedirectResponseCodes())
.build();
logger.info("Using " + startTrackingURI.toString() + " to start tracking");
logger.info("Using " + eraseSecurityRelatedValuesFromURL(startTrackingURI.toString()) + " to start tracking");
final HttpResponse response = client.execute(request);
try {
parseAndLogResponse(new BufferedReader(new InputStreamReader(response.getEntity().getContent(),
@@ -91,6 +91,10 @@ public class UpdateHandler {
return new URI(baseURI.getScheme(), baseURI.getHost(), baseURI.getPath()+(baseURI.getPath().endsWith("/")?"":"/")+action, baseURI.getFragment());
}
protected String eraseSecurityRelatedValuesFromURL(String url) {
return url.replaceAll("password=([^&]*)&", "password=****&");
}
/**
* @return a new list that the caller may extend to add more parameters; the list returned contains the basic
* parameters {@code eventid}, {@code raceid}, {@code username} and {@code password}.
@@ -48,6 +48,7 @@ import com.sap.sailing.gwt.ui.client.SailingServiceWriteAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
import com.sap.sse.common.Util.Triple;
import com.sap.sse.common.fileupload.FileUploadUtil;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.IconResources;
import com.sap.sse.gwt.client.Notification;
@@ -58,7 +59,6 @@ import com.sap.sse.gwt.client.controls.busyindicator.BusyIndicator;
import com.sap.sse.gwt.client.controls.busyindicator.SimpleBusyIndicator;
import com.sap.sse.gwt.client.controls.listedit.StringListEditorComposite;
import com.sap.sse.gwt.client.dialog.DialogUtils;
import com.sap.sse.gwt.client.fileupload.FileUploadUtil;
import com.sap.sse.security.shared.HasPermissions.DefaultActions;
import com.sap.sse.security.shared.dto.SecuredDTO;
import com.sap.sse.security.ui.client.UserService;
@@ -255,9 +255,9 @@ public abstract class AbstractBoatCertificatesPanel extends SimplePanel {
private void formSubmitComplete(SubmitCompleteEvent e) {
try {
final JSONObject json = (JSONObject) JSONParser.parseStrict(FileUploadUtil.getApplicationJsonContent(e));
final JSONObject json = (JSONObject) JSONParser.parseStrict(FileUploadUtil.getApplicationJsonContentFromHtml(e.getResults()));
if (json.get(ORCCertificateUploadConstants.CERTIFICATES) != null) {
sailingServiceWrite.getORCCertificates(e.getResults(), new AsyncCallback<Collection<ORCCertificate>>() {
sailingServiceWrite.getORCCertificates(json.toString(), new AsyncCallback<Collection<ORCCertificate>>() {
@Override
public void onFailure(Throwable caught) {
busyIndicator.setBusy(false);
@@ -23,10 +23,10 @@ import com.sap.sailing.gwt.ui.adminconsole.resulthandling.SensorDataImportResult
import com.sap.sailing.gwt.ui.client.SailingServiceWriteAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
import com.sap.sse.common.fileupload.FileUploadUtil;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.Notification;
import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.client.fileupload.FileUploadUtil;
public abstract class AbstractFileImportWidget extends Composite {
@@ -89,7 +89,7 @@ public abstract class AbstractFileImportWidget extends Composite {
@UiHandler("formPanelUi")
void onFileImportComplete(SubmitCompleteEvent event) {
SensorDataImportResponse importResponse = SensorDataImportResponse.parse(FileUploadUtil.getApplicationJsonContent(event));
SensorDataImportResponse importResponse = SensorDataImportResponse.parse(FileUploadUtil.getApplicationJsonContentFromHtml(event.getResults()));
if (importResponse == null) {
Notification.notify(StringMessages.INSTANCE.unexpectedErrorDuringFileImport(), NotificationType.ERROR);
} else {
@@ -33,11 +33,11 @@ import com.sap.sailing.gwt.ui.adminconsole.resulthandling.ExpeditionDataImportRe
import com.sap.sailing.gwt.ui.client.Displayer;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
import com.sap.sse.common.fileupload.FileUploadUtil;
import com.sap.sse.gwt.client.Notification;
import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.client.controls.busyindicator.BusyIndicator;
import com.sap.sse.gwt.client.controls.busyindicator.SimpleBusyIndicator;
import com.sap.sse.gwt.client.fileupload.FileUploadUtil;
/**
* The UI form to upload data for expedition all in one import.
@@ -150,7 +150,7 @@ public class ExpeditionAllInOneImportPanel extends Composite {
formPanel.addSubmitCompleteHandler(event -> {
validation.run();
busyIndicator.setBusy(false);
final ExpeditionDataImportResponse response = ExpeditionDataImportResponse.parse(FileUploadUtil.getApplicationJsonContent(event));
final ExpeditionDataImportResponse response = ExpeditionDataImportResponse.parse(FileUploadUtil.getApplicationJsonContentFromHtml(event.getResults()));
if (response == null) {
Notification.notify(StringMessages.INSTANCE.unexpectedErrorDuringFileImport(), NotificationType.ERROR);
} else if (response.hasEventId()) {
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.ui.adminconsole;
import java.util.Collection;
import java.util.List;
import com.google.gwt.user.client.ui.FocusWidget;
import com.sap.sailing.domain.common.ScoringSchemeType;
import com.sap.sailing.domain.common.dto.CourseAreaDTO;
import com.sap.sailing.gwt.ui.client.StringMessages;
@@ -47,4 +48,9 @@ public class FlexibleLeaderboardEditDialog extends FlexibleLeaderboardDialog {
}
discardThresholdBoxes = new DiscardThresholdBoxes(this, leaderboard.getDiscardThresholds(), stringMessages);
}
@Override
protected FocusWidget getInitialFocusWidget() {
return displayNameTextBox;
}
}
@@ -2,6 +2,7 @@ package com.sap.sailing.gwt.ui.adminconsole;
import java.util.Collection;
import com.google.gwt.user.client.ui.FocusWidget;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
@@ -22,4 +23,9 @@ public class RegattaLeaderboardEditDialog<LD extends LeaderboardDescriptor> exte
} // else, the regatta leaderboard obtains its result discarding rule implicitly from the underlying regatta
adjustVisibilityOfResultDiscardingRuleComponent();
}
@Override
protected FocusWidget getInitialFocusWidget() {
return displayNameTextBox;
}
}
@@ -69,13 +69,13 @@ import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
import com.sap.sailing.gwt.ui.shared.WindTrackInfoDTO;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.fileupload.FileUploadUtil;
import com.sap.sse.gwt.adminconsole.AdminConsoleTableResources;
import com.sap.sse.gwt.adminconsole.FilterablePanelProvider;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.celltable.BaseCelltable;
import com.sap.sse.gwt.client.celltable.RefreshableMultiSelectionModel;
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
import com.sap.sse.gwt.client.fileupload.FileUploadUtil;
import com.sap.sse.gwt.client.panels.AbstractFilterablePanel;
import com.sap.sse.security.shared.dto.UserDTO;
import com.sap.sse.security.ui.client.UserService;
@@ -477,7 +477,7 @@ public class WindPanel extends FormPanel implements FilterablePanelProvider<Race
form.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() {
public void onSubmitComplete(SubmitCompleteEvent event) {
importResultPanel.clear();
String windImportResultJson = FileUploadUtil.getApplicationJsonContent(event);
String windImportResultJson = FileUploadUtil.getApplicationJsonContentFromHtml(event.getResults());
try {
WindImportResult windImportResult = WindImportResult.fromJson(windImportResultJson);
JsArray<RaceEntry> raceEntries = windImportResult.getRaceEntries();
@@ -41,12 +41,12 @@ import com.google.gwt.user.client.ui.VerticalPanel;
import com.sap.sailing.gwt.home.shared.SharedHomeResources;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.common.fileupload.FileUploadConstants;
import com.sap.sse.common.fileupload.FileUploadUtil;
import com.sap.sse.common.media.MediaTagConstants;
import com.sap.sse.common.media.MediaType;
import com.sap.sse.common.media.MimeType;
import com.sap.sse.gwt.client.Notification;
import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.client.fileupload.FileUploadUtil;
import com.sap.sse.gwt.client.media.ImageDTO;
import com.sap.sse.gwt.client.media.VideoDTO;
import com.sap.sse.gwt.client.panels.HorizontalFlowPanel;
@@ -288,7 +288,7 @@ public abstract class AbstractMediaUploadPopup extends DialogBox {
// we can get the result text here (see the FormPanel documentation for
// further explanation).
progressOverlay.setVisible(false);
JSONValue resultJsonValue = JSONParser.parseStrict(FileUploadUtil.getApplicationJsonContent(event));
JSONValue resultJsonValue = JSONParser.parseStrict(FileUploadUtil.getApplicationJsonContentFromHtml(event.getResults()));
JSONArray resultJson = resultJsonValue.isArray();
boolean uploadSuccessful = false;
boolean fileSkipped = false;
@@ -4,6 +4,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;
import org.json.simple.parser.ParseException;
@@ -16,7 +17,7 @@ public class PolarDataClientMock extends PolarDataClient {
private final File file;
public PolarDataClientMock(File file, ReplicablePolarService polarService, DomainFactory domainFactory) {
super(null, polarService);
super(null, polarService, Optional.empty());
polarService.registerDomainFactory(domainFactory);
this.file = file;
}
@@ -29,13 +29,15 @@ Require-Bundle:
com.sap.sse.operationaltransformation,
com.sap.sse.security,
com.sun.jersey,
org.apache.geronimo.specs.geronimo-jta_1.1_spec; bundle-version="1.1.1",
org.apache.geronimo.specs.geronimo-jta_1.1_spec;bundle-version="1.1.1",
org.eclipse.jetty.osgi-servlet-api;bundle-version="3.1.0",
org.apache.shiro.core;bundle-version="1.2.2",
org.apache.shiro.web;bundle-version="1.2.2",
org.apache.shiro.ehcache;bundle-version="1.2.3",
com.sun.xml.bind.jaxb-impl;bundle-version="2.3.0",
com.sap.sse.replication.interfaces;bundle-version="1.0.0"
com.sap.sse.replication.interfaces;bundle-version="1.0.0",
org.apache.httpcomponents.httpcore;bundle-version="4.4.9",
com.sap.sailing.shared.server
Import-Package:
com.sap.sailing.util,
javax.ws.rs;version="1.1.1",
@@ -64,11 +64,14 @@ authc.successUrl = /api/restsecurity/hello
# authentication with POST parameters "username" and "password".
bearerToken = com.sap.sse.security.BearerTokenOrBasicOrFormAuthenticationFilter
# The same as bearerToken, but with additional fallback to anonymous authentication.
# In this case sufficient permission checks have to be done on the application side.
bearerTokenOrAnonymous = com.sap.sailing.shared.server.security.BearerTokenOrBasicOrFormOrAnonymousAuthenticationFilterSAPSailing
# Specifying filter chains for URL patterns
[urls]
# Uncomment the following to require the permission "event:view" in order to use /api/v1/events:
#/api/v1/events = bearerToken
/api/** = bearerTokenOrAnonymous
# Example: Secure access to leaderboard race column factor updates; read access should require no permissions
#/api/v1/leaderboards/*/racecolumnfactors/** = bearerToken
@@ -3,6 +3,7 @@ package com.sap.sailing.polars.impl;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -26,6 +27,7 @@ import com.sap.sse.util.ClearStateTestSupport;
public class Activator implements BundleActivator {
private static final String POLAR_DATA_SOURCE_URL_PROPERTY_NAME = "polardata.source.url";
private static final String POLAR_DATA_SOURCE_BEARER_TOKEN_PROPERTY_NAME = "polardata.source.bearertoken";
private static final Logger logger = Logger.getLogger(Activator.class.getName());
@@ -42,8 +44,10 @@ public class Activator implements BundleActivator {
registrations.add(context.registerService(Replicable.class, service, replicableServiceProperties));
registrations.add(context.registerService(ClearStateTestSupport.class.getName(), service, null));
final String polarDataSourceURL = System.getProperty(POLAR_DATA_SOURCE_URL_PROPERTY_NAME);
final String polarDataBearerToken = System.getProperty(POLAR_DATA_SOURCE_BEARER_TOKEN_PROPERTY_NAME);
if (polarDataSourceURL != null && !polarDataSourceURL.isEmpty()) {
waitForRacingEventServiceToObtainDomainFactory(polarDataSourceURL, service, context, polarDataServiceRegistration);
waitForRacingEventServiceToObtainDomainFactory(polarDataSourceURL,
Optional.ofNullable(polarDataBearerToken), service, context, polarDataServiceRegistration);
}
}
@@ -52,7 +56,6 @@ public class Activator implements BundleActivator {
* unregisters the service from the OSGi registry because it will temporarily become unusable, runs the polar data
* import from the given URL and registers the service again, adding the service registration object to the set of
* {@link #registrations}. The domain factory is required to resolve boat classes during de-serialization.
*
* @param polarDataServiceRegistration
* used to remove the service registration temporarily while updating the service by a remote import
* @param registerPolarServiceCallback
@@ -60,15 +63,15 @@ public class Activator implements BundleActivator {
* {@link Replicable} and as the {@link PolarDataService} with the OSGi registry
*/
private void waitForRacingEventServiceToObtainDomainFactory(final String polarDataSourceURL,
final ReplicablePolarService polarService, final BundleContext context,
ServiceRegistration<PolarDataService> polarDataServiceRegistration) {
Optional<String> polarDataBearerToken, final ReplicablePolarService polarService,
final BundleContext context, ServiceRegistration<PolarDataService> polarDataServiceRegistration) {
final Thread t = new Thread(() -> {
try {
Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); // ensure that classpath:... Shiro ini files are resolved properly
logger.info("Waiting for domain factory to be registered with PolarService...");
// Note: although the domainFactory parameter isn't used, using runWithDomainFactory ensures that the domain factory is there
polarService.runWithDomainFactory(domainFactory -> {
PolarDataClient polarDataClient = new PolarDataClient(polarDataSourceURL, polarService);
PolarDataClient polarDataClient = new PolarDataClient(polarDataSourceURL, polarService, polarDataBearerToken);
try {
polarDataServiceRegistration.unregister();
polarDataClient.updatePolarDataRegressions();
@@ -2,6 +2,7 @@ package com.sap.sailing.polars.jaxrs.api;
import java.io.IOException;
import java.io.OutputStream;
import java.util.logging.Logger;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@@ -10,13 +11,26 @@ import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import com.sap.sailing.domain.common.security.SecuredDomainType;
import com.sap.sailing.polars.jaxrs.AbstractPolarResource;
import com.sap.sse.ServerInfo;
import com.sap.sse.security.shared.HasPermissions.DefaultActions;
import com.sap.sse.security.shared.TypeRelativeObjectIdentifier;
@Path("/polar_data")
public class PolarDataResource extends AbstractPolarResource {
private static final Logger logger = Logger.getLogger(PolarDataResource.class.getName());
@GET
@Produces("application/octet-stream;charset=UTF-8")
public Response getRegressions() throws IOException {
final Subject subject = SecurityUtils.getSubject();
logger.info("Polar Data requested by "+ (subject.getPrincipal() == null ? "anonymous user" : subject.getPrincipal().toString()));
subject.checkPermission(SecuredDomainType.POLAR_DATA.getStringPermissionForTypeRelativeIdentifier(DefaultActions.READ,
new TypeRelativeObjectIdentifier(ServerInfo.getName())));
return Response.ok(new StreamingOutput() {
@Override
public void write(OutputStream output) throws IOException, WebApplicationException {
@@ -2,6 +2,7 @@ package com.sap.sailing.polars.jaxrs.client;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -11,9 +12,11 @@ import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.json.simple.parser.ParseException;
import com.sap.sailing.domain.common.security.SecuredDomainType;
import com.sap.sailing.polars.ReplicablePolarService;
import com.sap.sailing.polars.impl.PolarDataServiceImpl;
import com.sap.sailing.polars.mining.PolarDataMiner;
import com.sap.sse.security.shared.HasPermissions.DefaultActions;
import com.sap.sse.util.LaxRedirectStrategyForAllRedirectResponseCodes;
/**
@@ -32,17 +35,25 @@ public class PolarDataClient {
private final ReplicablePolarService polarDataService;
private final String polarDataSourceURL;
private final Optional<String> polarDataBearerToken;
/**
* Default constructor is missing because we need {@link PolarDataServiceImpl} to reach regressions
*
* @param polarDataSourceURL
* archive server URL string
* @param polarDataService
* {@link PolarDataServiceImpl} service to work with
* @param polarDataBearerToken
* if present, this will be used in a <tt>Authorization: Bearer ...</tt> HTTP header to authenticate the
* request that fetches the polar data. The token must authenticate a subject with permission
* {@link SecuredDomainType#POLAR_DATA}.{@link DefaultActions#READ READ} on the "SERVER" object from
* where polar data is request as per the {@code polarDataSourceURL}.
*/
public PolarDataClient(String polarDataSourceURL, ReplicablePolarService polarDataService) {
public PolarDataClient(String polarDataSourceURL, ReplicablePolarService polarDataService, Optional<String> polarDataBearerToken) {
this.polarDataService = polarDataService;
this.polarDataSourceURL = polarDataSourceURL;
this.polarDataBearerToken = polarDataBearerToken;
}
/**
@@ -70,9 +81,14 @@ public class PolarDataClient {
}
protected InputStream getContentFromResponse() throws IOException, ParseException {
HttpClient client = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategyForAllRedirectResponseCodes()).build();
HttpGet getProcessor = new HttpGet(getAPIString());
HttpResponse processorResponse = client.execute(getProcessor);
final HttpClient client = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategyForAllRedirectResponseCodes()).build();
final HttpGet getProcessor = new HttpGet(getAPIString());
polarDataBearerToken.ifPresent(bearerToken -> getProcessor.setHeader("Authorization", "Bearer " + bearerToken));
final HttpResponse processorResponse = client.execute(getProcessor);
if (processorResponse.getStatusLine().getStatusCode() >= 300) {
throw new IOException("Error trying to load polar data from "+getAPIString()+": "
+processorResponse.getStatusLine().getReasonPhrase()+" ("+processorResponse.getStatusLine().getStatusCode()+")");
}
return processorResponse.getEntity().getContent();
}
@@ -1,17 +1,59 @@
package com.sap.sailing.server.gateway;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import org.json.simple.JSONAware;
import com.sap.sse.common.fileupload.FileUploadUtil;
/**
* Base servlet for json exports
* @author Frank
* Base servlet for JSON exports. If implementing subclasses use {@link #setJsonResponseHeader(HttpServletResponse)},
* they are assumed to write their response to the servlet response's {@link HttpServletResponse#getOutputStream()
* output stream} directly. Alternatively, e.g., when used as the target of a file upload form that technically expects
* HTML output, the output can be set to {@code text/html}, and a special encoding of a JSON response will be used so it
* can be embedded robustly in an HTML document's {@code body} tag and be extracted again by the client receiving the
* event about submission completion.
*
* @author Frank Mittag
* @author Axel Uhl
*/
@SuppressWarnings("serial")
public abstract class AbstractJsonHttpServlet extends SailingServerHttpServlet {
/**
* By invoking this method you declare that you will write the JSON document
* straight to the output stream.
*/
protected void setJsonResponseHeader(HttpServletResponse resp) {
setBasicPropertiesInResponseHeader(resp);
resp.setContentType("application/json");
}
/**
* By invoking this method you declare that you assume being the target of a form submission
* and will encode your JSON into an HTML document's {@code body} tag, using the
* {@link FileUploadUtil} class.
*/
protected void setJsonEncodedInHtmlResponseHeader(HttpServletResponse resp) {
setBasicPropertiesInResponseHeader(resp);
resp.setContentType("text/html");
}
private void setBasicPropertiesInResponseHeader(HttpServletResponse resp) {
// to allow access to the json document directly from a client side javascript
resp.setHeader("Access-Control-Allow-Origin", "*");
resp.setContentType("application/json");
resp.setCharacterEncoding("UTF-8");
}
/**
* Encodes the stringified {@code json} object into an HTML document's {@code body} element, writing the output into
* {@code resp}'s {@link HttpServletResponse#getWriter() writer}. The encoding is done using
* {@link FileUploadUtil#getHtmlWithEmbeddedJsonContent(String)} which the client can
* then also use to {@link FileUploadUtil#getEmbeddedJsonContentFromHtml(String, java.util.function.Function)
* extract} the pure JSON string from the HTML carrier document again.
*/
protected void writeJsonIntoHtmlResponse(HttpServletResponse resp, JSONAware json) throws IOException {
resp.getWriter().write(FileUploadUtil.getHtmlWithEmbeddedJsonContent(json.toJSONString()));
}
}
@@ -15,9 +15,14 @@ import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import com.sap.sailing.server.gateway.AbstractJsonHttpServlet;
import com.sap.sse.common.fileupload.FileUploadUtil;
/**
* Abstract servlet handling multipart-mime file upload coming from an upload form
* Abstract servlet handling multipart-mime file upload coming from an upload form. The response content type is set to
* "text/html" by default (see {@link #setJsonEncodedInHtmlResponseHeader(HttpServletResponse)}). If your response is a
* JSON document, encode it as an HTML document {@code body} using
* {@link FileUploadUtil#getHtmlWithEmbeddedJsonContent(String)}. A client can then use the submit complete event
* response and decode it using {@link FileUploadUtil#getApplicationJsonContentFromHtml(String)}.
*
* @author Fredrik Teschke
* @author Axel Uhl
@@ -56,7 +61,7 @@ public abstract class AbstractFileUploadServlet extends AbstractJsonHttpServlet
// Conversely, trying to use text/html as content encoding leads some browsers---especially on mobile devices---
// to do ugly things to the content returned, such as replacing digit sequences by a corresponding <a> element
// that allows the user to dial that number with the phone app...
setJsonResponseHeader(resp);
setJsonEncodedInHtmlResponseHeader(resp);
process(items, req, resp);
} catch (FileUploadException e) {
throw new IOException("Could not parse request");
@@ -105,7 +105,6 @@ public class FileUploadServlet extends AbstractFileUploadServlet {
}
resultList.add(result);
}
resultList.writeJSONString(resp.getWriter());
writeJsonIntoHtmlResponse(resp, resultList);
}
}
@@ -456,7 +456,9 @@ public class CompareServersResource extends AbstractSailingServerResource {
json1.remove(i);
json2.remove(item2);
} else {
removeDuplicateEntries(item1, item2);
if (item1 != null && item2 != null) {
removeDuplicateEntries(item1, item2);
}
i++;
}
}
@@ -101,7 +101,6 @@ public class ORCCertificateImportServlet extends AbstractFileUploadServlet {
private void writeResponse(Iterable<ORCCertificate> certificates, HttpServletResponse resp) throws IOException {
// Use text/html to prevent browsers from wrapping the response body,
// see "Handling File Upload Responses in GWT" at http://www.artofsolving.com/node/50
resp.setContentType("text/html;charset=UTF-8");
final JSONObject jsonResponse = new JSONObject();
final ORCCertificateJsonSerializer certificateSerializer = new ORCCertificateJsonSerializer();
final JSONArray certificatesAsJson = new JSONArray();
@@ -110,7 +109,7 @@ public class ORCCertificateImportServlet extends AbstractFileUploadServlet {
}
jsonResponse.put(ORCCertificateUploadConstants.CERTIFICATES, certificatesAsJson);
jsonResponse.put(ORCCertificateUploadConstants.STATUS, "OK");
jsonResponse.writeJSONString(resp.getWriter());
writeJsonIntoHtmlResponse(resp, jsonResponse);
}
}
@@ -130,7 +130,7 @@ public class ExpeditionAllInOneImportServlet extends AbstractFileUploadServlet {
importerResult = new ImporterResult(t, Collections.emptyList());
logger.log(Level.SEVERE, t.getMessage());
} finally {
this.toJSON(importerResult).writeJSONString(resp.getWriter());
writeJsonIntoHtmlResponse(resp, toJSON(importerResult));
}
}
@@ -51,7 +51,7 @@ public class SensorDataImportServlet extends AbstractFileUploadServlet {
} catch (Exception e) {
importResult.add(e);
} finally {
ImportResultSerializer.serializeImportResult(importResult).writeJSONString(resp.getWriter());
writeJsonIntoHtmlResponse(resp, ImportResultSerializer.serializeImportResult(importResult));
}
}
}
@@ -62,7 +62,7 @@ public class TrackFilesImportServlet extends AbstractFileUploadServlet {
} catch (Exception e) {
importResult.add(e);
} finally {
ImportResultSerializer.serializeImportResult(importResult).writeJSONString(resp.getWriter());
writeJsonIntoHtmlResponse(resp, ImportResultSerializer.serializeImportResult(importResult));
}
}
}
@@ -28,295 +28,291 @@
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
<stringAttribute key="pde.version" value="3.3"/>
<setAttribute key="selected_target_bundles">
<setEntry value="routeconverter@default:default"/>
<setEntry value="org.apache.commons.codec@default:default"/>
<setEntry value="org.apache.poi@default:default"/>
<setEntry value="org.apache.poi.ooxml@default:default"/>
<setEntry value="org.apache.poi.ooxml.schemas@default:default"/>
<setEntry value="org.apache.commons.collections4@default:default"/>
<setEntry value="org.apache.commons.compress@default:default"/>
<setEntry value="org.apache.poi.source@default:default"/>
<setEntry value="org.apache.poi.ooxml.source@default:default"/>
<setEntry value="org.apache.commons.collections4.source@default:default"/>
<setEntry value="org.apache.commons.compress.source@default:default"/>
<setEntry value="org.dom4j@default:default"/>
<setEntry value="org.apache.xmlbeans@default:default"/>
<setEntry value="org.apache.commons.math@default:default"/>
<setEntry value="org.apache.httpcomponents.httpclient@default:default"/>
<setEntry value="org.apache.httpcomponents.httpcore@default:default"/>
<setEntry value="org.hyperic.sigar@default:default"/>
<setEntry value="com.sun.jersey.contribs.jersey-multipart@default:default"/>
<setEntry value="javax.validation@default:default"/>
<setEntry value="org.apache.commons.fileupload@default:default"/>
<setEntry value="org.jvnet.mimepull@default:default"/>
<setEntry value="org.apache.commons.math3@default:default"/>
<setEntry value="org.mongodb.driver-core@default:default"/>
<setEntry value="org.mongodb.driver-core.source@default:default"/>
<setEntry value="org.mongodb.bson@default:default"/>
<setEntry value="org.mongodb.bson.source@default:default"/>
<setEntry value="org.mongodb.driver-sync@default:default"/>
<setEntry value="org.mongodb.driver-sync@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot@3:true"/>
<setEntry value="org.eclipse.jetty.osgi.boot.warurl@default:default"/>
<setEntry value="org.hyperic.sigar@default:default"/>
<setEntry value="slf4j.jdk14@default:default"/>
<setEntry value="lz4-java@default:default"/>
<setEntry value="org.apache.felix.gogo.command@default:default"/>
<setEntry value="org.apache.felix.gogo.runtime@default:default"/>
<setEntry value="org.apache.felix.gogo.shell@default:default"/>
<setEntry value="org.eclipse.jetty.deploy@default:default"/>
<setEntry value="org.eclipse.jetty.deploy.source@default:default"/>
<setEntry value="org.eclipse.jetty.http@3:true"/>
<setEntry value="org.eclipse.jetty.http.source@default:default"/>
<setEntry value="org.eclipse.jetty.io@default:default"/>
<setEntry value="org.eclipse.jetty.io.source@default:default"/>
<setEntry value="org.eclipse.jetty.jmx@default:default"/>
<setEntry value="org.eclipse.jetty.jmx.source@default:default"/>
<setEntry value="org.eclipse.jetty.security@default:default"/>
<setEntry value="org.eclipse.jetty.security.source@default:default"/>
<setEntry value="org.eclipse.jetty.server@default:default"/>
<setEntry value="org.eclipse.jetty.server.source@default:default"/>
<setEntry value="org.eclipse.jetty.servlet@default:default"/>
<setEntry value="org.eclipse.jetty.servlet.source@default:default"/>
<setEntry value="org.eclipse.jetty.util@default:default"/>
<setEntry value="org.eclipse.jetty.util.source@default:default"/>
<setEntry value="org.eclipse.jetty.util.ajax@default:default"/>
<setEntry value="org.eclipse.jetty.util.ajax.source@default:default"/>
<setEntry value="org.eclipse.jetty.webapp@default:default"/>
<setEntry value="org.eclipse.jetty.webapp.source@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.api@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.api.source@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.client@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.client.source@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.common@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.common.source@default:default"/>
<setEntry value="org.eclipse.jetty.xml@default:default"/>
<setEntry value="org.eclipse.jetty.xml.source@default:default"/>
<setEntry value="slf4j.api@default:default"/>
<setEntry value="org.apache.servicemix.bundles.zxing@default:default"/>
<setEntry value="org.apache.commons.io@default:default"/>
<setEntry value="jcl.over.slf4j@default:default"/>
<setEntry value="com.sun.mail.javax.mail@default:default"/>
<setEntry value="com.rabbitmq.client@default:default"/>
<setEntry value="com.rabbitmq.client.source@default:default"/>
<setEntry value="org.apache.commons.lang@default:default"/>
<setEntry value="org.apache.commons.logging@default:default"/>
<setEntry value="jackson-jaxrs@default:default"/>
<setEntry value="com.sun.jersey@default:default"/>
<setEntry value="javax.ws.rs@default:default"/>
<setEntry value="org.apache.commons.beanutils@default:default"/>
<setEntry value="org.apache.commons.beanutils.source@default:default"/>
<setEntry value="org.apache.servicemix.bundles.ehcache@default:default"/>
<setEntry value="org.apache.servicemix.bundles.scribe@default:default"/>
<setEntry value="org.owasp.encoder@default:default"/>
<setEntry value="org.owasp.encoder.source@default:default"/>
<setEntry value="org.apache.shiro.core@default:default"/>
<setEntry value="org.apache.shiro.core.source@default:default"/>
<setEntry value="org.apache.shiro.ehcache@default:default"/>
<setEntry value="org.apache.shiro.ehcache.source@default:default"/>
<setEntry value="org.apache.shiro.web@default:default"/>
<setEntry value="org.apache.shiro.web.source@default:default"/>
<setEntry value="jackson-core-asl@default:default"/>
<setEntry value="jackson-mapper-asl@default:default"/>
<setEntry value="org.apache.commons.collections@default:default"/>
<setEntry value="org.eclipse.jetty.client@default:default"/>
<setEntry value="javax.xml@default:default"/>
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
<setEntry value="org.eclipse.osgi.source@default:default"/>
<setEntry value="org.osgi.util.promise@default:default"/>
<setEntry value="org.osgi.util.promise.source@default:default"/>
<setEntry value="org.osgi.util.function@default:default"/>
<setEntry value="org.osgi.util.function.source@default:default"/>
<setEntry value="org.osgi.util.measurement@default:default"/>
<setEntry value="org.osgi.util.measurement.source@default:default"/>
<setEntry value="org.osgi.util.position@default:default"/>
<setEntry value="org.osgi.util.position.source@default:default"/>
<setEntry value="org.osgi.util.xml@default:default"/>
<setEntry value="org.osgi.util.xml.source@default:default"/>
<setEntry value="org.eclipse.osgi.services@default:default"/>
<setEntry value="org.eclipse.osgi.services.source@default:default"/>
<setEntry value="org.eclipse.equinox.cm@default:default"/>
<setEntry value="com.sun.istack.commons-runtime@default:default"/>
<setEntry value="com.sun.xml.bind.jaxb-impl@default:default"/>
<setEntry value="javax.xml.stream@default:default"/>
<setEntry value="javax.xml.ws@default:default"/>
<setEntry value="javax.xml.soap@default:default"/>
<setEntry value="org.eclipse.osgi.util@default:default"/>
<setEntry value="org.eclipse.osgi.util.source@default:default"/>
<setEntry value="com.chargebee.chargebee-java@default:default"/>
<setEntry value="com.github.mwiede.jsch@default:default"/>
<setEntry value="com.github.mwiede.jsch.source@default:default"/>
<setEntry value="bcprov-ext@default:default"/>
<setEntry value="com.amazon.aws.aws-java-api@default:default"/>
<setEntry value="com.amazon.aws.aws-java-api.source@default:default"/>
<setEntry value="org.objectweb.asm@default:default"/>
<setEntry value="org.objectweb.asm.commons@default:default"/>
<setEntry value="org.objectweb.asm.analysis@default:default"/>
<setEntry value="org.objectweb.asm.tree@default:default"/>
<setEntry value="org.objectweb.asm.util@default:default"/>
<setEntry value="org.objectweb.asm.source@default:default"/>
<setEntry value="org.objectweb.asm.analysis.source@default:default"/>
<setEntry value="org.objectweb.asm.commons.source@default:default"/>
<setEntry value="org.objectweb.asm.tree.source@default:default"/>
<setEntry value="org.objectweb.asm.util.source@default:default"/>
<setEntry value="org.eclipse.jetty.apache-jsp@4:true"/>
<setEntry value="org.eclipse.jetty.apache-jsp.source@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot.jsp@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot.jsp.source@default:default"/>
<setEntry value="org.apache.geronimo.specs.geronimo-jta_1.1_spec@default:default"/>
<setEntry value="org.apache.aries.spifly.dynamic.bundle@3:true"/>
<setEntry value="org.apache.aries.spifly.dynamic.bundle.source@default:default"/>
<setEntry value="org.mortbay.jasper.apache-el@default:default"/>
<setEntry value="org.mortbay.jasper.apache-jsp@default:default"/>
<setEntry value="org.eclipse.jdt.core.compiler.batch@default:default"/>
<setEntry value="org.apache.taglibs.standard-impl@default:default"/>
<setEntry value="org.apache.taglibs.taglibs-standard-spec@default:default"/>
<setEntry value="javax.annotation@default:default"/>
<setEntry value="org.eclipse.jetty.osgi-servlet-api@default:default"/>
<setEntry value="org.apache.xalan@default:default"/>
<setEntry value="org.apache.xml.serializer@default:default"/>
<setEntry value="org.eclipse.equinox.event@default:default"/>
<setEntry value="org.eclipse.jetty.annotations@4:true"/>
<setEntry value="org.eclipse.jetty.jndi@default:default"/>
<setEntry value="org.eclipse.jetty.plus@default:default"/>
<setEntry value="com.sap.db.jdbc@default:default"/>
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="com.github.haifengl.smile-core@default:default"/>
<setEntry value="com.github.haifengl.smile-core.source@default:default"/>
<setEntry value="com.github.haifengl.smile-data@default:default"/>
<setEntry value="com.github.haifengl.smile-data.source@default:default"/>
<setEntry value="com.github.haifengl.smile-graph@default:default"/>
<setEntry value="com.github.haifengl.smile-graph.source@default:default"/>
<setEntry value="com.github.haifengl.smile-math@default:default"/>
<setEntry value="com.github.haifengl.smile-math.source@default:default"/>
<setEntry value="com.google.gson@default:default"/>
<setEntry value="com.google.gson.source@default:default"/>
</setAttribute>
<setEntry value="bcprov-ext@default:default"/>
<setEntry value="com.amazon.aws.aws-java-api.source"/>
<setEntry value="com.amazon.aws.aws-java-api@default:default"/>
<setEntry value="com.chargebee.chargebee-java@default:default"/>
<setEntry value="com.github.haifengl.smile-core.source"/>
<setEntry value="com.github.haifengl.smile-core@default:default"/>
<setEntry value="com.github.haifengl.smile-data.source"/>
<setEntry value="com.github.haifengl.smile-data@default:default"/>
<setEntry value="com.github.haifengl.smile-graph.source"/>
<setEntry value="com.github.haifengl.smile-graph@default:default"/>
<setEntry value="com.github.haifengl.smile-math.source"/>
<setEntry value="com.github.haifengl.smile-math@default:default"/>
<setEntry value="com.github.mwiede.jsch.source"/>
<setEntry value="com.github.mwiede.jsch@default:default"/>
<setEntry value="com.google.gson.source"/>
<setEntry value="com.google.gson@default:default"/>
<setEntry value="com.rabbitmq.client.source"/>
<setEntry value="com.rabbitmq.client@default:default"/>
<setEntry value="com.sap.db.jdbc.source"/>
<setEntry value="com.sap.db.jdbc@default:default"/>
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="com.sun.istack.commons-runtime@default:default"/>
<setEntry value="com.sun.jersey.contribs.jersey-multipart@default:default"/>
<setEntry value="com.sun.jersey@default:default"/>
<setEntry value="com.sun.mail.javax.mail@default:default"/>
<setEntry value="com.sun.xml.bind.jaxb-impl@default:default"/>
<setEntry value="jackson-core-asl@default:default"/>
<setEntry value="jackson-jaxrs@default:default"/>
<setEntry value="jackson-mapper-asl@default:default"/>
<setEntry value="javax.annotation@default:default"/>
<setEntry value="javax.validation@default:default"/>
<setEntry value="javax.ws.rs@default:default"/>
<setEntry value="javax.xml.soap@default:default"/>
<setEntry value="javax.xml.stream@default:default"/>
<setEntry value="javax.xml.ws@default:default"/>
<setEntry value="javax.xml@default:default"/>
<setEntry value="jcl.over.slf4j@default:default"/>
<setEntry value="lz4-java@default:default"/>
<setEntry value="org.apache.aries.spifly.dynamic.bundle.source"/>
<setEntry value="org.apache.aries.spifly.dynamic.bundle@3:true"/>
<setEntry value="org.apache.commons.beanutils.source@default:default"/>
<setEntry value="org.apache.commons.beanutils@default:default"/>
<setEntry value="org.apache.commons.codec@default:default"/>
<setEntry value="org.apache.commons.collections4.source"/>
<setEntry value="org.apache.commons.collections4@default:default"/>
<setEntry value="org.apache.commons.collections@default:default"/>
<setEntry value="org.apache.commons.compress.source"/>
<setEntry value="org.apache.commons.compress@default:default"/>
<setEntry value="org.apache.commons.fileupload@default:default"/>
<setEntry value="org.apache.commons.io@default:default"/>
<setEntry value="org.apache.commons.lang@default:default"/>
<setEntry value="org.apache.commons.logging@default:default"/>
<setEntry value="org.apache.commons.math3@default:default"/>
<setEntry value="org.apache.commons.math@default:default"/>
<setEntry value="org.apache.felix.gogo.command@default:default"/>
<setEntry value="org.apache.felix.gogo.runtime@default:default"/>
<setEntry value="org.apache.felix.gogo.shell@default:default"/>
<setEntry value="org.apache.geronimo.specs.geronimo-jta_1.1_spec@default:default"/>
<setEntry value="org.apache.httpcomponents.httpclient@default:default"/>
<setEntry value="org.apache.httpcomponents.httpcore@default:default"/>
<setEntry value="org.apache.poi.ooxml.schemas@default:default"/>
<setEntry value="org.apache.poi.ooxml.source"/>
<setEntry value="org.apache.poi.ooxml@default:default"/>
<setEntry value="org.apache.poi.source"/>
<setEntry value="org.apache.poi@default:default"/>
<setEntry value="org.apache.servicemix.bundles.ehcache@default:default"/>
<setEntry value="org.apache.servicemix.bundles.scribe@default:default"/>
<setEntry value="org.apache.servicemix.bundles.zxing@default:default"/>
<setEntry value="org.apache.shiro.core.source"/>
<setEntry value="org.apache.shiro.core@default:default"/>
<setEntry value="org.apache.shiro.ehcache.source"/>
<setEntry value="org.apache.shiro.ehcache@default:default"/>
<setEntry value="org.apache.shiro.web.source"/>
<setEntry value="org.apache.shiro.web@default:default"/>
<setEntry value="org.apache.taglibs.standard-impl@default:default"/>
<setEntry value="org.apache.taglibs.taglibs-standard-spec@default:default"/>
<setEntry value="org.apache.xalan@default:default"/>
<setEntry value="org.apache.xml.serializer@default:default"/>
<setEntry value="org.apache.xmlbeans@default:default"/>
<setEntry value="org.dom4j@default:default"/>
<setEntry value="org.eclipse.equinox.cm@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.event@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.jdt.core.compiler.batch@default:default"/>
<setEntry value="org.eclipse.jetty.annotations@4:true"/>
<setEntry value="org.eclipse.jetty.apache-jsp.source"/>
<setEntry value="org.eclipse.jetty.apache-jsp@4:true"/>
<setEntry value="org.eclipse.jetty.client@default:default"/>
<setEntry value="org.eclipse.jetty.deploy.source"/>
<setEntry value="org.eclipse.jetty.deploy@default:default"/>
<setEntry value="org.eclipse.jetty.http.source"/>
<setEntry value="org.eclipse.jetty.http@3:true"/>
<setEntry value="org.eclipse.jetty.io.source"/>
<setEntry value="org.eclipse.jetty.io@default:default"/>
<setEntry value="org.eclipse.jetty.jmx.source"/>
<setEntry value="org.eclipse.jetty.jmx@default:default"/>
<setEntry value="org.eclipse.jetty.jndi@default:default"/>
<setEntry value="org.eclipse.jetty.osgi-servlet-api@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot.jsp.source"/>
<setEntry value="org.eclipse.jetty.osgi.boot.jsp@default:false"/>
<setEntry value="org.eclipse.jetty.osgi.boot.warurl@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot@3:true"/>
<setEntry value="org.eclipse.jetty.plus@default:default"/>
<setEntry value="org.eclipse.jetty.security.source"/>
<setEntry value="org.eclipse.jetty.security@default:default"/>
<setEntry value="org.eclipse.jetty.server.source"/>
<setEntry value="org.eclipse.jetty.server@default:default"/>
<setEntry value="org.eclipse.jetty.servlet.source"/>
<setEntry value="org.eclipse.jetty.servlet@default:default"/>
<setEntry value="org.eclipse.jetty.util.ajax.source"/>
<setEntry value="org.eclipse.jetty.util.ajax@default:default"/>
<setEntry value="org.eclipse.jetty.util.source"/>
<setEntry value="org.eclipse.jetty.util@default:default"/>
<setEntry value="org.eclipse.jetty.webapp.source"/>
<setEntry value="org.eclipse.jetty.webapp@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.api.source"/>
<setEntry value="org.eclipse.jetty.websocket.api@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.client.source"/>
<setEntry value="org.eclipse.jetty.websocket.client@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.common.source"/>
<setEntry value="org.eclipse.jetty.websocket.common@default:default"/>
<setEntry value="org.eclipse.jetty.xml.source"/>
<setEntry value="org.eclipse.jetty.xml@default:default"/>
<setEntry value="org.eclipse.osgi.services.source"/>
<setEntry value="org.eclipse.osgi.services@default:default"/>
<setEntry value="org.eclipse.osgi.source"/>
<setEntry value="org.eclipse.osgi.util.source"/>
<setEntry value="org.eclipse.osgi.util@default:default"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
<setEntry value="org.hyperic.sigar@default:default"/>
<setEntry value="org.jvnet.mimepull@default:default"/>
<setEntry value="org.mongodb.bson.source"/>
<setEntry value="org.mongodb.bson@default:default"/>
<setEntry value="org.mongodb.driver-core.source"/>
<setEntry value="org.mongodb.driver-core@default:default"/>
<setEntry value="org.mongodb.driver-sync@default:default"/>
<setEntry value="org.mortbay.jasper.apache-el@default:default"/>
<setEntry value="org.mortbay.jasper.apache-jsp@default:default"/>
<setEntry value="org.objectweb.asm.analysis.source"/>
<setEntry value="org.objectweb.asm.analysis@default:default"/>
<setEntry value="org.objectweb.asm.commons.source"/>
<setEntry value="org.objectweb.asm.commons@default:default"/>
<setEntry value="org.objectweb.asm.source"/>
<setEntry value="org.objectweb.asm.tree.source"/>
<setEntry value="org.objectweb.asm.tree@default:default"/>
<setEntry value="org.objectweb.asm.util.source"/>
<setEntry value="org.objectweb.asm.util@default:default"/>
<setEntry value="org.objectweb.asm@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="org.osgi.util.function.source"/>
<setEntry value="org.osgi.util.function@default:default"/>
<setEntry value="org.osgi.util.measurement.source"/>
<setEntry value="org.osgi.util.measurement@default:default"/>
<setEntry value="org.osgi.util.position.source"/>
<setEntry value="org.osgi.util.position@default:default"/>
<setEntry value="org.osgi.util.promise.source"/>
<setEntry value="org.osgi.util.promise@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.util.xml.source"/>
<setEntry value="org.osgi.util.xml@default:default"/>
<setEntry value="org.owasp.encoder.source"/>
<setEntry value="org.owasp.encoder@default:default"/>
<setEntry value="routeconverter@default:default"/>
<setEntry value="slf4j.api@default:default"/>
<setEntry value="slf4j.jdk14@default:default"/>
</setAttribute>
<setAttribute key="selected_workspace_bundles">
<setEntry value="com.sap.sailing.geocoding@default:default"/>
<setEntry value="com.sap.sailing.domain.common@default:default"/>
<setEntry value="com.sap.sailing.domain@default:default"/>
<setEntry value="com.sap.sailing.news@4:true"/>
<setEntry value="com.sap.sailing.domain.tractracadapter@5:true"/>
<setEntry value="com.sap.sailing.expeditionconnector@default:default"/>
<setEntry value="com.sap.sailing.domain.windfinderadapter@4:true"/>
<setEntry value="com.sap.sailing.server@5:true"/>
<setEntry value="com.sap.sailing.server.gateway@5:true"/>
<setEntry value="com.sap.sailing.server.gateway.interfaces@default:default"/>
<setEntry value="com.tractrac.clientmodule@default:default"/>
<setEntry value="com.sap.sailing.declination@default:default"/>
<setEntry value="com.sap.sailing.domain.persistence@default:default"/>
<setEntry value="com.sap.sailing.domain.swisstimingadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.swisstimingadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.domain.swisstimingreplayadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.tractracadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.gwt.ui@6:true"/>
<setEntry value="com.sap.sailing.udpconnector@default:default"/>
<setEntry value="com.sap.sailing.simulator@default:default"/>
<setEntry value="com.sap.sailing.www@5:true"/>
<setEntry value="com.sap.sailing.resultimport@4:true"/>
<setEntry value="com.sap.sailing.kiworesultimport@4:true"/>
<setEntry value="com.sap.sailing.ess40.resultimport@4:true"/>
<setEntry value="com.sap.sailing.freg.resultimport@4:true"/>
<setEntry value="com.sap.sailing.barbados.resultimport@4:true"/>
<setEntry value="com.sap.sailing.sailwave.resultimport@4:true"/>
<setEntry value="com.sap.sailing.manage2sail.resultimport@4:true"/>
<setEntry value="com.sap.sailing.sailti.resultimport@4:true"/>
<setEntry value="com.sap.sailing.yachtscoring.resultimport@4:true"/>
<setEntry value="com.sap.sailing.velum.resultimport@4:true"/>
<setEntry value="com.sap.sailing.monitoring@7:true"/>
<setEntry value="com.sap.sailing.xrr.resultimport@4:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.persistence@default:default"/>
<setEntry value="com.sap.sailing.domain.racelogtrackingadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.deckmanadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.oceanraceadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.yellowbrickadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.yellowbrickadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.xrr.structureimport@default:default"/>
<setEntry value="com.sap.sailing.server.gateway.serialization.shared.android@default:default"/>
<setEntry value="com.sap.sailing.server.gateway.serialization@default:default"/>
<setEntry value="com.sap.sailing.dashboards.gwt@6:true"/>
<setEntry value="com.sap.sailing.dashboards.gwt@6:true"/>
<setEntry value="com.sap.sailing.datamining@5:true"/>
<setEntry value="com.sap.sailing.datamining.shared@default:default"/>
<setEntry value="com.sap.sailing.polars@5:true"/>
<setEntry value="com.sap.sailing.windestimation@5:true"/>
<setEntry value="com.sap.sailing.polars.datamining@5:true"/>
<setEntry value="com.sap.sailing.domain.shared.android@default:default"/>
<setEntry value="com.sap.sailing.manage2sail@default:default"/>
<setEntry value="com.sap.sailing.polars.datamining.shared@default:default"/>
<setEntry value="com.sap.sailing.xrr.schema@default:default"/>
<setEntry value="com.sap.sailing.server.trackfiles@default:default"/>
<setEntry value="com.sap.sailing.competitorimport@default:default"/>
<setEntry value="com.sap.sailing.datamining.provider@default:default"/>
<setEntry value="com.sap.sailing.grib@default:default"/>
<setEntry value="com.sap.sailing.nmeaconnector@default:default"/>
<setEntry value="com.sap.sailing.domain.expeditionadapter@5:true"/>
<setEntry value="com.sap.sailing.expeditionconnector.persistence@4:true"/>
<setEntry value="com.sap.sailing.expeditionconnector.common@default:default"/>
<setEntry value="com.sap.sailing.domain.bravoadapter@5:true"/>
<setEntry value="net.sf.marineapi@default:default"/>
<setEntry value="com.sap.sailing.routeconverterjava11extension@default:default"/>
<setEntry value="com.sap.sailing.server.interface@default:default"/>
<setEntry value="com.sap.sse.datamining.ui@default:default"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.gateway@5:true"/>
<setEntry value="com.sap.sailing.shared.server@5:true"/>
<setEntry value="com.sap.sailing.shared.server.gateway@5:true"/>
<setEntry value="com.sap.sailing.shared.persistence@default:default"/>
<setEntry value="com.sap.sailing.landscape@default:default"/>
<setEntry value="com.sap.sailing.landscape.gateway@5:true"/>
<setEntry value="com.sap.sailing.landscape.common@default:default"/>
<setEntry value="com.sap.sailing.landscape.ui@default:default"/>
<setEntry value="com.sap.sailing.hanaexport@5:true"/>
<setEntry value="com.tractrac.clientmodule@default:default"/>
<setEntry value="com.sap.sse.gwt@default:default"/>
<setEntry value="com.google.gwt.servlet@default:default"/>
<setEntry value="com.sap.sse.security@default:default"/>
<setEntry value="com.sap.sse.security.ui@6:true"/>
<setEntry value="com.sap.sse.security.userstore.mongodb@4:true"/>
<setEntry value="com.sap.sse@default:default"/>
<setEntry value="com.sap.sse.common@default:default"/>
<setEntry value="com.sap.sse.datamining@default:default"/>
<setEntry value="com.sap.sse.datamining.annotations@default:default"/>
<setEntry value="com.sap.sse.datamining.shared@default:default"/>
<setEntry value="com.sap.sse.gwt.adminconsole@default:default"/>
<setEntry value="com.sap.sse.mongodb@default:default"/>
<setEntry value="com.sap.sse.operationaltransformation@default:default"/>
<setEntry value="com.sap.sse.replication@6:true"/>
<setEntry value="com.sap.sse.filestorage@4:true"/>
<setEntry value="com.sap.sse.shared.android@default:default"/>
<setEntry value="com.sap.sse.mail@5:true"/>
<setEntry value="com.sap.sse.threadmanager@default:default"/>
<setEntry value="com.sap.sse.security.common@default:default"/>
<setEntry value="org.json.simple@default:default"/>
<setEntry value="org.moxieapps.gwt.highcharts@default:default"/>
<setEntry value="com.googlecode.java-diff-utils@default:default"/>
<setEntry value="org.mp4parser.isoparser@default:default"/>
<setEntry value="com.sap.sse.replication.interfaces@default:default"/>
<setEntry value="com.sap.sse.security.datamining@5:true"/>
<setEntry value="com.sap.sse.security.persistence@default:default"/>
<setEntry value="com.sap.sse.security.interface@default:default"/>
<setEntry value="com.sap.sse.replication.persistence@default:default"/>
<setEntry value="com.sap.sse.landscape.common@default:default"/>
<setEntry value="com.sap.sse.landscape@default:default"/>
<setEntry value="com.sap.sse.landscape.aws@4:true"/>
<setEntry value="com.sap.sse.landscape.aws.common@default:default"/>
<setEntry value="com.sap.sse.landscape.aws.persistence@default:default"/>
<setEntry value="com.sap.sse.debranding@default:default"/>
<setEntry value="elemental2@default:default"/>
</setAttribute>
<setEntry value="com.google.gwt.servlet@default:default"/>
<setEntry value="com.googlecode.java-diff-utils@default:default"/>
<setEntry value="com.sap.sailing.barbados.resultimport@4:true"/>
<setEntry value="com.sap.sailing.competitorimport@default:default"/>
<setEntry value="com.sap.sailing.dashboards.gwt@6:true"/>
<setEntry value="com.sap.sailing.datamining.provider@default:default"/>
<setEntry value="com.sap.sailing.datamining.shared@default:default"/>
<setEntry value="com.sap.sailing.datamining@5:true"/>
<setEntry value="com.sap.sailing.declination@default:default"/>
<setEntry value="com.sap.sailing.domain.bravoadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.common@default:default"/>
<setEntry value="com.sap.sailing.domain.deckmanadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.expeditionadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.gateway@5:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.persistence@default:default"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.oceanraceadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.persistence@default:default"/>
<setEntry value="com.sap.sailing.domain.racelogtrackingadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.shared.android@default:default"/>
<setEntry value="com.sap.sailing.domain.swisstimingadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.domain.swisstimingadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.swisstimingreplayadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.tractracadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.domain.tractracadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.windfinderadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.yellowbrickadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.domain.yellowbrickadapter@5:true"/>
<setEntry value="com.sap.sailing.domain@default:default"/>
<setEntry value="com.sap.sailing.ess40.resultimport@4:true"/>
<setEntry value="com.sap.sailing.expeditionconnector.common@default:default"/>
<setEntry value="com.sap.sailing.expeditionconnector.persistence@4:true"/>
<setEntry value="com.sap.sailing.expeditionconnector@default:default"/>
<setEntry value="com.sap.sailing.freg.resultimport@4:true"/>
<setEntry value="com.sap.sailing.geocoding@default:default"/>
<setEntry value="com.sap.sailing.grib@default:default"/>
<setEntry value="com.sap.sailing.gwt.ui@6:true"/>
<setEntry value="com.sap.sailing.hanaexport@5:true"/>
<setEntry value="com.sap.sailing.kiworesultimport@4:true"/>
<setEntry value="com.sap.sailing.landscape.common@default:default"/>
<setEntry value="com.sap.sailing.landscape.gateway@5:true"/>
<setEntry value="com.sap.sailing.landscape.ui@default:default"/>
<setEntry value="com.sap.sailing.landscape@default:default"/>
<setEntry value="com.sap.sailing.manage2sail.resultimport@4:true"/>
<setEntry value="com.sap.sailing.manage2sail@default:default"/>
<setEntry value="com.sap.sailing.monitoring@7:true"/>
<setEntry value="com.sap.sailing.news@4:true"/>
<setEntry value="com.sap.sailing.nmeaconnector@default:default"/>
<setEntry value="com.sap.sailing.polars.datamining.shared@default:default"/>
<setEntry value="com.sap.sailing.polars.datamining@5:true"/>
<setEntry value="com.sap.sailing.polars@5:true"/>
<setEntry value="com.sap.sailing.resultimport@4:true"/>
<setEntry value="com.sap.sailing.routeconverterjava11extension@default:false"/>
<setEntry value="com.sap.sailing.sailti.resultimport@4:true"/>
<setEntry value="com.sap.sailing.sailwave.resultimport@4:true"/>
<setEntry value="com.sap.sailing.server.gateway.interfaces@default:default"/>
<setEntry value="com.sap.sailing.server.gateway.serialization.shared.android@default:default"/>
<setEntry value="com.sap.sailing.server.gateway.serialization@default:default"/>
<setEntry value="com.sap.sailing.server.gateway@5:true"/>
<setEntry value="com.sap.sailing.server.interface@default:default"/>
<setEntry value="com.sap.sailing.server.trackfiles@default:default"/>
<setEntry value="com.sap.sailing.server@5:true"/>
<setEntry value="com.sap.sailing.shared.persistence@default:default"/>
<setEntry value="com.sap.sailing.shared.server.gateway@5:true"/>
<setEntry value="com.sap.sailing.shared.server@5:true"/>
<setEntry value="com.sap.sailing.simulator@default:default"/>
<setEntry value="com.sap.sailing.udpconnector@default:default"/>
<setEntry value="com.sap.sailing.velum.resultimport@4:true"/>
<setEntry value="com.sap.sailing.windestimation@5:true"/>
<setEntry value="com.sap.sailing.www@5:true"/>
<setEntry value="com.sap.sailing.xrr.resultimport@4:true"/>
<setEntry value="com.sap.sailing.xrr.schema@default:default"/>
<setEntry value="com.sap.sailing.xrr.structureimport@default:default"/>
<setEntry value="com.sap.sailing.yachtscoring.resultimport@4:true"/>
<setEntry value="com.sap.sse.common@default:default"/>
<setEntry value="com.sap.sse.datamining.annotations@default:default"/>
<setEntry value="com.sap.sse.datamining.shared@default:default"/>
<setEntry value="com.sap.sse.datamining.ui@default:default"/>
<setEntry value="com.sap.sse.datamining@default:default"/>
<setEntry value="com.sap.sse.debranding@default:default"/>
<setEntry value="com.sap.sse.filestorage@4:true"/>
<setEntry value="com.sap.sse.gwt.adminconsole@default:default"/>
<setEntry value="com.sap.sse.gwt@default:default"/>
<setEntry value="com.sap.sse.landscape.aws.common@default:default"/>
<setEntry value="com.sap.sse.landscape.aws.persistence@default:default"/>
<setEntry value="com.sap.sse.landscape.aws@4:true"/>
<setEntry value="com.sap.sse.landscape.common@default:default"/>
<setEntry value="com.sap.sse.landscape@default:default"/>
<setEntry value="com.sap.sse.mail@5:true"/>
<setEntry value="com.sap.sse.mongodb@default:default"/>
<setEntry value="com.sap.sse.operationaltransformation@default:default"/>
<setEntry value="com.sap.sse.replication.interfaces@default:default"/>
<setEntry value="com.sap.sse.replication.persistence@default:default"/>
<setEntry value="com.sap.sse.replication@6:true"/>
<setEntry value="com.sap.sse.security.common@default:default"/>
<setEntry value="com.sap.sse.security.datamining@5:true"/>
<setEntry value="com.sap.sse.security.interface@default:default"/>
<setEntry value="com.sap.sse.security.persistence@default:default"/>
<setEntry value="com.sap.sse.security.ui@6:true"/>
<setEntry value="com.sap.sse.security.userstore.mongodb@4:true"/>
<setEntry value="com.sap.sse.security@default:default"/>
<setEntry value="com.sap.sse.shared.android@default:default"/>
<setEntry value="com.sap.sse.threadmanager@default:default"/>
<setEntry value="com.sap.sse@default:default"/>
<setEntry value="com.tractrac.clientmodule@default:default"/>
<setEntry value="elemental2@default:default"/>
<setEntry value="net.sf.marineapi@default:default"/>
<setEntry value="org.json.simple@default:default"/>
<setEntry value="org.moxieapps.gwt.highcharts@default:default"/>
<setEntry value="org.mp4parser.isoparser@default:default"/>
</setAttribute>
<booleanAttribute key="show_selected_only" value="false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
@@ -1,6 +1,7 @@
package com.sap.sailing.server.impl;
import java.util.function.Supplier;
import java.util.logging.Logger;
import com.sap.sailing.domain.abstractlog.race.CompetitorResult;
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
@@ -32,7 +33,8 @@ import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
public class RaceLogScoringReplicator implements RaceColumnListenerWithDefaultAction {
private static final Logger logger = Logger.getLogger(RaceLogScoringReplicator.class.getName());
private static final long serialVersionUID = -5958519195756937338L;
private final RacingEventService service;
@@ -54,10 +56,10 @@ public class RaceLogScoringReplicator implements RaceColumnListenerWithDefaultAc
}
private void handleFinishPositioningList(RaceColumn raceColumn, RaceLogIdentifier raceLogIdentifier, RaceLogFinishPositioningConfirmedEvent event) {
Leaderboard leaderboard = service.getLeaderboardByName(raceLogIdentifier.getRegattaLikeParent().getName());
final Leaderboard leaderboard = service.getLeaderboardByName(raceLogIdentifier.getRegattaLikeParent().getName());
if (leaderboard != null) {
Fleet fleet = raceColumn.getFleetByName(raceLogIdentifier.getFleetName());
RaceLog raceLog = raceColumn.getRaceLog(fleet);
final Fleet fleet = raceColumn.getFleetByName(raceLogIdentifier.getFleetName());
final RaceLog raceLog = raceColumn.getRaceLog(fleet);
checkNeedForScoreCorrectionByResultsOfRaceCommittee(leaderboard, raceColumn, fleet, raceLog, event.getCreatedAt(), event);
}
}
@@ -122,18 +124,34 @@ public class RaceLogScoringReplicator implements RaceColumnListenerWithDefaultAc
// RaceLogFinishPositioningConfirmedEvent event was found in the race log
}
if (positioningList != null) {
boolean metadataUpdateRequired = false;
for (CompetitorResult positionedCompetitor : positioningList) {
final Competitor competitor = service.getBaseDomainFactory().getExistingCompetitorById(positionedCompetitor.getCompetitorId());
int rankByRaceCommittee = getRankInPositioningListByRaceCommittee(positionedCompetitor);
final Double preChangeTotalPoints = leaderboard.getTotalPoints(competitor, raceColumn, timePoint);
final MaxPointsReason preChangeMaxPointsReason = leaderboard.getMaxPointsReason(competitor, raceColumn, timePoint);
correctScoreInLeaderboardIfNecessary(leaderboard, raceColumn, timePoint, numberOfCompetitorsInRace, competitor,
rankByRaceCommittee, positionedCompetitor.getScore(), positionedCompetitor.getMaxPointsReason());
setMaxPointsReasonInLeaderboardIfNecessary(leaderboard, raceColumn, timePoint, positionedCompetitor.getMaxPointsReason(), competitor);
final Double postChangeTotalPoints = leaderboard.getTotalPoints(competitor, raceColumn, timePoint);
final MaxPointsReason postChangeMaxPointsReason = leaderboard.getMaxPointsReason(competitor, raceColumn, timePoint);
if (!metadataUpdateRequired &&
(!Util.equalsWithNull(postChangeTotalPoints, preChangeTotalPoints)
||
!Util.equalsWithNull(preChangeMaxPointsReason, postChangeMaxPointsReason))) {
logger.info("Found at least one score correction change in leaderboard "+leaderboard.getName()+
" for competitor "+competitor.getName()+" in race column "+raceColumn.getName()+
". Updating comment and time of last correction.");
metadataUpdateRequired = true;
}
}
// Update the metadata only if it is newer than any previous score correction update.
// This helps if "mechanical" updates are received out of order and will converge towards
// the latest update time point:
if (leaderboard.getScoreCorrection().getTimePointOfLastCorrectionsValidity() == null ||
(timePoint != null && leaderboard.getScoreCorrection().getTimePointOfLastCorrectionsValidity().before(timePoint))) {
if (metadataUpdateRequired
&& (leaderboard.getScoreCorrection().getTimePointOfLastCorrectionsValidity() == null
|| (timePoint != null && leaderboard.getScoreCorrection()
.getTimePointOfLastCorrectionsValidity().before(timePoint)))) {
// Since the metadata update is used by the Sailing suite to determine the final state of a race, it has to
// be triggered, even though no score correction may have been performed
String comment = LeaderboardNameConstants.DEFAULT_FLEET_NAME.equals(fleet.getName())
@@ -6,6 +6,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.util.Map;
import java.util.Optional;
import org.json.simple.parser.ParseException;
@@ -26,7 +27,7 @@ public class WindEstimationDataClientMock extends WindEstimationDataClient {
public WindEstimationDataClientMock(ModelStore modelStore,
ReplicableWindEstimationFactoryService windEstimationFactoryService) {
super(null, windEstimationFactoryService);
super(null, windEstimationFactoryService, /* windEstimationModelBearerToken */ Optional.empty());
this.modelStore = modelStore;
}
@@ -3,6 +3,7 @@ package com.sap.sailing.windestimation.integration;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -52,6 +53,14 @@ public class Activator implements BundleActivator {
* file system that contains serialized model files to load.
*/
private static final String WIND_ESTIMATION_MODEL_DATA_SOURCE_FOLDER_PROPERTY_NAME = "windestimation.source.folder";
/**
* If a system property with this name is provided, the property value will be used as a bearer token in an HTTP
* header <tt>Authorization: Bearer ...</tt> to authenticate the request fetching the wind estimation data from the
* URL specified in either the {@link #WIND_ESTIMATION_MODEL_DATA_SOURCE_URL_PROPERTY_NAME} or the
* {@link #WIND_ESTIMATION_MODEL_DATA_SOURCE_ALWAYS_URL_PROPERTY_NAME} property.
*/
private static final String WIND_ESTIMATION_MODEL_BEARER_TOKEN_PROPERTY_NAME = "windestimation.source.bearertoken";
private final Set<ServiceRegistration<?>> registrations = new HashSet<>();
@@ -72,6 +81,8 @@ public class Activator implements BundleActivator {
.getProperty(WIND_ESTIMATION_MODEL_DATA_SOURCE_ALWAYS_URL_PROPERTY_NAME);
final String windEstimationModelDataSourceFolder = System
.getProperty(WIND_ESTIMATION_MODEL_DATA_SOURCE_FOLDER_PROPERTY_NAME);
final String windEstimationModelBearerToken = System
.getProperty(WIND_ESTIMATION_MODEL_BEARER_TOKEN_PROPERTY_NAME);
int loadFromCount = (windEstimationModelDataSourceURL != null ? 1 : 0) +
(windEstimationModelDataSourceAlwaysURL != null ? 1 : 0) +
(windEstimationModelDataSourceFolder != null ? 1 : 0);
@@ -82,9 +93,9 @@ public class Activator implements BundleActivator {
+ WIND_ESTIMATION_MODEL_DATA_SOURCE_FOLDER_PROPERTY_NAME + "\"");
}
if (windEstimationModelDataSourceURL != null && !service.isReady()) {
importWindEstimationModelsFromUrl(windEstimationModelDataSourceURL);
importWindEstimationModelsFromUrl(windEstimationModelDataSourceURL, Optional.ofNullable(windEstimationModelBearerToken));
} else if (windEstimationModelDataSourceAlwaysURL != null) {
importWindEstimationModelsFromUrl(windEstimationModelDataSourceAlwaysURL);
importWindEstimationModelsFromUrl(windEstimationModelDataSourceAlwaysURL, Optional.ofNullable(windEstimationModelBearerToken));
} else if (windEstimationModelDataSourceFolder != null) {
importWindEstimationModelsFromFolder(windEstimationModelDataSourceFolder);
}
@@ -117,10 +128,15 @@ public class Activator implements BundleActivator {
}
}
private void importWindEstimationModelsFromUrl(String windEstimationModelDataSourceURL) {
/**
* @param windEstimationModelBearerToken
* if present, this bearer token will be used to authenticate the request for the wind estimation model
* data
*/
private void importWindEstimationModelsFromUrl(String windEstimationModelDataSourceURL, Optional<String> windEstimationModelBearerToken) {
logger.info("Importing wind estimation data from URL: " + windEstimationModelDataSourceURL);
WindEstimationDataClient windEstimationDataClient = new WindEstimationDataClient(
windEstimationModelDataSourceURL, service);
windEstimationModelDataSourceURL, service, windEstimationModelBearerToken);
try {
windEstimationDataClient.updateWindEstimationModels();
} catch (Exception e) {
@@ -43,6 +43,8 @@ public class WindEstimationDataResource extends AbstractWindEstimationDataResour
logger.info("Wind Estimation Model Data requested by "+
(subject.getPrincipal() == null ? "anonymous user" :
subject.getPrincipal().toString()));
subject.checkPermission(SecuredDomainType.WIND_ESTIMATION_MODELS.getStringPermissionForTypeRelativeIdentifier(
DefaultActions.READ, new TypeRelativeObjectIdentifier(ServerInfo.getName())));
return Response.ok(new StreamingOutput() {
@Override
public void write(OutputStream output) throws IOException, WebApplicationException {
@@ -2,6 +2,7 @@ package com.sap.sailing.windestimation.jaxrs.client;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -29,11 +30,13 @@ public class WindEstimationDataClient {
private final ReplicableWindEstimationFactoryService windEstimationFactoryService;
private final String windEstimationDataSourceURL;
private final Optional<String> windEstimationModelBearerToken;
public WindEstimationDataClient(String windEstimationDataSourceURL,
ReplicableWindEstimationFactoryService windEstimationFactoryService) {
ReplicableWindEstimationFactoryService windEstimationFactoryService, Optional<String> windEstimationModelBearerToken) {
this.windEstimationFactoryService = windEstimationFactoryService;
this.windEstimationDataSourceURL = windEstimationDataSourceURL;
this.windEstimationModelBearerToken = windEstimationModelBearerToken;
}
/**
@@ -62,9 +65,14 @@ public class WindEstimationDataClient {
}
protected InputStream getContentFromResponse() throws IOException, ParseException {
HttpClient client = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategyForAllRedirectResponseCodes()).build();
HttpGet getProcessor = new HttpGet(getAPIString());
HttpResponse processorResponse = client.execute(getProcessor);
final HttpClient client = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategyForAllRedirectResponseCodes()).build();
final HttpGet getProcessor = new HttpGet(getAPIString());
windEstimationModelBearerToken.ifPresent(bearerToken -> getProcessor.setHeader("Authorization", "Bearer " + bearerToken));
final HttpResponse processorResponse = client.execute(getProcessor);
if (processorResponse.getStatusLine().getStatusCode() >= 300) {
throw new IOException("Error trying to load wind estimation data from "+getAPIString()+": "
+processorResponse.getStatusLine().getReasonPhrase()+" ("+processorResponse.getStatusLine().getStatusCode()+")");
}
return processorResponse.getEntity().getContent();
}
@@ -23,6 +23,25 @@
<div class="mainContent">
<h2 class="releaseHeadline">Release Notes - Administration Console</h2>
<div class="innerContent">
<h2 class="articleSubheadline">May 2024</h2>
<ul class="bulletList">
<li>Reading the wind estimation data from a server during start-up, using the
<tt>windestimation.source.url</tt> system property, now requires authentication.
The <tt>java/target/start</tt> script now reads the <tt>WINDESTIMATION_BEARER_TOKEN</tt>
variable and passes it as the <tt>windestimation.source.bearertoken</tt> system property
to the application. The user authenticated by that token must have the
<tt>WIND_ESTIMATION_MODELS:READ</tt> permission for the server identified by the
URL provided in the <tt>windestimation.source.url</tt> property, for example
<tt>WIND_ESTIMATION_MODELS:READ:ARCHIVE</tt> if the URL is <tt>https://sapsailing.com</tt></li>
<li>Reading the polar data from a server during start-up, using the
<tt>polardata.source.url</tt> system property, now requires authentication.
The <tt>java/target/start</tt> script now reads the <tt>POLAR_DATA_BEARER_TOKEN</tt>
variable and passes it as the <tt>polardata.source.bearertoken</tt> system property
to the application. The user authenticated by that token must have the
<tt>POLAR_DATA:READ</tt> permission for the server identified by the
URL provided in the <tt>polardata.source.url</tt> property, for example
<tt>POLAR_DATA:READ:ARCHIVE</tt> if the URL is <tt>https://sapsailing.com</tt></li>
</ul>
<h2 class="articleSubheadline">April 2024</h2>
<ul class="bulletList">
<li>The TracTrac connector now pools and re-uses event subscriber threads for live connections
@@ -33,6 +52,18 @@
both, mark and race, specify one. This way, redundant and excessive mark fixes can be avoided,
don't consume extra memory and don't waste replication bandwidth. See also
<a href="https://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=5919">bug 5919</a>.</li>
<li>Fixed file upload for Chrome browsers after Chrome made an incompatible change, appending
a combination of <tt>&lt;div&gt;</tt> tags after the already <tt>&lt;pre&gt;</tt>-enclosed
form submission completion payload.</li>
<li>The TracTrac connector will no longer disconnect from a race when it is abandoned. It is now
assumed the race will be re-sailed, and so the connector will keep tracking the race.</li>
<li>Fixed handling of <tt>null</tt> values in "compareservers" end point.</li>
<li>Upgraded to TracAPI 3.15.7, fixing an issue with static mark positions not transmitted during live races.</li>
<li>The LOW_POINT_WITH_ELIMINATING_MEDAL_SERIES_PROMOTING_ONE_TO_FINAL_AND_TWO_TO_SEMIFINAL scoring scheme,
as used typically for iQFOil formats with quarter/semi/grand finals, now does no longer require explicit
column factors of 1.0 for those medal-series race columns. The medal series-based doubling is deactivated
now for this scoring scheme. Should you have relied on this scheme doubling your medal series scores,
you now have to adjust the column factors for those race columns to 2.0 explicitly.</li>
</ul>
<h2 class="articleSubheadline">March 2024</h2>
<ul class="bulletList">
@@ -0,0 +1,72 @@
package com.sap.sse.common.fileupload;
import com.sap.sse.common.Base64Utils;
/**
* Helper class used in conjunction with {@code AbstractFileUploadServlet} and its sub-classes which assume to be
* servlets targeted by file upload forms, returning a JSON payload embedded in an HTML document's body. This class
* has static helper methods that allow the servlet to {@link #getHtmlWithEmbeddedJsonContent(String) embed/encode}
* and the client to {@link #getApplicationJsonContentFromHtml(String) extract/decode} the JSON payload
* embedded in the servlet response's HTML document.
* <p>
*
* For file uploads through {@link FormPanel} elements, if the response is a JSON message (content type
* {@code application/json}) then the way the {@link FormPanel} intercepts this response (namely through an auxiliary
* {@code iframe} element into which the response is loaded) the content may get wrapped by a combination of {@code <pre>}
* and {@code </pre>} elements. In newer Chrome versions as of around 2024-04-15, additional {@code <div>} elements may be found after
* the closing {@code </pre>} tag. These elements persist through the {@link SubmitCompleteEvent#getResults()} method,
* and hence must be stripped off before trying to parse the results as JSON. This is what
* {@link #getApplicationJsonContentFromHtml(String)} does.
* <p>
*
* The background is described also in bugs 5992 and bug 5127 (especially comment #44).
*
* @author Axel Uhl (d043530)
*
*/
public class FileUploadUtil {
private final static String EMBEDDING_TAG = "div";
// use an all lower-case attribute name because along the channel, HMTL content may be normalized
private final static String PAYLOAD_ATTRIBUTE_NAME = "jsonpayloadasbase64";
/**
* Decodes a JSON {@link String} from an HTML document's {@code body} element that has
* been produced from such a JSON string using the {@link #getHtmlWithEmbeddedJsonContent(String)}
* method.
*/
public static String getApplicationJsonContentFromHtml(final String resultHtml) {
final String base64EncodedJsonPayload = resultHtml.replaceFirst("^.*<"+EMBEDDING_TAG+" *"+PAYLOAD_ATTRIBUTE_NAME+"=\"([^\"]*)\"></"+EMBEDDING_TAG+">.*$", "$1");
return new String(Base64Utils.fromBase64(base64EncodedJsonPayload));
}
/**
* Embeds a JSON payload {@link String} in an HTML {@code body} element such that the resulting document is robust
* against browser normalization, such as case changes in element and attribute names, or document adjustments for
* display purposes. The JSON payload can be extracted from the resulting HTML string using the
* {@link #getApplicationJsonContentFromHtml(String)} method.
* <p>
*
* In particular, the following expression is always {@code true} for any non-{@code null} {@link String}
* {@code json}:
* <p>
*
* {@code json.equals(}{@link #getApplicationJsonContentFromHtml(String)
* getApplicationJsonContentFromHtml(}{@link #getHtmlWithEmbeddedJsonContent(String)
* getHtmlWithEmbeddedJsonContent(json)))}
* <p>
*
* Servlets using this method shall declare their response content type as "text/html" so that at most HTML
* normalization would take place en-route.
*
* @param json
* a non-{@code null} {@link String} that will be encoded safely into an HTML document body's contents so
* that it survives normalization and potentially enclosing into other tags and the pre-pending and
* appending of other tags to the content.
* @return an HTML string whose top-level element is a {@code body} element containing the safely-encoded payload
* which can be decoded again using the {@link #getApplicationJsonContentFromHtml(String)} method.
*/
public static String getHtmlWithEmbeddedJsonContent(final String json) {
return "<body><"+EMBEDDING_TAG+" "+PAYLOAD_ATTRIBUTE_NAME+"=\""+Base64Utils.toBase64(json.getBytes())+"\"></"+EMBEDDING_TAG+"></body>";
}
}
@@ -38,9 +38,9 @@ import com.google.gwt.user.client.ui.SubmitButton;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.sap.sse.common.fileupload.FileUploadConstants;
import com.sap.sse.common.fileupload.FileUploadUtil;
import com.sap.sse.gwt.client.Notification;
import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.client.fileupload.FileUploadUtil;
/**
* A {@link TextBox} together with an upload button that can use the file storage service to
@@ -175,7 +175,7 @@ public class URLFieldWithFileUpload extends Composite implements HasValue<Map<St
}
selectUploadButton.removeStyleName(RESOURCES.urlFieldWithFileUploadStyle().loadingClass());
endUploadEvent.endUpload();
JSONArray resultJson = JSONParser.parseStrict(FileUploadUtil.getApplicationJsonContent(event)).isArray();
JSONArray resultJson = JSONParser.parseStrict(FileUploadUtil.getApplicationJsonContentFromHtml(event.getResults())).isArray();
if (resultJson != null) {
Map<String, String> uris = new HashMap<>(resultJson.size());
List<String> titleStrings = new ArrayList<>(resultJson.size());
@@ -1,22 +0,0 @@
package com.sap.sse.gwt.client.fileupload;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteEvent;
public class FileUploadUtil {
/**
* For file uploads through {@link FormPanel} elements, if the response is a JSON message (content type
* {@code application/json}) then the way the {@link FormPanel} intercepts this response (namely through
* an auxiliary {@code iframe} element into which the response is loaded) the content may get wrapped by
* a combination of {@code <pre>} and {@code </pre>} elements. These elements persist through the
* {@link SubmitCompleteEvent#getResults()} method, and hence must be stripped off before trying to
* parse the results as JSON. This is that this method does.<p>
*
* Conversely, trying to use {@code text/html} as content encoding leads some
* browsers---especially on mobile devices---to do ugly things to the content returned, such as replacing digit
* sequences by a corresponding {@code <a>} element that allows the user to dial that number with the phone app...
*/
public static String getApplicationJsonContent(SubmitCompleteEvent submitResultWithApplicationJsonContent) {
return submitResultWithApplicationJsonContent.getResults().replaceFirst("<pre[^>]*>(.*)</pre>", "$1");
}
}
@@ -8,34 +8,5 @@
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>com.sap.sse.landscape.aws.test</artifactId>
<packaging>eclipse-plugin</packaging>
<!-- Enable the following if there is a valid AWS SDK key available in the test execution environment:
<packaging>eclipse-test-plugin</packaging>
-->
<properties>
<tycho.plugin-test.skip>true</tycho.plugin-test.skip>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-surefire-plugin</artifactId>
<version>${tycho-version}</version>
<configuration>
<excludes>
<test>**/*</test>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -24,6 +24,7 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import com.jcraft.jsch.ChannelSftp;
@@ -87,6 +88,7 @@ import software.amazon.awssdk.services.sts.model.Credentials;
* @author Axel Uhl (D043530)
*
*/
@Ignore("Needs AWS key ID, key secret and session token in system properties")
public class ConnectivityTest<ProcessT extends AwsApplicationProcess<String, SailingAnalyticsMetrics, ProcessT>> {
private static final Logger logger = Logger.getLogger(ConnectivityTest.class.getName());
private static final Optional<Duration> optionalTimeout = Optional.of(Duration.ONE_MINUTE.times(10));
@@ -13,6 +13,7 @@ import java.util.Random;
import org.bson.Document;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.Mockito;
@@ -26,6 +27,7 @@ import com.sap.sse.landscape.mongodb.impl.MongoProcessImpl;
import com.sap.sse.landscape.mongodb.impl.MongoProcessInReplicaSetImpl;
import com.sap.sse.landscape.mongodb.impl.MongoReplicaSetImpl;
@Ignore("Needs a specific MongoDB replica set named 'rs0' in the environment")
public class MongoTests {
private static final Optional<Duration> optionalTimeout = Optional.of(Duration.ONE_MINUTE.times(5));
@@ -25,7 +25,7 @@ import com.sap.sse.landscape.mongodb.MongoProcessInReplicaSet;
import com.sap.sse.landscape.mongodb.MongoReplicaSet;
public class MongoUriParserTest {
private static final String WWW_EXAMPLE_COM = "www.example.com";
private static final String WWW_EXAMPLE_COM = "127.0.0.2";
private MongoUriParser<String> parser;
@SuppressWarnings("unchecked")
@@ -36,7 +36,7 @@ public class MongoUriParserTest {
final AwsInstance<String> host1 = mock(AwsInstance.class);
when(host1.getPublicAddress()).thenReturn(wwwExampleCom);
when(host1.getPrivateAddress()).thenReturn(wwwExampleCom);
when(landscape.getHostByPublicIpAddress(ArgumentMatchers.any(Region.class), ArgumentMatchers.contains(wwwExampleCom.getHostAddress()), ArgumentMatchers.any(HostSupplier.class))).thenReturn(host1);
when(landscape.getHostByPrivateIpAddress(ArgumentMatchers.any(Region.class), ArgumentMatchers.contains(wwwExampleCom.getHostAddress()), ArgumentMatchers.any(HostSupplier.class))).thenReturn(host1);
final InetAddress loopback = InetAddress.getLoopbackAddress();
final AwsInstance<String> host2 = mock(AwsInstance.class);
when(host2.getPrivateAddress()).thenReturn(loopback);
@@ -46,25 +46,25 @@ public class MongoUriParserTest {
@Test
public void testSimpleSingleNodeUri() throws URISyntaxException, UnknownHostException {
final String hostname = WWW_EXAMPLE_COM;
final String hostname = "127.0.0.1";
final String dbName = "myDb";
final Database database = parser.parseMongoUri("mongodb://"+hostname+"/"+dbName);
assertFalse(database.getEndpoint().isReplicaSet());
final MongoProcess mongoProcess = database.getEndpoint().asMongoProcess();
assertEquals(InetAddress.getByName(WWW_EXAMPLE_COM).getHostAddress(), mongoProcess.getHostname());
assertEquals(hostname, mongoProcess.getHostname());
assertEquals(27017, mongoProcess.getPort());
assertEquals(dbName, database.getName());
}
@Test
public void testSimpleSingleNodeUriWithExplicitPort() throws URISyntaxException, UnknownHostException {
final String hostname = WWW_EXAMPLE_COM;
final String hostname = "127.0.0.1";
final int port = 10202;
final String dbName = "myDb";
final Database database = parser.parseMongoUri("mongodb://"+hostname+":"+port+"/"+dbName);
assertFalse(database.getEndpoint().isReplicaSet());
final MongoProcess mongoProcess = database.getEndpoint().asMongoProcess();
assertEquals(InetAddress.getByName(WWW_EXAMPLE_COM).getHostAddress(), mongoProcess.getHostname());
assertEquals(InetAddress.getByName(hostname).getHostAddress(), mongoProcess.getHostname());
assertEquals(port, mongoProcess.getPort());
assertEquals(dbName, database.getName());
}
@@ -0,0 +1,25 @@
package com.sap.sse.landscape.aws.impl;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import com.sap.sse.landscape.application.ApplicationProcess;
import com.sap.sse.landscape.application.ApplicationProcessMetrics;
import com.sap.sse.landscape.aws.ReverseProxy;
public class ReverseProxyTargetGroupHealthCheckPathTest {
private final static String TARGET_GROUP_ARN = "arn:aws:elasticloadbalancing:eu-west-1:017363970217:targetgroup/S-BYC-m/141f1fbae1ac783f";
@Test
public void testHealthCheckPath() {
final String healthCheckPath = String.format(AbstractApacheReverseProxy.TARGET_GROUP_STATUS, TARGET_GROUP_ARN);
assertTrue(healthCheckPath.endsWith("?arn="+TARGET_GROUP_ARN));
}
@Test
public <ApplicationProcessT extends ApplicationProcess<String, ApplicationProcessMetrics, ApplicationProcessT>> void testHealthCheckPathOnReverseProxy() {
final ReverseProxy<?, ?, ?, ?> reverseProxy = new ApacheReverseProxy<String, ApplicationProcessMetrics, ApplicationProcessT>(null, null);
assertTrue(reverseProxy.getTargetGroupHealthCheckPath(TARGET_GROUP_ARN).endsWith("?arn="+TARGET_GROUP_ARN));
}
}
@@ -110,5 +110,18 @@ public interface ReverseProxy<ShardingKey, MetricsT extends ApplicationProcessMe
*/
void terminate();
/**
* Gets the basic path that will indicate the health of a reverse proxy.
*/
String getHealthCheckPath();
/**
* Gets the health check path that should be used by a target group, containing only reverse proxies.
*
* @param targetGroupArn
* identifies the target group expected to run the health check; this can be used to construct a URL path
* and health check that is aware of this target group and may, e.g., take into account the set of its
* member instances and their availability zones.
*/
String getTargetGroupHealthCheckPath(String targetGroupArn);
}
@@ -12,7 +12,8 @@ implements ReverseProxy<ShardingKey, MetricsT, ProcessT, RotatingFileBasedLog> {
/**
* The path the target group will ping to check the health of the reverse proxy.
*/
protected static final String INTERNAL_SERVER_STATUS = "cgi-bin/reverseProxyHealthcheck.sh";
protected static final String INTERNAL_SERVER_STATUS = "internal-server-status";
protected static final String TARGET_GROUP_STATUS = "cgi-bin/reverseProxyHealthcheck.sh?arn=%s";
private final AwsLandscape<ShardingKey> landscape;
public AbstractApacheReverseProxy(AwsLandscape<ShardingKey> landscape) {
@@ -25,6 +26,11 @@ implements ReverseProxy<ShardingKey, MetricsT, ProcessT, RotatingFileBasedLog> {
@Override
public String getHealthCheckPath() {
return "/"+INTERNAL_SERVER_STATUS;
return "/" + INTERNAL_SERVER_STATUS;
}
@Override
public String getTargetGroupHealthCheckPath(String targetGroupArn) {
return "/" + String.format(TARGET_GROUP_STATUS, targetGroupArn);
}
}
@@ -155,6 +155,7 @@ import software.amazon.awssdk.services.elasticloadbalancingv2.model.LoadBalancer
import software.amazon.awssdk.services.elasticloadbalancingv2.model.LoadBalancerState;
import software.amazon.awssdk.services.elasticloadbalancingv2.model.ModifyRuleResponse;
import software.amazon.awssdk.services.elasticloadbalancingv2.model.ModifyTargetGroupAttributesRequest;
import software.amazon.awssdk.services.elasticloadbalancingv2.model.ModifyTargetGroupRequest;
import software.amazon.awssdk.services.elasticloadbalancingv2.model.ProtocolEnum;
import software.amazon.awssdk.services.elasticloadbalancingv2.model.RedirectActionStatusCodeEnum;
import software.amazon.awssdk.services.elasticloadbalancingv2.model.Rule;
@@ -405,6 +406,7 @@ public class AwsLandscapeImpl<ShardingKey> implements AwsLandscape<ShardingKey>
tagKeyandValue.put(LandscapeConstants.ALL_REVERSE_PROXIES, "");
final TargetGroup<ShardingKey> defaultTargetGroup = createTargetGroup(alb.getRegion(), DEFAULT_TARGET_GROUP_PREFIX + alb.getName() + "-" + ProtocolEnum.HTTP.name(),
httpPort, reverseProxy.getHealthCheckPath(), /* healthCheckPort */ httpPort, alb.getArn(), alb.getVpcId(), tagKeyandValue);
setTargetGroupHealthCheckPath(defaultTargetGroup, reverseProxy.getTargetGroupHealthCheckPath(defaultTargetGroup.getTargetGroupArn()));
defaultTargetGroup.addTargets(reverseProxy.getHosts());
final String defaultCertificateArn = defaultCertificateArnFuture.get();
return getLoadBalancingClient(getRegion(alb.getRegion()))
@@ -1225,7 +1227,17 @@ public class AwsLandscapeImpl<ShardingKey> implements AwsLandscape<ShardingKey>
}
});
}
/**
* Adjusts the health check path of an existing target group. Note that this will make the {@link TargetGroup} object passed as
* the {@code targetGroup} parameter inconsistent in its {@link TargetGroup#getHealthCheckPath()} field which does not reflect the
* new value set here.
*/
private void setTargetGroupHealthCheckPath(TargetGroup<ShardingKey> targetGroup, String path) {
getLoadBalancingClient(getRegion(targetGroup.getRegion())).modifyTargetGroup(ModifyTargetGroupRequest.builder()
.targetGroupArn(targetGroup.getTargetGroupArn()).healthCheckPath(path).build());
}
@Override
public void addTargetsToTargetGroup(
TargetGroup<ShardingKey> targetGroup,
@@ -40,7 +40,7 @@ public class RabbitInputStreamProvider extends NamedImpl {
clientReadsFromThis = new PipedInputStream(messagesAreWrittenToThis);
final QueueingConsumer messageConsumer = new QueueingConsumer(channel);
channel.basicConsume(queueName, /* auto-ack */ true, messageConsumer);
new Thread() {
new Thread(getClass().getSimpleName()) {
@Override
public void run() {
while (true) {
@@ -147,7 +147,7 @@ public class ReplicationServlet extends AbstractHttpServlet {
try {
replicable.serializeForInitialReplication(compressingOutputStream);
logger.info("Done serializing initial load for replicable "+replicableIdAsString+" for remote host "+req.getRemoteHost());
} catch (Exception e) {
} catch (Throwable e) {
logger.info("Error trying to serialize initial load for replication: " + e.getMessage());
logger.log(Level.SEVERE, "doGet", e);
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: TracTrac Client module
Bundle-SymbolicName: com.tractrac.clientmodule
Bundle-Version: 3.15.3
Bundle-Version: 3.15.7
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ClassPath: .,
lib/TracAPI.jar
+69
View File
@@ -15,6 +15,75 @@ It contains also some files:
- test.sh -> script that compiles the code in the src folder, creates the test.jar library and execute the code of the example.
- Manifest.txt -> manifest used to create the test.jar file
********************************************
TracAPI 3.15.7
********************************************
This is a final version. It keeps the backward compatibility.
Release date: 23/04/2024
1) Bugs
- When a new static mark is created, the library only sends a updateControlPointPosition callback using the event start time,
that is outside the race bounds. Now, it is calling updateControlPointPosition twice and in the second call uses the
tracking start time as the position time (Reported by Axel Uhl, 23/04/2024)
********************************************
TracAPI 3.15.6
********************************************
This is a final version. It keeps the backward compatibility.
Release date: 17/04/2024
1) Bugs
- There are some threads that are not killed when the connection is closed. These threads were added to collect
statistics but this feature make not sense in TracAPI. (Reported by Axel Uhl, 17/04/2024)
********************************************
TracAPI 3.15.5
********************************************
This is a final version. It keeps the backward compatibility.
Release date: 17/04/2024
1) Bugs
- Deadlock when a connection was closed by the server and the client called the IRaceSubscriber.stop method. (Reported by
Axel Uhl, 16/04/2024)
********************************************
TracAPI 3.15.4
********************************************
This is a final version. It keeps the backward compatibility.
Release date: 16/04/2024
1) Features
- Formatting the code using blank spaces (instead of tabs). The workspace was already configured like this,
but the old files kept some tabs. All the code has been formatted again. (Requested by Axel Uhl, 19/02/2024)
2) Bugs
- When the IRaceSubscriber.stop method is called, the library doesn't close the connection. (Reported by Axel Uhl, 03/04/2024)
- Improving the detection of a dead connection. (Reported by Axel Uhl, 03/04/2024)
********************************************
TracAPI 3.15.3
********************************************
This is a final version. It keeps the backward compatibility.
Release date: 11/03/2024
1) Feature
- Adding the method IPosition.getRTKStatus used to get the RTK status (Requested by Chris Terkelsen, 07/03/2024)
2) Bugs
- Some socket connections were not closed correctly (Reported by Jorge Piera, 08/03/2024)
********************************************
TracAPI 3.15.2
********************************************
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:37 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>All Classes (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>All Classes (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
<script type="text/javascript" src="script.js"></script>
</head>
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:37 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>All Classes (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>All Classes (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
<script type="text/javascript" src="script.js"></script>
</head>
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:36 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>IIdentifiable (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>IIdentifiable (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="IIdentifiable (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="IIdentifiable (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:36 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>INamed (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>INamed (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="INamed (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="INamed (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -113,7 +113,7 @@ var activeTableTab = "activeTableTab";
<pre>public interface <span class="typeNameLabel">INamed</span>
extends <a href="../../../../../com/tractrac/model/lib/api/IIdentifiable.html" title="interface in com.tractrac.model.lib.api">IIdentifiable</a></pre>
<div class="block">Defines a method to get the name of an entity.
<p>
It is assumed that a named entity also has an Id, hence it extends
<a href="../../../../../com/tractrac/model/lib/api/IIdentifiable.html" title="interface in com.tractrac.model.lib.api"><code>IIdentifiable</code></a></div>
<dl>
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:36 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ModelLocator (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>ModelLocator (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="ModelLocator (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="ModelLocator (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -134,10 +134,10 @@ extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html
<dd><a href="mailto:jorge@tractrac.dk">Jorge Piera Llodr&aacute;</a></dd>
<dt><span class="seeLabel">See Also:</span></dt>
<dd><a
href="http://en.wikipedia.org/wiki/Service_locator_pattern">Locator</a>,
href="http://en.wikipedia.org/wiki/Service_locator_pattern">Locator</a>,
<a
href="http://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html">Service
Loader</a></dd>
href="http://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html">Service
Loader</a></dd>
</dl>
</li>
</ul>
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:36 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>AbstractAttachable (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>AbstractAttachable (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="AbstractAttachable (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="AbstractAttachable (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:36 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>IAttachable (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>IAttachable (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="IAttachable (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="IAttachable (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:36 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>IAttachmentKey (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>IAttachmentKey (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="IAttachmentKey (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="IAttachmentKey (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:36 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>IAttachmentManager (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>IAttachmentManager (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="IAttachmentManager (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="IAttachmentManager (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -179,7 +179,7 @@ extends com.tractrac.common.lib.api.service.IServiceProvider</pre>
<dd><code>description</code> - a description for the attachment</dd>
<dt><span class="returnLabel">Returns:</span></dt>
<dd>a key that is used to attach an object to the <a href="../../../../../../com/tractrac/model/lib/api/attachment/IAttachable.html" title="interface in com.tractrac.model.lib.api.attachment"><code>IAttachable</code></a>
class.</dd>
class.</dd>
</dl>
</li>
</ul>
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:37 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Uses of Class com.tractrac.model.lib.api.attachment.AbstractAttachable (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>Uses of Class com.tractrac.model.lib.api.attachment.AbstractAttachable (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="Uses of Class com.tractrac.model.lib.api.attachment.AbstractAttachable (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="Uses of Class com.tractrac.model.lib.api.attachment.AbstractAttachable (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:37 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Uses of Interface com.tractrac.model.lib.api.attachment.IAttachable (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>Uses of Interface com.tractrac.model.lib.api.attachment.IAttachable (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="Uses of Interface com.tractrac.model.lib.api.attachment.IAttachable (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="Uses of Interface com.tractrac.model.lib.api.attachment.IAttachable (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:37 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Uses of Interface com.tractrac.model.lib.api.attachment.IAttachmentKey (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>Uses of Interface com.tractrac.model.lib.api.attachment.IAttachmentKey (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="Uses of Interface com.tractrac.model.lib.api.attachment.IAttachmentKey (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="Uses of Interface com.tractrac.model.lib.api.attachment.IAttachmentKey (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:37 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Uses of Interface com.tractrac.model.lib.api.attachment.IAttachmentManager (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>Uses of Interface com.tractrac.model.lib.api.attachment.IAttachmentManager (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="Uses of Interface com.tractrac.model.lib.api.attachment.IAttachmentManager (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="Uses of Interface com.tractrac.model.lib.api.attachment.IAttachmentManager (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:37 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>com.tractrac.model.lib.api.attachment (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>com.tractrac.model.lib.api.attachment (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../script.js"></script>
</head>
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:37 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>com.tractrac.model.lib.api.attachment (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>com.tractrac.model.lib.api.attachment (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="com.tractrac.model.lib.api.attachment (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="com.tractrac.model.lib.api.attachment (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:37 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>com.tractrac.model.lib.api.attachment Class Hierarchy (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>com.tractrac.model.lib.api.attachment Class Hierarchy (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="com.tractrac.model.lib.api.attachment Class Hierarchy (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="com.tractrac.model.lib.api.attachment Class Hierarchy (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:37 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Uses of Package com.tractrac.model.lib.api.attachment (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>Uses of Package com.tractrac.model.lib.api.attachment (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="Uses of Package com.tractrac.model.lib.api.attachment (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="Uses of Package com.tractrac.model.lib.api.attachment (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:37 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Uses of Interface com.tractrac.model.lib.api.IIdentifiable (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>Uses of Interface com.tractrac.model.lib.api.IIdentifiable (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="Uses of Interface com.tractrac.model.lib.api.IIdentifiable (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="Uses of Interface com.tractrac.model.lib.api.IIdentifiable (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:37 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Uses of Interface com.tractrac.model.lib.api.INamed (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>Uses of Interface com.tractrac.model.lib.api.INamed (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="Uses of Interface com.tractrac.model.lib.api.INamed (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="Uses of Interface com.tractrac.model.lib.api.INamed (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:37 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Uses of Class com.tractrac.model.lib.api.ModelLocator (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>Uses of Class com.tractrac.model.lib.api.ModelLocator (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="Uses of Class com.tractrac.model.lib.api.ModelLocator (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="Uses of Class com.tractrac.model.lib.api.ModelLocator (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:36 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>IControlPassing (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>IControlPassing (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="IControlPassing (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="IControlPassing (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:36 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>IControlPassings (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>IControlPassings (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="IControlPassings (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="IControlPassings (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:36 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>IMessageData (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>IMessageData (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="IMessageData (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="IMessageData (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:36 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>IPosition (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>IPosition (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="IPosition (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="IPosition (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -119,7 +119,7 @@ extends <a href="../../../../../../com/tractrac/model/lib/api/spatial/IGeoCoordi
<p>
The position is in the WGS84 coordinate frame.
</p>
<p>
TODO: Should it instead return an ICoordinate? That would make it possible to
work in geographical coordinates as well as projected coordinates directly,
not having to store both.</div>
@@ -293,7 +293,7 @@ extends <a href="../../../../../../com/tractrac/model/lib/api/spatial/IGeoCoordi
<h4>getDirection</h4>
<pre>double&nbsp;getDirection()</pre>
<div class="block">Returns the direction of the carrier at the time of the position.
<p>
The direction is the 360 degree compass heading, i.e. 0 when the carrier is
travelling directly north and 90 when the carrier is travelling directly
east.</div>
@@ -328,7 +328,7 @@ extends <a href="../../../../../../com/tractrac/model/lib/api/spatial/IGeoCoordi
<div class="block">Gets the status of the RTK connection.
Each bit means:
<lu>
<li>bit 0</li>
<li>bit 0</li>
<ul>
<li>0: correction server not connected</li>
<li>1: correction server connected</li>
@@ -434,7 +434,7 @@ extends <a href="../../../../../../com/tractrac/model/lib/api/spatial/IGeoCoordi
<pre>boolean&nbsp;isGPSTiming()</pre>
<div class="block">Returns if the time stamp has been retrieved from a GPS device. If not,
the GPS time is an estimation.
<p>
e.g: the static positions use the event start time and the positions from
the parameters file use the tracking start time. These two types of positions
use a time stamp that has not been retrieved from a GPS device.</div>
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:36 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>IPositionFactory (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>IPositionFactory (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="IPositionFactory (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="IPositionFactory (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
@@ -117,7 +117,7 @@ extends com.tractrac.common.lib.api.service.IServiceProvider</pre>
<dd><a href="mailto:jorge@tractrac.dk">Jorge Piera Llodr&aacute;</a></dd>
<dt><span class="seeLabel">See Also:</span></dt>
<dd><a
href="http://en.wikipedia.org/wiki/Factory_method_pattern">Factory</a></dd>
href="http://en.wikipedia.org/wiki/Factory_method_pattern">Factory</a></dd>
</dl>
</li>
</ul>
@@ -2,10 +2,10 @@
<!-- NewPage -->
<html lang="en">
<head>
<!-- Generated by javadoc (1.8.0_392) on Tue Mar 12 06:39:58 UTC 2024 -->
<!-- Generated by javadoc (1.8.0_402) on Tue Apr 23 12:05:36 UTC 2024 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>IPositionOffset (Subscription - Applications - TracAPI 3.15.3 API)</title>
<meta name="date" content="2024-03-12">
<title>IPositionOffset (Subscription - Applications - TracAPI 3.15.7 API)</title>
<meta name="date" content="2024-04-23">
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
<script type="text/javascript" src="../../../../../../script.js"></script>
</head>
@@ -13,7 +13,7 @@
<script type="text/javascript"><!--
try {
if (location.href.indexOf('is-external=true') == -1) {
parent.document.title="IPositionOffset (Subscription - Applications - TracAPI 3.15.3 API)";
parent.document.title="IPositionOffset (Subscription - Applications - TracAPI 3.15.7 API)";
}
}
catch(err) {
Loaded 100 of 310 files, more files were not shown because too many files have changed in this diff. Show more