diff --git a/.github/workflows/cibuild.yml b/.github/workflows/cibuild.yml
index 5a48da6bc44..2853c7ee00b 100644
--- a/.github/workflows/cibuild.yml
+++ b/.github/workflows/cibuild.yml
@@ -51,9 +51,11 @@ jobs:
- name: Send coverage data to codecov.io
if: github.repository_owner == 'opentripplanner'
- uses: codecov/codecov-action@v3.1.1
+ uses: codecov/codecov-action@v4
with:
files: target/site/jacoco/jacoco.xml
+ token: ${{ secrets.CODECOV_TOKEN }}
+ verbose: true
- name: Deploy to Github Package Registry
if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev-1.x' || github.ref == 'refs/heads/dev-2.x')
diff --git a/.github/workflows/performance-test.yml b/.github/workflows/performance-test.yml
index 1b8201a01ae..60b3e69610d 100644
--- a/.github/workflows/performance-test.yml
+++ b/.github/workflows/performance-test.yml
@@ -75,7 +75,7 @@ jobs:
- name: Set up Maven
if: matrix.profile == 'core' || github.ref == 'refs/heads/dev-2.x'
- uses: stCarolas/setup-maven@v.4.5
+ uses: stCarolas/setup-maven@v5
with:
maven-version: 3.8.2
@@ -102,7 +102,7 @@ jobs:
- name: Archive travel results file
if: matrix.profile == 'core' || github.ref == 'refs/heads/dev-2.x'
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ${{ matrix.location }}-travelSearch-results.csv
path: test/performance/${{ matrix.location }}/travelSearch-results.csv
diff --git a/README.md b/README.md
index 8d7e3968cb1..5e016c22bb2 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,9 @@
## Overview
[![Join the chat at https://gitter.im/opentripplanner/OpenTripPLanner](https://badges.gitter.im/opentripplanner/OpenTripPlanner.svg)](https://gitter.im/opentripplanner/OpenTripPlanner)
+[![Matrix](https://img.shields.io/matrix/opentripplanner%3Amatrix.org?label=Matrix%20chat)](https://matrix.to/#/#opentripplanner_OpenTripPlanner:gitter.im)
[![codecov](https://codecov.io/gh/opentripplanner/OpenTripPlanner/branch/dev-2.x/graph/badge.svg?token=ak4PbIKgZ1)](https://codecov.io/gh/opentripplanner/OpenTripPlanner)
+[![Commit activity](https://img.shields.io/github/commit-activity/y/opentripplanner/OpenTripPlanner)](https://github.com/opentripplanner/OpenTripPlanner/graphs/contributors)
[![Docker Pulls](https://img.shields.io/docker/pulls/opentripplanner/opentripplanner)](https://hub.docker.com/r/opentripplanner/opentripplanner)
OpenTripPlanner (OTP) is an open source multi-modal trip planner, focusing on travel by scheduled
diff --git a/client-next/package-lock.json b/client-next/package-lock.json
index d3b8c10754b..08a9146ceb1 100644
--- a/client-next/package-lock.json
+++ b/client-next/package-lock.json
@@ -23,13 +23,13 @@
"@graphql-codegen/client-preset": "4.2.5",
"@graphql-codegen/introspection": "4.0.3",
"@parcel/watcher": "2.4.1",
- "@testing-library/react": "14.2.2",
- "@types/react": "18.2.73",
- "@types/react-dom": "18.2.23",
- "@typescript-eslint/eslint-plugin": "7.5.0",
- "@typescript-eslint/parser": "7.5.0",
+ "@testing-library/react": "15.0.2",
+ "@types/react": "18.2.79",
+ "@types/react-dom": "18.2.25",
+ "@typescript-eslint/eslint-plugin": "7.7.0",
+ "@typescript-eslint/parser": "7.7.0",
"@vitejs/plugin-react": "4.2.1",
- "@vitest/coverage-v8": "1.4.0",
+ "@vitest/coverage-v8": "1.5.0",
"eslint": "8.57.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-import": "2.29.1",
@@ -39,9 +39,9 @@
"eslint-plugin-react-refresh": "0.4.6",
"jsdom": "24.0.0",
"prettier": "3.2.5",
- "typescript": "5.4.3",
- "vite": "5.2.7",
- "vitest": "1.4.0"
+ "typescript": "5.4.5",
+ "vite": "5.2.8",
+ "vitest": "1.5.0"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -3353,36 +3353,36 @@
}
},
"node_modules/@testing-library/dom": {
- "version": "9.3.4",
- "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz",
- "integrity": "sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.0.0.tgz",
+ "integrity": "sha512-PmJPnogldqoVFf+EwbHvbBJ98MmqASV8kLrBYgsDNxQcFMeIS7JFL48sfyXvuMtgmWO/wMhh25odr+8VhDmn4g==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.10.4",
"@babel/runtime": "^7.12.5",
"@types/aria-query": "^5.0.1",
- "aria-query": "5.1.3",
+ "aria-query": "5.3.0",
"chalk": "^4.1.0",
"dom-accessibility-api": "^0.5.9",
"lz-string": "^1.5.0",
"pretty-format": "^27.0.2"
},
"engines": {
- "node": ">=14"
+ "node": ">=18"
}
},
"node_modules/@testing-library/react": {
- "version": "14.2.2",
- "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.2.2.tgz",
- "integrity": "sha512-SOUuM2ysCvjUWBXTNfQ/ztmnKDmqaiPV3SvoIuyxMUca45rbSWWAT/qB8CUs/JQ/ux/8JFs9DNdFQ3f6jH3crA==",
+ "version": "15.0.2",
+ "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-15.0.2.tgz",
+ "integrity": "sha512-5mzIpuytB1ctpyywvyaY2TAAUQVCZIGqwiqFQf6u9lvj/SJQepGUzNV18Xpk+NLCaCE2j7CWrZE0tEf9xLZYiQ==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.12.5",
- "@testing-library/dom": "^9.0.0",
+ "@testing-library/dom": "^10.0.0",
"@types/react-dom": "^18.0.0"
},
"engines": {
- "node": ">=14"
+ "node": ">=18"
},
"peerDependencies": {
"react": "^18.0.0",
@@ -3455,12 +3455,6 @@
"@types/geojson": "*"
}
},
- "node_modules/@types/istanbul-lib-coverage": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
- "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
- "dev": true
- },
"node_modules/@types/js-yaml": {
"version": "4.0.9",
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz",
@@ -3528,18 +3522,18 @@
"integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q=="
},
"node_modules/@types/react": {
- "version": "18.2.73",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.73.tgz",
- "integrity": "sha512-XcGdod0Jjv84HOC7N5ziY3x+qL0AfmubvKOZ9hJjJ2yd5EE+KYjWhdOjt387e9HPheHkdggF9atTifMRtyAaRA==",
+ "version": "18.2.79",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.79.tgz",
+ "integrity": "sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w==",
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
}
},
"node_modules/@types/react-dom": {
- "version": "18.2.23",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.23.tgz",
- "integrity": "sha512-ZQ71wgGOTmDYpnav2knkjr3qXdAFu0vsk8Ci5w3pGAIdj7/kKAyn+VsQDhXsmzzzepAiI9leWMmubXz690AI/A==",
+ "version": "18.2.25",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.25.tgz",
+ "integrity": "sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==",
"dev": true,
"dependencies": {
"@types/react": "*"
@@ -3582,22 +3576,22 @@
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.5.0.tgz",
- "integrity": "sha512-HpqNTH8Du34nLxbKgVMGljZMG0rJd2O9ecvr2QLYp+7512ty1j42KnsFwspPXg1Vh8an9YImf6CokUBltisZFQ==",
+ "version": "7.7.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.0.tgz",
+ "integrity": "sha512-GJWR0YnfrKnsRoluVO3PRb9r5aMZriiMMM/RHj5nnTrBy1/wIgk76XCtCKcnXGjpZQJQRFtGV9/0JJ6n30uwpQ==",
"dev": true,
"dependencies": {
- "@eslint-community/regexpp": "^4.5.1",
- "@typescript-eslint/scope-manager": "7.5.0",
- "@typescript-eslint/type-utils": "7.5.0",
- "@typescript-eslint/utils": "7.5.0",
- "@typescript-eslint/visitor-keys": "7.5.0",
+ "@eslint-community/regexpp": "^4.10.0",
+ "@typescript-eslint/scope-manager": "7.7.0",
+ "@typescript-eslint/type-utils": "7.7.0",
+ "@typescript-eslint/utils": "7.7.0",
+ "@typescript-eslint/visitor-keys": "7.7.0",
"debug": "^4.3.4",
"graphemer": "^1.4.0",
- "ignore": "^5.2.4",
+ "ignore": "^5.3.1",
"natural-compare": "^1.4.0",
- "semver": "^7.5.4",
- "ts-api-utils": "^1.0.1"
+ "semver": "^7.6.0",
+ "ts-api-utils": "^1.3.0"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -3650,15 +3644,15 @@
"dev": true
},
"node_modules/@typescript-eslint/parser": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.5.0.tgz",
- "integrity": "sha512-cj+XGhNujfD2/wzR1tabNsidnYRaFfEkcULdcIyVBYcXjBvBKOes+mpMBP7hMpOyk+gBcfXsrg4NBGAStQyxjQ==",
+ "version": "7.7.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.0.tgz",
+ "integrity": "sha512-fNcDm3wSwVM8QYL4HKVBggdIPAy9Q41vcvC/GtDobw3c4ndVT3K6cqudUmjHPw8EAp4ufax0o58/xvWaP2FmTg==",
"dev": true,
"dependencies": {
- "@typescript-eslint/scope-manager": "7.5.0",
- "@typescript-eslint/types": "7.5.0",
- "@typescript-eslint/typescript-estree": "7.5.0",
- "@typescript-eslint/visitor-keys": "7.5.0",
+ "@typescript-eslint/scope-manager": "7.7.0",
+ "@typescript-eslint/types": "7.7.0",
+ "@typescript-eslint/typescript-estree": "7.7.0",
+ "@typescript-eslint/visitor-keys": "7.7.0",
"debug": "^4.3.4"
},
"engines": {
@@ -3678,13 +3672,13 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.5.0.tgz",
- "integrity": "sha512-Z1r7uJY0MDeUlql9XJ6kRVgk/sP11sr3HKXn268HZyqL7i4cEfrdFuSSY/0tUqT37l5zT0tJOsuDP16kio85iA==",
+ "version": "7.7.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.0.tgz",
+ "integrity": "sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "7.5.0",
- "@typescript-eslint/visitor-keys": "7.5.0"
+ "@typescript-eslint/types": "7.7.0",
+ "@typescript-eslint/visitor-keys": "7.7.0"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -3695,15 +3689,15 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.5.0.tgz",
- "integrity": "sha512-A021Rj33+G8mx2Dqh0nMO9GyjjIBK3MqgVgZ2qlKf6CJy51wY/lkkFqq3TqqnH34XyAHUkq27IjlUkWlQRpLHw==",
+ "version": "7.7.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.0.tgz",
+ "integrity": "sha512-bOp3ejoRYrhAlnT/bozNQi3nio9tIgv3U5C0mVDdZC7cpcQEDZXvq8inrHYghLVwuNABRqrMW5tzAv88Vy77Sg==",
"dev": true,
"dependencies": {
- "@typescript-eslint/typescript-estree": "7.5.0",
- "@typescript-eslint/utils": "7.5.0",
+ "@typescript-eslint/typescript-estree": "7.7.0",
+ "@typescript-eslint/utils": "7.7.0",
"debug": "^4.3.4",
- "ts-api-utils": "^1.0.1"
+ "ts-api-utils": "^1.3.0"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -3722,9 +3716,9 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.5.0.tgz",
- "integrity": "sha512-tv5B4IHeAdhR7uS4+bf8Ov3k793VEVHd45viRRkehIUZxm0WF82VPiLgHzA/Xl4TGPg1ZD49vfxBKFPecD5/mg==",
+ "version": "7.7.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.0.tgz",
+ "integrity": "sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==",
"dev": true,
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -3735,19 +3729,19 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.5.0.tgz",
- "integrity": "sha512-YklQQfe0Rv2PZEueLTUffiQGKQneiIEKKnfIqPIOxgM9lKSZFCjT5Ad4VqRKj/U4+kQE3fa8YQpskViL7WjdPQ==",
+ "version": "7.7.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.0.tgz",
+ "integrity": "sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "7.5.0",
- "@typescript-eslint/visitor-keys": "7.5.0",
+ "@typescript-eslint/types": "7.7.0",
+ "@typescript-eslint/visitor-keys": "7.7.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
- "minimatch": "9.0.3",
- "semver": "^7.5.4",
- "ts-api-utils": "^1.0.1"
+ "minimatch": "^9.0.4",
+ "semver": "^7.6.0",
+ "ts-api-utils": "^1.3.0"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -3796,18 +3790,18 @@
"dev": true
},
"node_modules/@typescript-eslint/utils": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.5.0.tgz",
- "integrity": "sha512-3vZl9u0R+/FLQcpy2EHyRGNqAS/ofJ3Ji8aebilfJe+fobK8+LbIFmrHciLVDxjDoONmufDcnVSF38KwMEOjzw==",
+ "version": "7.7.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.0.tgz",
+ "integrity": "sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
- "@types/json-schema": "^7.0.12",
- "@types/semver": "^7.5.0",
- "@typescript-eslint/scope-manager": "7.5.0",
- "@typescript-eslint/types": "7.5.0",
- "@typescript-eslint/typescript-estree": "7.5.0",
- "semver": "^7.5.4"
+ "@types/json-schema": "^7.0.15",
+ "@types/semver": "^7.5.8",
+ "@typescript-eslint/scope-manager": "7.7.0",
+ "@typescript-eslint/types": "7.7.0",
+ "@typescript-eslint/typescript-estree": "7.7.0",
+ "semver": "^7.6.0"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -3854,13 +3848,13 @@
"dev": true
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.5.0.tgz",
- "integrity": "sha512-mcuHM/QircmA6O7fy6nn2w/3ditQkj+SgtOc8DW3uQ10Yfj42amm2i+6F2K4YAOPNNTmE6iM1ynM6lrSwdendA==",
+ "version": "7.7.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.0.tgz",
+ "integrity": "sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "7.5.0",
- "eslint-visitor-keys": "^3.4.1"
+ "@typescript-eslint/types": "7.7.0",
+ "eslint-visitor-keys": "^3.4.3"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -3896,9 +3890,9 @@
}
},
"node_modules/@vitest/coverage-v8": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.4.0.tgz",
- "integrity": "sha512-4hDGyH1SvKpgZnIByr9LhGgCEuF9DKM34IBLCC/fVfy24Z3+PZ+Ii9hsVBsHvY1umM1aGPEjceRkzxCfcQ10wg==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.5.0.tgz",
+ "integrity": "sha512-1igVwlcqw1QUMdfcMlzzY4coikSIBN944pkueGi0pawrX5I5Z+9hxdTR+w3Sg6Q3eZhvdMAs8ZaF9JuTG1uYOQ==",
"dev": true,
"dependencies": {
"@ampproject/remapping": "^2.2.1",
@@ -3913,24 +3907,23 @@
"picocolors": "^1.0.0",
"std-env": "^3.5.0",
"strip-literal": "^2.0.0",
- "test-exclude": "^6.0.0",
- "v8-to-istanbul": "^9.2.0"
+ "test-exclude": "^6.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
- "vitest": "1.4.0"
+ "vitest": "1.5.0"
}
},
"node_modules/@vitest/expect": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.4.0.tgz",
- "integrity": "sha512-Jths0sWCJZ8BxjKe+p+eKsoqev1/T8lYcrjavEaz8auEJ4jAVY0GwW3JKmdVU4mmNPLPHixh4GNXP7GFtAiDHA==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.0.tgz",
+ "integrity": "sha512-0pzuCI6KYi2SIC3LQezmxujU9RK/vwC1U9R0rLuGlNGcOuDWxqWKu6nUdFsX9tH1WU0SXtAxToOsEjeUn1s3hA==",
"dev": true,
"dependencies": {
- "@vitest/spy": "1.4.0",
- "@vitest/utils": "1.4.0",
+ "@vitest/spy": "1.5.0",
+ "@vitest/utils": "1.5.0",
"chai": "^4.3.10"
},
"funding": {
@@ -3938,12 +3931,12 @@
}
},
"node_modules/@vitest/runner": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.4.0.tgz",
- "integrity": "sha512-EDYVSmesqlQ4RD2VvWo3hQgTJ7ZrFQ2VSJdfiJiArkCerDAGeyF1i6dHkmySqk573jLp6d/cfqCN+7wUB5tLgg==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.0.tgz",
+ "integrity": "sha512-7HWwdxXP5yDoe7DTpbif9l6ZmDwCzcSIK38kTSIt6CFEpMjX4EpCgT6wUmS0xTXqMI6E/ONmfgRKmaujpabjZQ==",
"dev": true,
"dependencies": {
- "@vitest/utils": "1.4.0",
+ "@vitest/utils": "1.5.0",
"p-limit": "^5.0.0",
"pathe": "^1.1.1"
},
@@ -3979,9 +3972,9 @@
}
},
"node_modules/@vitest/snapshot": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.4.0.tgz",
- "integrity": "sha512-saAFnt5pPIA5qDGxOHxJ/XxhMFKkUSBJmVt5VgDsAqPTX6JP326r5C/c9UuCMPoXNzuudTPsYDZCoJ5ilpqG2A==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.0.tgz",
+ "integrity": "sha512-qpv3fSEuNrhAO3FpH6YYRdaECnnRjg9VxbhdtPwPRnzSfHVXnNzzrpX4cJxqiwgRMo7uRMWDFBlsBq4Cr+rO3A==",
"dev": true,
"dependencies": {
"magic-string": "^0.30.5",
@@ -4025,9 +4018,9 @@
"dev": true
},
"node_modules/@vitest/spy": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.4.0.tgz",
- "integrity": "sha512-Ywau/Qs1DzM/8Uc+yA77CwSegizMlcgTJuYGAi0jujOteJOUf1ujunHThYo243KG9nAyWT3L9ifPYZ5+As/+6Q==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.0.tgz",
+ "integrity": "sha512-vu6vi6ew5N5MMHJjD5PoakMRKYdmIrNJmyfkhRpQt5d9Ewhw9nZ5Aqynbi3N61bvk9UvZ5UysMT6ayIrZ8GA9w==",
"dev": true,
"dependencies": {
"tinyspy": "^2.2.0"
@@ -4037,9 +4030,9 @@
}
},
"node_modules/@vitest/utils": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.4.0.tgz",
- "integrity": "sha512-mx3Yd1/6e2Vt/PUC98DcqTirtfxUyAZ32uK82r8rZzbtBeBo+nqgnjx/LvqQdWsrvNtm14VmurNgcf4nqY5gJg==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.0.tgz",
+ "integrity": "sha512-BDU0GNL8MWkRkSRdNFvCUCAVOeHaUlVJ9Tx0TYBZyXaaOTmGtUFObzchCivIBrIwKzvZA7A9sCejVhXM2aY98A==",
"dev": true,
"dependencies": {
"diff-sequences": "^29.6.3",
@@ -4232,12 +4225,12 @@
"dev": true
},
"node_modules/aria-query": {
- "version": "5.1.3",
- "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz",
- "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==",
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
+ "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
"dev": true,
"dependencies": {
- "deep-equal": "^2.0.5"
+ "dequal": "^2.0.3"
}
},
"node_modules/arr-union": {
@@ -5284,38 +5277,6 @@
"node": ">=6"
}
},
- "node_modules/deep-equal": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz",
- "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==",
- "dev": true,
- "dependencies": {
- "array-buffer-byte-length": "^1.0.0",
- "call-bind": "^1.0.5",
- "es-get-iterator": "^1.1.3",
- "get-intrinsic": "^1.2.2",
- "is-arguments": "^1.1.1",
- "is-array-buffer": "^3.0.2",
- "is-date-object": "^1.0.5",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.2",
- "isarray": "^2.0.5",
- "object-is": "^1.1.5",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.4",
- "regexp.prototype.flags": "^1.5.1",
- "side-channel": "^1.0.4",
- "which-boxed-primitive": "^1.0.2",
- "which-collection": "^1.0.1",
- "which-typed-array": "^1.1.13"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -5613,26 +5574,6 @@
"node": ">= 0.4"
}
},
- "node_modules/es-get-iterator": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz",
- "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.3",
- "has-symbols": "^1.0.3",
- "is-arguments": "^1.1.1",
- "is-map": "^2.0.2",
- "is-set": "^2.0.2",
- "is-string": "^1.0.7",
- "isarray": "^2.0.5",
- "stop-iteration-iterator": "^1.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/es-iterator-helpers": {
"version": "1.0.18",
"resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz",
@@ -5986,15 +5927,6 @@
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
}
},
- "node_modules/eslint-plugin-jsx-a11y/node_modules/aria-query": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
- "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
- "dev": true,
- "dependencies": {
- "dequal": "^2.0.3"
- }
- },
"node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -7311,22 +7243,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/is-arguments": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
- "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/is-array-buffer": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
@@ -8532,9 +8448,9 @@
}
},
"node_modules/minimatch": {
- "version": "9.0.3",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
- "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+ "version": "9.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
+ "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
@@ -8744,22 +8660,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/object-is": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
- "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
@@ -10164,18 +10064,6 @@
"integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==",
"dev": true
},
- "node_modules/stop-iteration-iterator": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
- "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==",
- "dev": true,
- "dependencies": {
- "internal-slot": "^1.0.4"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"node_modules/streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
@@ -10723,9 +10611,9 @@
}
},
"node_modules/typescript": {
- "version": "5.4.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz",
- "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==",
+ "version": "5.4.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
+ "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
@@ -10944,20 +10832,6 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true
},
- "node_modules/v8-to-istanbul": {
- "version": "9.2.0",
- "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz",
- "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==",
- "dev": true,
- "dependencies": {
- "@jridgewell/trace-mapping": "^0.3.12",
- "@types/istanbul-lib-coverage": "^2.0.1",
- "convert-source-map": "^2.0.0"
- },
- "engines": {
- "node": ">=10.12.0"
- }
- },
"node_modules/value-or-promise": {
"version": "1.0.12",
"resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.12.tgz",
@@ -10968,9 +10842,9 @@
}
},
"node_modules/vite": {
- "version": "5.2.7",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.7.tgz",
- "integrity": "sha512-k14PWOKLI6pMaSzAuGtT+Cf0YmIx12z9YGon39onaJNy8DLBfBJrzg9FQEmkAM5lpHBZs9wksWAsyF/HkpEwJA==",
+ "version": "5.2.8",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz",
+ "integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==",
"dev": true,
"dependencies": {
"esbuild": "^0.20.1",
@@ -11023,9 +10897,9 @@
}
},
"node_modules/vite-node": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.4.0.tgz",
- "integrity": "sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.0.tgz",
+ "integrity": "sha512-tV8h6gMj6vPzVCa7l+VGq9lwoJjW8Y79vst8QZZGiuRAfijU+EEWuc0kFpmndQrWhMMhet1jdSF+40KSZUqIIw==",
"dev": true,
"dependencies": {
"cac": "^6.7.14",
@@ -11045,16 +10919,16 @@
}
},
"node_modules/vitest": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.4.0.tgz",
- "integrity": "sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.0.tgz",
+ "integrity": "sha512-d8UKgR0m2kjdxDWX6911uwxout6GHS0XaGH1cksSIVVG8kRlE7G7aBw7myKQCvDI5dT4j7ZMa+l706BIORMDLw==",
"dev": true,
"dependencies": {
- "@vitest/expect": "1.4.0",
- "@vitest/runner": "1.4.0",
- "@vitest/snapshot": "1.4.0",
- "@vitest/spy": "1.4.0",
- "@vitest/utils": "1.4.0",
+ "@vitest/expect": "1.5.0",
+ "@vitest/runner": "1.5.0",
+ "@vitest/snapshot": "1.5.0",
+ "@vitest/spy": "1.5.0",
+ "@vitest/utils": "1.5.0",
"acorn-walk": "^8.3.2",
"chai": "^4.3.10",
"debug": "^4.3.4",
@@ -11066,9 +10940,9 @@
"std-env": "^3.5.0",
"strip-literal": "^2.0.0",
"tinybench": "^2.5.1",
- "tinypool": "^0.8.2",
+ "tinypool": "^0.8.3",
"vite": "^5.0.0",
- "vite-node": "1.4.0",
+ "vite-node": "1.5.0",
"why-is-node-running": "^2.2.2"
},
"bin": {
@@ -11083,8 +10957,8 @@
"peerDependencies": {
"@edge-runtime/vm": "*",
"@types/node": "^18.0.0 || >=20.0.0",
- "@vitest/browser": "1.4.0",
- "@vitest/ui": "1.4.0",
+ "@vitest/browser": "1.5.0",
+ "@vitest/ui": "1.5.0",
"happy-dom": "*",
"jsdom": "*"
},
diff --git a/client-next/package.json b/client-next/package.json
index d3f583057d8..643acd1c082 100644
--- a/client-next/package.json
+++ b/client-next/package.json
@@ -32,13 +32,13 @@
"@graphql-codegen/client-preset": "4.2.5",
"@graphql-codegen/introspection": "4.0.3",
"@parcel/watcher": "2.4.1",
- "@testing-library/react": "14.2.2",
- "@types/react": "18.2.73",
- "@types/react-dom": "18.2.23",
- "@typescript-eslint/eslint-plugin": "7.5.0",
- "@typescript-eslint/parser": "7.5.0",
+ "@testing-library/react": "15.0.2",
+ "@types/react": "18.2.79",
+ "@types/react-dom": "18.2.25",
+ "@typescript-eslint/eslint-plugin": "7.7.0",
+ "@typescript-eslint/parser": "7.7.0",
"@vitejs/plugin-react": "4.2.1",
- "@vitest/coverage-v8": "1.4.0",
+ "@vitest/coverage-v8": "1.5.0",
"eslint": "8.57.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-import": "2.29.1",
@@ -48,8 +48,8 @@
"eslint-plugin-react-refresh": "0.4.6",
"jsdom": "24.0.0",
"prettier": "3.2.5",
- "typescript": "5.4.3",
- "vite": "5.2.7",
- "vitest": "1.4.0"
+ "typescript": "5.4.5",
+ "vite": "5.2.8",
+ "vitest": "1.5.0"
}
}
diff --git a/doc-templates/VehicleParking.md b/doc-templates/VehicleParking.md
index 37988ef7902..50bd8806267 100644
--- a/doc-templates/VehicleParking.md
+++ b/doc-templates/VehicleParking.md
@@ -3,7 +3,7 @@
## Contact Info
- For HSL Park and Ride updater: Digitransit team, HSL, Helsinki, Finland
-- For Bikely updater: Leonard Ehrenfried, [mail@leonard.io](mailto:mail@leonard.io)
+- For Bikely and NOI updater: Leonard Ehrenfried, [mail@leonard.io](mailto:mail@leonard.io)
## Documentation
@@ -16,6 +16,7 @@ Currently contains the following updaters:
- [HSL Park and Ride](https://p.hsl.fi/docs/index.html)
- [ParkAPI](https://github.com/offenesdresden/ParkAPI)
- [Bikely](https://www.safebikely.com/)
+- [NOI Open Data Hub](https://opendatahub.com/)
### Configuration
@@ -39,6 +40,10 @@ All updaters have the following parameters in common:
+## NOI Open Data Hub
+
+
+
## Changelog
diff --git a/docs/Changelog.md b/docs/Changelog.md
index e1773cb0a5e..25c8cb80594 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -8,6 +8,12 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle
- ISO-8601 date time for GTFS API itinerary responses [#5660](https://github.com/opentripplanner/OpenTripPlanner/pull/5660)
- Fix street routing on roundabout [#5732](https://github.com/opentripplanner/OpenTripPlanner/pull/5732)
- Expose route sort order in GTFS API [#5764](https://github.com/opentripplanner/OpenTripPlanner/pull/5764)
+- Fix issue with cancellations on trip patterns that run after midnight [#5719](https://github.com/opentripplanner/OpenTripPlanner/pull/5719)
+- Fix handling of null transport mode filter [#5789](https://github.com/opentripplanner/OpenTripPlanner/pull/5789)
+- Discourage instead of ban cycling on use_sidepath ways and do the same for walking on foot=use_sidepath [#5790](https://github.com/opentripplanner/OpenTripPlanner/pull/5790)
+- Prune islands with mode-less stop vertices [#5782](https://github.com/opentripplanner/OpenTripPlanner/pull/5782)
+- Overwrite default WALK directMode when it is not set in the request, but modes is set [#5779](https://github.com/opentripplanner/OpenTripPlanner/pull/5779)
+- Fix trip duplication in Graph Builder DSJ mapping [#5794](https://github.com/opentripplanner/OpenTripPlanner/pull/5794)
[](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE)
## 2.5.0 (2024-03-13)
diff --git a/docs/RouterConfiguration.md b/docs/RouterConfiguration.md
index 503b8c7370f..e0f1d81b590 100644
--- a/docs/RouterConfiguration.md
+++ b/docs/RouterConfiguration.md
@@ -764,6 +764,12 @@ Used to group requests when monitoring OTP.
"Authorization" : "${BIKELY_AUTHORIZATION}"
}
},
+ {
+ "type" : "vehicle-parking",
+ "feedId" : "noi",
+ "sourceType" : "noi-open-data-hub",
+ "url" : "https://parking.otp.opendatahub.com/parking/all.json"
+ },
{
"type" : "stop-time-updater",
"frequency" : "1m",
diff --git a/docs/UpdaterConfig.md b/docs/UpdaterConfig.md
index 973874be66a..3e0907f60ad 100644
--- a/docs/UpdaterConfig.md
+++ b/docs/UpdaterConfig.md
@@ -92,20 +92,20 @@ The information is downloaded in a single HTTP request and polled regularly.
| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since |
|-----------------------------------------------------------------------|:---------------:|----------------------------------------------------------------------------|:----------:|----------------------|:-----:|
| type = "stop-time-updater" | `enum` | The type of the updater. | *Required* | | 1.5 |
-| [backwardsDelayPropagationType](#u__5__backwardsDelayPropagationType) | `enum` | How backwards propagation should be handled. | *Optional* | `"required-no-data"` | 2.2 |
+| [backwardsDelayPropagationType](#u__6__backwardsDelayPropagationType) | `enum` | How backwards propagation should be handled. | *Optional* | `"required-no-data"` | 2.2 |
| feedId | `string` | Which feed the updates apply to. | *Required* | | 1.5 |
| frequency | `duration` | How often the data should be downloaded. | *Optional* | `"PT1M"` | 1.5 |
| fuzzyTripMatching | `boolean` | If the trips should be matched fuzzily. | *Optional* | `false` | 1.5 |
-| [url](#u__5__url) | `string` | The URL of the GTFS-RT resource. | *Required* | | 1.5 |
-| [headers](#u__5__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 |
+| [url](#u__6__url) | `string` | The URL of the GTFS-RT resource. | *Required* | | 1.5 |
+| [headers](#u__6__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 |
##### Parameter details
-
backwardsDelayPropagationType
+backwardsDelayPropagationType
**Since version:** `2.2` ∙ **Type:** `enum` ∙ **Cardinality:** `Optional` ∙ **Default value:** `"required-no-data"`
-**Path:** /updaters/[5]
+**Path:** /updaters/[6]
**Enum values:** `required-no-data` | `required` | `always`
How backwards propagation should be handled.
@@ -124,19 +124,19 @@ How backwards propagation should be handled.
The updated times are exposed through APIs.
-url
+url
**Since version:** `1.5` ∙ **Type:** `string` ∙ **Cardinality:** `Required`
-**Path:** /updaters/[5]
+**Path:** /updaters/[6]
The URL of the GTFS-RT resource.
`file:` URLs are also supported if you want to read a file from the local disk.
-
+
**Since version:** `2.3` ∙ **Type:** `map of string` ∙ **Cardinality:** `Optional`
-**Path:** /updaters/[5]
+**Path:** /updaters/[6]
HTTP headers to add to the request. Any header key, value can be inserted.
@@ -178,7 +178,7 @@ This system powers the realtime updates in Helsinki and more information can be
| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since |
|-----------------------------------------------------------------------|:---------:|----------------------------------------------|:----------:|----------------------|:-----:|
| type = "mqtt-gtfs-rt-updater" | `enum` | The type of the updater. | *Required* | | 1.5 |
-| [backwardsDelayPropagationType](#u__6__backwardsDelayPropagationType) | `enum` | How backwards propagation should be handled. | *Optional* | `"required-no-data"` | 2.2 |
+| [backwardsDelayPropagationType](#u__7__backwardsDelayPropagationType) | `enum` | How backwards propagation should be handled. | *Optional* | `"required-no-data"` | 2.2 |
| feedId | `string` | The feed id to apply the updates to. | *Required* | | 2.0 |
| fuzzyTripMatching | `boolean` | Whether to match trips fuzzily. | *Optional* | `false` | 2.0 |
| qos | `integer` | QOS level. | *Optional* | `0` | 2.0 |
@@ -188,10 +188,10 @@ This system powers the realtime updates in Helsinki and more information can be
##### Parameter details
-backwardsDelayPropagationType
+backwardsDelayPropagationType
**Since version:** `2.2` ∙ **Type:** `enum` ∙ **Cardinality:** `Optional` ∙ **Default value:** `"required-no-data"`
-**Path:** /updaters/[6]
+**Path:** /updaters/[7]
**Enum values:** `required-no-data` | `required` | `always`
How backwards propagation should be handled.
@@ -247,24 +247,24 @@ The information is downloaded in a single HTTP request and polled regularly.
| frequency | `duration` | How often the positions should be updated. | *Optional* | `"PT1M"` | 2.2 |
| fuzzyTripMatching | `boolean` | Whether to match trips fuzzily. | *Optional* | `false` | 2.5 |
| url | `uri` | The URL of GTFS-RT protobuf HTTP resource to download the positions from. | *Required* | | 2.2 |
-| [features](#u__7__features) | `enum set` | Which features of GTFS RT vehicle positions should be loaded into OTP. | *Optional* | | 2.5 |
-| [headers](#u__7__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 |
+| [features](#u__8__features) | `enum set` | Which features of GTFS RT vehicle positions should be loaded into OTP. | *Optional* | | 2.5 |
+| [headers](#u__8__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 |
##### Parameter details
-features
+features
**Since version:** `2.5` ∙ **Type:** `enum set` ∙ **Cardinality:** `Optional`
-**Path:** /updaters/[7]
+**Path:** /updaters/[8]
**Enum values:** `position` | `stop-position` | `occupancy`
Which features of GTFS RT vehicle positions should be loaded into OTP.
-
+
**Since version:** `2.3` ∙ **Type:** `map of string` ∙ **Cardinality:** `Optional`
-**Path:** /updaters/[7]
+**Path:** /updaters/[8]
HTTP headers to add to the request. Any header key, value can be inserted.
diff --git a/docs/sandbox/VehicleParking.md b/docs/sandbox/VehicleParking.md
index 4bfc2f6bd36..2721fff9b0c 100644
--- a/docs/sandbox/VehicleParking.md
+++ b/docs/sandbox/VehicleParking.md
@@ -3,7 +3,7 @@
## Contact Info
- For HSL Park and Ride updater: Digitransit team, HSL, Helsinki, Finland
-- For Bikely updater: Leonard Ehrenfried, [mail@leonard.io](mailto:mail@leonard.io)
+- For Bikely and NOI updater: Leonard Ehrenfried, [mail@leonard.io](mailto:mail@leonard.io)
## Documentation
@@ -16,6 +16,7 @@ Currently contains the following updaters:
- [HSL Park and Ride](https://p.hsl.fi/docs/index.html)
- [ParkAPI](https://github.com/offenesdresden/ParkAPI)
- [Bikely](https://www.safebikely.com/)
+- [NOI Open Data Hub](https://opendatahub.com/)
### Configuration
@@ -60,7 +61,7 @@ This will end up in the API responses as the feed id of of the parking lot.
**Since version:** `2.2` ∙ **Type:** `enum` ∙ **Cardinality:** `Required`
**Path:** /updaters/[2]
-**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely`
+**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` | `noi-open-data-hub`
The source of the vehicle updates.
@@ -110,7 +111,7 @@ Used for converting abstract opening hours into concrete points in time.
| frequency | `duration` | How often to update the source. | *Optional* | `"PT1M"` | 2.2 |
| [sourceType](#u__3__sourceType) | `enum` | The source of the vehicle updates. | *Required* | | 2.2 |
| [timeZone](#u__3__timeZone) | `time-zone` | The time zone of the feed. | *Optional* | | 2.2 |
-| url | `string` | URL of the resource. | *Optional* | | 2.2 |
+| url | `string` | URL of the resource. | *Required* | | 2.2 |
| [headers](#u__3__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.2 |
| [tags](#u__3__tags) | `string[]` | Tags to add to the parking lots. | *Optional* | | 2.2 |
@@ -130,7 +131,7 @@ This will end up in the API responses as the feed id of of the parking lot.
**Since version:** `2.2` ∙ **Type:** `enum` ∙ **Cardinality:** `Required`
**Path:** /updaters/[3]
-**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely`
+**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` | `noi-open-data-hub`
The source of the vehicle updates.
@@ -196,7 +197,7 @@ Tags to add to the parking lots.
| [feedId](#u__4__feedId) | `string` | The name of the data source. | *Required* | | 2.2 |
| frequency | `duration` | How often to update the source. | *Optional* | `"PT1M"` | 2.3 |
| [sourceType](#u__4__sourceType) | `enum` | The source of the vehicle updates. | *Required* | | 2.2 |
-| url | `uri` | URL of the locations endpoint. | *Optional* | | 2.3 |
+| url | `uri` | URL of the locations endpoint. | *Required* | | 2.3 |
| [headers](#u__4__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 |
@@ -215,7 +216,7 @@ This will end up in the API responses as the feed id of of the parking lot.
**Since version:** `2.2` ∙ **Type:** `enum` ∙ **Cardinality:** `Required`
**Path:** /updaters/[4]
-**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely`
+**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` | `noi-open-data-hub`
The source of the vehicle updates.
@@ -250,6 +251,67 @@ HTTP headers to add to the request. Any header key, value can be inserted.
+## NOI Open Data Hub
+
+
+
+
+| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since |
+|---------------------------------|:---------------:|----------------------------------------------------------------------------|:----------:|---------------|:-----:|
+| type = "vehicle-parking" | `enum` | The type of the updater. | *Required* | | 1.5 |
+| [feedId](#u__5__feedId) | `string` | The name of the data source. | *Required* | | 2.2 |
+| frequency | `duration` | How often to update the source. | *Optional* | `"PT1M"` | 2.6 |
+| [sourceType](#u__5__sourceType) | `enum` | The source of the vehicle updates. | *Required* | | 2.2 |
+| url | `uri` | URL of the locations endpoint. | *Required* | | 2.6 |
+| [headers](#u__5__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.6 |
+
+
+#### Details
+
+feedId
+
+**Since version:** `2.2` ∙ **Type:** `string` ∙ **Cardinality:** `Required`
+**Path:** /updaters/[5]
+
+The name of the data source.
+
+This will end up in the API responses as the feed id of of the parking lot.
+
+sourceType
+
+**Since version:** `2.2` ∙ **Type:** `enum` ∙ **Cardinality:** `Required`
+**Path:** /updaters/[5]
+**Enum values:** `park-api` | `bicycle-park-api` | `hsl-park` | `bikely` | `noi-open-data-hub`
+
+The source of the vehicle updates.
+
+
+
+**Since version:** `2.6` ∙ **Type:** `map of string` ∙ **Cardinality:** `Optional`
+**Path:** /updaters/[5]
+
+HTTP headers to add to the request. Any header key, value can be inserted.
+
+
+
+##### Example configuration
+
+```JSON
+// router-config.json
+{
+ "updaters" : [
+ {
+ "type" : "vehicle-parking",
+ "feedId" : "noi",
+ "sourceType" : "noi-open-data-hub",
+ "url" : "https://parking.otp.opendatahub.com/parking/all.json"
+ }
+ ]
+}
+```
+
+
+
## Changelog
diff --git a/docs/sandbox/siri/SiriAzureUpdater.md b/docs/sandbox/siri/SiriAzureUpdater.md
index 3b5c536946d..c6ddf9f3ebe 100644
--- a/docs/sandbox/siri/SiriAzureUpdater.md
+++ b/docs/sandbox/siri/SiriAzureUpdater.md
@@ -24,14 +24,14 @@ To enable the SIRI updater you need to add it to the updaters section of the `ro
| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since |
|------------------------------------------------------------|:----------:|------------------------------------------------------------------|:----------:|---------------------|:-----:|
| type = "siri-azure-et-updater" | `enum` | The type of the updater. | *Required* | | 1.5 |
-| [authenticationType](#u__11__authenticationType) | `enum` | Which authentication type to use | *Optional* | `"sharedaccesskey"` | 2.5 |
+| [authenticationType](#u__12__authenticationType) | `enum` | Which authentication type to use | *Optional* | `"sharedaccesskey"` | 2.5 |
| autoDeleteOnIdle | `duration` | The time after which an inactive subscription is removed. | *Optional* | `"PT1H"` | 2.5 |
-| [customMidnight](#u__11__customMidnight) | `integer` | Time on which time breaks into new day. | *Optional* | `0` | 2.2 |
+| [customMidnight](#u__12__customMidnight) | `integer` | Time on which time breaks into new day. | *Optional* | `0` | 2.2 |
| feedId | `string` | The ID of the feed to apply the updates to. | *Optional* | | 2.2 |
-| [fullyQualifiedNamespace](#u__11__fullyQualifiedNamespace) | `string` | Service Bus fully qualified namespace used for authentication. | *Optional* | | 2.5 |
+| [fullyQualifiedNamespace](#u__12__fullyQualifiedNamespace) | `string` | Service Bus fully qualified namespace used for authentication. | *Optional* | | 2.5 |
| fuzzyTripMatching | `boolean` | Whether to apply fuzzyTripMatching on the updates | *Optional* | `false` | 2.2 |
| prefetchCount | `integer` | The number of messages to fetch from the subscription at a time. | *Optional* | `10` | 2.5 |
-| [servicebus-url](#u__11__servicebus_url) | `string` | Service Bus connection used for authentication. | *Optional* | | 2.2 |
+| [servicebus-url](#u__12__servicebus_url) | `string` | Service Bus connection used for authentication. | *Optional* | | 2.2 |
| topic | `string` | Service Bus topic to connect to. | *Optional* | | 2.2 |
| history | `object` | Configuration for fetching historical data on startup | *Optional* | | 2.2 |
| fromDateTime | `string` | Datetime boundary for historical data | *Optional* | `"-P1D"` | 2.2 |
@@ -41,36 +41,36 @@ To enable the SIRI updater you need to add it to the updaters section of the `ro
##### Parameter details
-authenticationType
+authenticationType
**Since version:** `2.5` ∙ **Type:** `enum` ∙ **Cardinality:** `Optional` ∙ **Default value:** `"sharedaccesskey"`
-**Path:** /updaters/[11]
+**Path:** /updaters/[12]
**Enum values:** `sharedaccesskey` | `federatedidentity`
Which authentication type to use
-customMidnight
+customMidnight
**Since version:** `2.2` ∙ **Type:** `integer` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0`
-**Path:** /updaters/[11]
+**Path:** /updaters/[12]
Time on which time breaks into new day.
It is common that operating day date breaks a little bit later than midnight so that the switch happens when traffic is at the lowest point. Parameter uses 24-hour format. If the switch happens on 4 am then set this field to 4.
-fullyQualifiedNamespace
+fullyQualifiedNamespace
**Since version:** `2.5` ∙ **Type:** `string` ∙ **Cardinality:** `Optional`
-**Path:** /updaters/[11]
+**Path:** /updaters/[12]
Service Bus fully qualified namespace used for authentication.
Has to be present for authenticationMethod FederatedIdentity.
-servicebus-url
+servicebus-url
**Since version:** `2.2` ∙ **Type:** `string` ∙ **Cardinality:** `Optional`
-**Path:** /updaters/[11]
+**Path:** /updaters/[12]
Service Bus connection used for authentication.
@@ -112,14 +112,14 @@ Has to be present for authenticationMethod SharedAccessKey. This should be Prima
| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since |
|------------------------------------------------------------|:----------:|------------------------------------------------------------------|:----------:|---------------------|:-----:|
| type = "siri-azure-sx-updater" | `enum` | The type of the updater. | *Required* | | 1.5 |
-| [authenticationType](#u__10__authenticationType) | `enum` | Which authentication type to use | *Optional* | `"sharedaccesskey"` | 2.5 |
+| [authenticationType](#u__11__authenticationType) | `enum` | Which authentication type to use | *Optional* | `"sharedaccesskey"` | 2.5 |
| autoDeleteOnIdle | `duration` | The time after which an inactive subscription is removed. | *Optional* | `"PT1H"` | 2.5 |
-| [customMidnight](#u__10__customMidnight) | `integer` | Time on which time breaks into new day. | *Optional* | `0` | 2.2 |
+| [customMidnight](#u__11__customMidnight) | `integer` | Time on which time breaks into new day. | *Optional* | `0` | 2.2 |
| feedId | `string` | The ID of the feed to apply the updates to. | *Optional* | | 2.2 |
-| [fullyQualifiedNamespace](#u__10__fullyQualifiedNamespace) | `string` | Service Bus fully qualified namespace used for authentication. | *Optional* | | 2.5 |
+| [fullyQualifiedNamespace](#u__11__fullyQualifiedNamespace) | `string` | Service Bus fully qualified namespace used for authentication. | *Optional* | | 2.5 |
| fuzzyTripMatching | `boolean` | Whether to apply fuzzyTripMatching on the updates | *Optional* | `false` | 2.2 |
| prefetchCount | `integer` | The number of messages to fetch from the subscription at a time. | *Optional* | `10` | 2.5 |
-| [servicebus-url](#u__10__servicebus_url) | `string` | Service Bus connection used for authentication. | *Optional* | | 2.2 |
+| [servicebus-url](#u__11__servicebus_url) | `string` | Service Bus connection used for authentication. | *Optional* | | 2.2 |
| topic | `string` | Service Bus topic to connect to. | *Optional* | | 2.2 |
| history | `object` | Configuration for fetching historical data on startup | *Optional* | | 2.2 |
| fromDateTime | `string` | Datetime boundary for historical data. | *Optional* | `"-P1D"` | 2.2 |
@@ -130,36 +130,36 @@ Has to be present for authenticationMethod SharedAccessKey. This should be Prima
##### Parameter details
-authenticationType
+authenticationType
**Since version:** `2.5` ∙ **Type:** `enum` ∙ **Cardinality:** `Optional` ∙ **Default value:** `"sharedaccesskey"`
-**Path:** /updaters/[10]
+**Path:** /updaters/[11]
**Enum values:** `sharedaccesskey` | `federatedidentity`
Which authentication type to use
-customMidnight
+customMidnight
**Since version:** `2.2` ∙ **Type:** `integer` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0`
-**Path:** /updaters/[10]
+**Path:** /updaters/[11]
Time on which time breaks into new day.
It is common that operating day date breaks a little bit later than midnight so that the switch happens when traffic is at the lowest point. Parameter uses 24-hour format. If the switch happens on 4 am then set this field to 4.
-fullyQualifiedNamespace
+fullyQualifiedNamespace
**Since version:** `2.5` ∙ **Type:** `string` ∙ **Cardinality:** `Optional`
-**Path:** /updaters/[10]
+**Path:** /updaters/[11]
Service Bus fully qualified namespace used for authentication.
Has to be present for authenticationMethod FederatedIdentity.
-servicebus-url
+servicebus-url
**Since version:** `2.2` ∙ **Type:** `string` ∙ **Cardinality:** `Optional`
-**Path:** /updaters/[10]
+**Path:** /updaters/[11]
Service Bus connection used for authentication.
diff --git a/docs/sandbox/siri/SiriUpdater.md b/docs/sandbox/siri/SiriUpdater.md
index f6c4c3f999f..72ab45d0f39 100644
--- a/docs/sandbox/siri/SiriUpdater.md
+++ b/docs/sandbox/siri/SiriUpdater.md
@@ -37,16 +37,16 @@ To enable the SIRI updater you need to add it to the updaters section of the `ro
| previewInterval | `duration` | TODO | *Optional* | | 2.0 |
| requestorRef | `string` | The requester reference. | *Optional* | | 2.0 |
| timeout | `duration` | The HTTP timeout to download the updates. | *Optional* | `"PT15S"` | 2.0 |
-| [url](#u__8__url) | `string` | The URL to send the HTTP requests to. | *Required* | | 2.0 |
-| [headers](#u__8__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 |
+| [url](#u__9__url) | `string` | The URL to send the HTTP requests to. | *Required* | | 2.0 |
+| [headers](#u__9__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 |
##### Parameter details
-url
+url
**Since version:** `2.0` ∙ **Type:** `string` ∙ **Cardinality:** `Required`
-**Path:** /updaters/[8]
+**Path:** /updaters/[9]
The URL to send the HTTP requests to.
@@ -58,10 +58,10 @@ renamed by the loader when processed:
-
+
**Since version:** `2.3` ∙ **Type:** `map of string` ∙ **Cardinality:** `Optional`
-**Path:** /updaters/[8]
+**Path:** /updaters/[9]
HTTP headers to add to the request. Any header key, value can be inserted.
@@ -93,25 +93,25 @@ HTTP headers to add to the request. Any header key, value can be inserted.
-| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since |
-|---------------------------------|:---------------:|--------------------------------------------------------------------------------------------------------|:----------:|---------------|:-----:|
-| type = "siri-sx-updater" | `enum` | The type of the updater. | *Required* | | 1.5 |
-| blockReadinessUntilInitialized | `boolean` | Whether catching up with the updates should block the readiness check from returning a 'ready' result. | *Optional* | `false` | 2.0 |
-| [earlyStart](#u__9__earlyStart) | `duration` | This value is subtracted from the actual validity defined in the message. | *Optional* | `"PT0S"` | 2.0 |
-| feedId | `string` | The ID of the feed to apply the updates to. | *Required* | | 2.0 |
-| frequency | `duration` | How often the updates should be retrieved. | *Optional* | `"PT1M"` | 2.0 |
-| requestorRef | `string` | The requester reference. | *Optional* | | 2.0 |
-| timeout | `duration` | The HTTP timeout to download the updates. | *Optional* | `"PT15S"` | 2.0 |
-| [url](#u__9__url) | `string` | The URL to send the HTTP requests to. Supports http/https and file protocol. | *Required* | | 2.0 |
-| [headers](#u__9__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 |
+| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since |
+|----------------------------------|:---------------:|--------------------------------------------------------------------------------------------------------|:----------:|---------------|:-----:|
+| type = "siri-sx-updater" | `enum` | The type of the updater. | *Required* | | 1.5 |
+| blockReadinessUntilInitialized | `boolean` | Whether catching up with the updates should block the readiness check from returning a 'ready' result. | *Optional* | `false` | 2.0 |
+| [earlyStart](#u__10__earlyStart) | `duration` | This value is subtracted from the actual validity defined in the message. | *Optional* | `"PT0S"` | 2.0 |
+| feedId | `string` | The ID of the feed to apply the updates to. | *Required* | | 2.0 |
+| frequency | `duration` | How often the updates should be retrieved. | *Optional* | `"PT1M"` | 2.0 |
+| requestorRef | `string` | The requester reference. | *Optional* | | 2.0 |
+| timeout | `duration` | The HTTP timeout to download the updates. | *Optional* | `"PT15S"` | 2.0 |
+| [url](#u__10__url) | `string` | The URL to send the HTTP requests to. Supports http/https and file protocol. | *Required* | | 2.0 |
+| [headers](#u__10__headers) | `map of string` | HTTP headers to add to the request. Any header key, value can be inserted. | *Optional* | | 2.3 |
##### Parameter details
-earlyStart
+earlyStart
**Since version:** `2.0` ∙ **Type:** `duration` ∙ **Cardinality:** `Optional` ∙ **Default value:** `"PT0S"`
-**Path:** /updaters/[9]
+**Path:** /updaters/[10]
This value is subtracted from the actual validity defined in the message.
@@ -119,10 +119,10 @@ Normally the planned departure time is used, so setting this to 10s will cause t
SX-message to be included in trip-results 10 seconds before the the planned departure
time.
-url
+url
**Since version:** `2.0` ∙ **Type:** `string` ∙ **Cardinality:** `Required`
-**Path:** /updaters/[9]
+**Path:** /updaters/[10]
The URL to send the HTTP requests to. Supports http/https and file protocol.
@@ -135,10 +135,10 @@ renamed by the loader when processed:
-
+
**Since version:** `2.3` ∙ **Type:** `map of string` ∙ **Cardinality:** `Optional`
-**Path:** /updaters/[9]
+**Path:** /updaters/[10]
HTTP headers to add to the request. Any header key, value can be inserted.
diff --git a/pom.xml b/pom.xml
index 0de0e7ef711..66d2919b3c4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -59,15 +59,15 @@
149
31.0
- 2.51
+ 2.51.1
2.17.0
- 3.1.5
+ 3.1.6
5.10.2
1.12.3
5.5.3
1.5.3
- 9.9.1
- 2.0.12
+ 9.10.0
+ 2.0.13
2.0.15
1.26
4.0.5
@@ -158,7 +158,7 @@
org.apache.maven.plugins
maven-jar-plugin
- 3.3.0
+ 3.4.0
@@ -185,7 +185,7 @@
org.apache.maven.plugins
maven-source-plugin
- 3.3.0
+ 3.3.1
attach-sources
@@ -312,7 +312,7 @@
org.jacoco
jacoco-maven-plugin
- 0.8.11
+ 0.8.12
-
- com.googlecode.json-simple
- json-simple
- 1.1.1
-
-
-
- junit
- junit
-
-
-
-
@@ -688,7 +674,7 @@
org.entur.gbfs
gbfs-java-model
- 3.0.26
+ 3.1.1
@@ -707,7 +693,7 @@
com.tngtech.archunit
archunit
- 1.2.1
+ 1.3.0
test
diff --git a/renovate.json5 b/renovate.json5
index 8a7f57e6764..b3472c1a0d1 100644
--- a/renovate.json5
+++ b/renovate.json5
@@ -46,14 +46,21 @@
// noise, so we slow it down a bit
{
"matchPackageNames": [
- "org.entur.gbfs:gbfs-java-model",
- "ch.qos.logback:logback-classic",
- "io.github.git-commit-id:git-commit-id-maven-plugin"
+ "org.entur.gbfs:gbfs-java-model"
],
"matchUpdateTypes": ["patch"],
"schedule": "on the 18th day of the month",
"automerge": true
},
+ {
+ "matchPackageNames": [
+ "ch.qos.logback:logback-classic",
+ "io.github.git-commit-id:git-commit-id-maven-plugin",
+ "org.apache.maven.plugins:maven-gpg-plugin"
+ ],
+ "schedule": "on the 19th day of the month",
+ "automerge": true
+ },
{
// https://github.com/graphql-java-kickstart/renovate-config/blob/main/default.json
"description": "GraphQL Java (ignoring snapshot builds)",
@@ -110,12 +117,12 @@
"org.apache.commons:commons-compress", // only used by tests
// maven plugins
"org.codehaus.mojo:build-helper-maven-plugin",
- "org.apache.maven.plugins:maven-gpg-plugin",
"org.apache.maven.plugins:maven-source-plugin",
"com.hubspot.maven.plugins:prettier-maven-plugin",
"com.google.cloud.tools:jib-maven-plugin",
"org.apache.maven.plugins:maven-shade-plugin",
- "org.apache.maven.plugins:maven-compiler-plugin"
+ "org.apache.maven.plugins:maven-compiler-plugin",
+ "org.apache.maven.plugins:maven-jar-plugin"
],
"matchPackagePrefixes": [
"org.junit.jupiter:",
diff --git a/src/client/debug-client-preview/index.html b/src/client/debug-client-preview/index.html
index 3973571de30..1b561ffc656 100644
--- a/src/client/debug-client-preview/index.html
+++ b/src/client/debug-client-preview/index.html
@@ -5,8 +5,8 @@
OTP Debug Client
-
-
+
+
diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/TestTransitService.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/TestTransitService.java
new file mode 100644
index 00000000000..d187b611ef3
--- /dev/null
+++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/TestTransitService.java
@@ -0,0 +1,23 @@
+package org.opentripplanner.ext.vectortiles.layers;
+
+import java.util.Set;
+import org.opentripplanner.transit.model._data.TransitModelForTest;
+import org.opentripplanner.transit.model.basic.TransitMode;
+import org.opentripplanner.transit.model.network.Route;
+import org.opentripplanner.transit.model.site.StopLocation;
+import org.opentripplanner.transit.service.DefaultTransitService;
+import org.opentripplanner.transit.service.TransitModel;
+
+public class TestTransitService extends DefaultTransitService {
+
+ public TestTransitService(TransitModel transitModel) {
+ super(transitModel);
+ }
+
+ @Override
+ public Set getRoutesForStop(StopLocation stop) {
+ return Set.of(
+ TransitModelForTest.route("1").withMode(TransitMode.RAIL).withGtfsType(100).build()
+ );
+ }
+}
diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stations/DigitransitStationPropertyMapperTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stations/DigitransitStationPropertyMapperTest.java
new file mode 100644
index 00000000000..da85285954d
--- /dev/null
+++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stations/DigitransitStationPropertyMapperTest.java
@@ -0,0 +1,46 @@
+package org.opentripplanner.ext.vectortiles.layers.stations;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.opentripplanner.transit.model._data.TransitModelForTest.id;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+import org.opentripplanner.ext.vectortiles.layers.TestTransitService;
+import org.opentripplanner.framework.i18n.I18NString;
+import org.opentripplanner.transit.model._data.TransitModelForTest;
+import org.opentripplanner.transit.model.framework.Deduplicator;
+import org.opentripplanner.transit.model.site.Station;
+import org.opentripplanner.transit.service.StopModel;
+import org.opentripplanner.transit.service.TransitModel;
+
+public class DigitransitStationPropertyMapperTest {
+
+ @Test
+ void map() {
+ var deduplicator = new Deduplicator();
+ var transitModel = new TransitModel(new StopModel(), deduplicator);
+ transitModel.index();
+ var transitService = new TestTransitService(transitModel);
+
+ var mapper = DigitransitStationPropertyMapper.create(transitService, Locale.US);
+
+ var station = Station
+ .of(id("a-station"))
+ .withCoordinate(1, 1)
+ .withName(I18NString.of("A station"))
+ .build();
+
+ TransitModelForTest.of().stop("stop-1").withParentStation(station).build();
+
+ Map map = new HashMap<>();
+ mapper.map(station).forEach(o -> map.put(o.key(), o.value()));
+
+ assertEquals("F:a-station", map.get("gtfsId"));
+ assertEquals("A station", map.get("name"));
+ assertEquals("", map.get("type"));
+ assertEquals("[{\"mode\":\"RAIL\",\"shortName\":\"R1\"}]", map.get("routes"));
+ assertEquals("[\"F:stop-1\"]", map.get("stops"));
+ }
+}
diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/RealtimeStopsLayerTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/RealtimeStopsLayerTest.java
new file mode 100644
index 00000000000..8f2e1f94fa6
--- /dev/null
+++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/RealtimeStopsLayerTest.java
@@ -0,0 +1,104 @@
+package org.opentripplanner.ext.vectortiles.layers.stops;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.opentripplanner.framework.time.TimeUtils.time;
+import static org.opentripplanner.model.plan.TestItineraryBuilder.newItinerary;
+
+import java.time.ZonedDateTime;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.opentripplanner._support.time.ZoneIds;
+import org.opentripplanner.ext.realtimeresolver.RealtimeResolver;
+import org.opentripplanner.framework.i18n.I18NString;
+import org.opentripplanner.model.plan.Place;
+import org.opentripplanner.routing.alertpatch.AlertEffect;
+import org.opentripplanner.routing.alertpatch.EntitySelector;
+import org.opentripplanner.routing.alertpatch.TimePeriod;
+import org.opentripplanner.routing.alertpatch.TransitAlert;
+import org.opentripplanner.routing.impl.TransitAlertServiceImpl;
+import org.opentripplanner.routing.services.TransitAlertService;
+import org.opentripplanner.transit.model._data.TransitModelForTest;
+import org.opentripplanner.transit.model.framework.Deduplicator;
+import org.opentripplanner.transit.model.framework.FeedScopedId;
+import org.opentripplanner.transit.model.network.Route;
+import org.opentripplanner.transit.model.site.RegularStop;
+import org.opentripplanner.transit.service.DefaultTransitService;
+import org.opentripplanner.transit.service.StopModel;
+import org.opentripplanner.transit.service.TransitModel;
+
+public class RealtimeStopsLayerTest {
+
+ private RegularStop stop;
+ private RegularStop stop2;
+
+ @BeforeEach
+ public void setUp() {
+ var name = I18NString.of("name");
+ var desc = I18NString.of("desc");
+ stop =
+ StopModel
+ .of()
+ .regularStop(new FeedScopedId("F", "name"))
+ .withName(name)
+ .withDescription(desc)
+ .withCoordinate(50, 10)
+ .build();
+ stop2 =
+ StopModel
+ .of()
+ .regularStop(new FeedScopedId("F", "name"))
+ .withName(name)
+ .withDescription(desc)
+ .withCoordinate(51, 10)
+ .build();
+ }
+
+ @Test
+ void realtimeStopLayer() {
+ var deduplicator = new Deduplicator();
+ var transitModel = new TransitModel(new StopModel(), deduplicator);
+ transitModel.initTimeZone(ZoneIds.HELSINKI);
+ transitModel.index();
+ var alertService = new TransitAlertServiceImpl(transitModel);
+ var transitService = new DefaultTransitService(transitModel) {
+ @Override
+ public TransitAlertService getTransitAlertService() {
+ return alertService;
+ }
+ };
+
+ Route route = TransitModelForTest.route("route").build();
+ var itinerary = newItinerary(Place.forStop(stop), time("11:00"))
+ .bus(route, 1, time("11:05"), time("11:20"), Place.forStop(stop2))
+ .build();
+ var startDate = ZonedDateTime.now(ZoneIds.HELSINKI).minusDays(1).toEpochSecond();
+ var endDate = ZonedDateTime.now(ZoneIds.HELSINKI).plusDays(1).toEpochSecond();
+ var alert = TransitAlert
+ .of(stop.getId())
+ .addEntity(new EntitySelector.Stop(stop.getId()))
+ .addTimePeriod(new TimePeriod(startDate, endDate))
+ .withEffect(AlertEffect.NO_SERVICE)
+ .build();
+ transitService.getTransitAlertService().setAlerts(List.of(alert));
+
+ var itineraries = List.of(itinerary);
+ RealtimeResolver.populateLegsWithRealtime(itineraries, transitService);
+
+ DigitransitRealtimeStopPropertyMapper mapper = new DigitransitRealtimeStopPropertyMapper(
+ transitService,
+ new Locale("en-US")
+ );
+
+ Map map = new HashMap<>();
+ mapper.map(stop).forEach(o -> map.put(o.key(), o.value()));
+
+ assertEquals("F:name", map.get("gtfsId"));
+ assertEquals("name", map.get("name"));
+ assertEquals("desc", map.get("desc"));
+ assertEquals(true, map.get("closedByServiceAlert"));
+ }
+}
diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/StopsLayerTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/StopsLayerTest.java
index a914cf9db6c..4c3e60701bd 100644
--- a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/StopsLayerTest.java
+++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/stops/StopsLayerTest.java
@@ -1,32 +1,16 @@
package org.opentripplanner.ext.vectortiles.layers.stops;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.opentripplanner.framework.time.TimeUtils.time;
-import static org.opentripplanner.model.plan.TestItineraryBuilder.newItinerary;
-import java.time.Instant;
-import java.time.LocalDate;
-import java.time.ZonedDateTime;
import java.util.HashMap;
-import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.opentripplanner._support.time.ZoneIds;
-import org.opentripplanner.ext.realtimeresolver.RealtimeResolver;
+import org.opentripplanner.ext.vectortiles.layers.TestTransitService;
import org.opentripplanner.framework.i18n.TranslatedString;
-import org.opentripplanner.model.plan.Place;
-import org.opentripplanner.routing.alertpatch.AlertEffect;
-import org.opentripplanner.routing.alertpatch.EntitySelector;
-import org.opentripplanner.routing.alertpatch.TimePeriod;
-import org.opentripplanner.routing.alertpatch.TransitAlert;
-import org.opentripplanner.routing.impl.TransitAlertServiceImpl;
-import org.opentripplanner.routing.services.TransitAlertService;
-import org.opentripplanner.transit.model._data.TransitModelForTest;
import org.opentripplanner.transit.model.framework.Deduplicator;
import org.opentripplanner.transit.model.framework.FeedScopedId;
-import org.opentripplanner.transit.model.network.Route;
import org.opentripplanner.transit.model.site.RegularStop;
import org.opentripplanner.transit.service.DefaultTransitService;
import org.opentripplanner.transit.service.StopModel;
@@ -35,7 +19,6 @@
public class StopsLayerTest {
private RegularStop stop;
- private RegularStop stop2;
@BeforeEach
public void setUp() {
@@ -67,14 +50,6 @@ public void setUp() {
.withDescription(descTranslations)
.withCoordinate(50, 10)
.build();
- stop2 =
- StopModel
- .of()
- .regularStop(new FeedScopedId("F", "name"))
- .withName(nameTranslations)
- .withDescription(descTranslations)
- .withCoordinate(51, 10)
- .build();
}
@Test
@@ -82,7 +57,7 @@ public void digitransitStopPropertyMapperTest() {
var deduplicator = new Deduplicator();
var transitModel = new TransitModel(new StopModel(), deduplicator);
transitModel.index();
- var transitService = new DefaultTransitService(transitModel);
+ var transitService = new TestTransitService(transitModel);
DigitransitStopPropertyMapper mapper = DigitransitStopPropertyMapper.create(
transitService,
@@ -95,6 +70,7 @@ public void digitransitStopPropertyMapperTest() {
assertEquals("F:name", map.get("gtfsId"));
assertEquals("name", map.get("name"));
assertEquals("desc", map.get("desc"));
+ assertEquals("[{\"gtfsType\":100}]", map.get("routes"));
}
@Test
@@ -115,49 +91,4 @@ public void digitransitStopPropertyMapperTranslationTest() {
assertEquals("nameDE", map.get("name"));
assertEquals("descDE", map.get("desc"));
}
-
- @Test
- public void digitransitRealtimeStopPropertyMapperTest() {
- var deduplicator = new Deduplicator();
- var transitModel = new TransitModel(new StopModel(), deduplicator);
- transitModel.initTimeZone(ZoneIds.HELSINKI);
- transitModel.index();
- var alertService = new TransitAlertServiceImpl(transitModel);
- var transitService = new DefaultTransitService(transitModel) {
- @Override
- public TransitAlertService getTransitAlertService() {
- return alertService;
- }
- };
-
- Route route = TransitModelForTest.route("route").build();
- var itinerary = newItinerary(Place.forStop(stop), time("11:00"))
- .bus(route, 1, time("11:05"), time("11:20"), Place.forStop(stop2))
- .build();
- var startDate = ZonedDateTime.now(ZoneIds.HELSINKI).minusDays(1).toEpochSecond();
- var endDate = ZonedDateTime.now(ZoneIds.HELSINKI).plusDays(1).toEpochSecond();
- var alert = TransitAlert
- .of(stop.getId())
- .addEntity(new EntitySelector.Stop(stop.getId()))
- .addTimePeriod(new TimePeriod(startDate, endDate))
- .withEffect(AlertEffect.NO_SERVICE)
- .build();
- transitService.getTransitAlertService().setAlerts(List.of(alert));
-
- var itineraries = List.of(itinerary);
- RealtimeResolver.populateLegsWithRealtime(itineraries, transitService);
-
- DigitransitRealtimeStopPropertyMapper mapper = new DigitransitRealtimeStopPropertyMapper(
- transitService,
- new Locale("en-US")
- );
-
- Map map = new HashMap<>();
- mapper.map(stop).forEach(o -> map.put(o.key(), o.value()));
-
- assertEquals("F:name", map.get("gtfsId"));
- assertEquals("name", map.get("name"));
- assertEquals("desc", map.get("desc"));
- assertEquals(true, map.get("closedByServiceAlert"));
- }
}
diff --git a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/VehicleParkingGroupsLayerTest.java b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/VehicleParkingGroupsLayerTest.java
index 1ec7d042894..60ba9100f43 100644
--- a/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/VehicleParkingGroupsLayerTest.java
+++ b/src/ext-test/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/VehicleParkingGroupsLayerTest.java
@@ -144,7 +144,7 @@ public void digitransitVehicleParkingGroupPropertyMapperTest() {
assertEquals("groupName", map.get("name").toString());
assertEquals(
- "[{\"bicyclePlaces\":false,\"carPlaces\":true,\"name\":\"name\",\"id\":\"F:id\"}]",
+ "[{\"carPlaces\":true,\"bicyclePlaces\":false,\"id\":\"F:id\",\"name\":\"name\"}]",
map.get("vehicleParking")
);
}
@@ -162,7 +162,7 @@ public void digitransitVehicleParkingGroupPropertyMapperTranslationTest() {
assertEquals("groupDE", map.get("name").toString());
assertEquals(
- "[{\"bicyclePlaces\":false,\"carPlaces\":true,\"name\":\"DE\",\"id\":\"F:id\"}]",
+ "[{\"carPlaces\":true,\"bicyclePlaces\":false,\"id\":\"F:id\",\"name\":\"DE\"}]",
map.get("vehicleParking")
);
}
diff --git a/src/ext-test/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdaterTest.java b/src/ext-test/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdaterTest.java
new file mode 100644
index 00000000000..f931e3d964e
--- /dev/null
+++ b/src/ext-test/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdaterTest.java
@@ -0,0 +1,51 @@
+package org.opentripplanner.ext.vehicleparking.noi;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.time.Duration;
+import org.junit.jupiter.api.Test;
+import org.opentripplanner.test.support.ResourceLoader;
+import org.opentripplanner.updater.spi.HttpHeaders;
+
+class NoiUpdaterTest {
+
+ @Test
+ void parse() {
+ var uri = ResourceLoader.of(this).uri("stations.json");
+ var parameters = new NoiUpdaterParameters(
+ "noi",
+ uri,
+ "noi",
+ Duration.ofSeconds(30),
+ HttpHeaders.empty()
+ );
+ var updater = new NoiUpdater(parameters);
+ updater.update();
+ var lots = updater.getUpdates();
+
+ assertEquals(14, lots.size());
+
+ lots.forEach(l -> assertNotNull(l.getName()));
+
+ var first = lots.getFirst();
+ assertEquals("noi:105", first.getId().toString());
+ assertEquals("(46.49817, 11.35726)", first.getCoordinate().toString());
+ assertEquals("P05 - Laurin", first.getName().toString());
+ assertEquals(57, first.getAvailability().getCarSpaces());
+ assertEquals(90, first.getCapacity().getCarSpaces());
+
+ var last = lots.getLast();
+ assertEquals(
+ "noi:935af00d-aa5f-eb11-9889-501ac5928d31-0.8458736393052522",
+ last.getId().toString()
+ );
+ assertEquals("(46.5057, 11.3395)", last.getCoordinate().toString());
+ assertEquals(
+ "Parksensoren Bozen - PNI Parksensor Nr.10 Commissariato - Viale Eugenio di savoia",
+ last.getName().toString()
+ );
+ assertEquals(0, last.getAvailability().getCarSpaces());
+ assertEquals(1, last.getCapacity().getCarSpaces());
+ }
+}
diff --git a/src/ext-test/resources/org/opentripplanner/ext/vehicleparking/noi/stations.json b/src/ext-test/resources/org/opentripplanner/ext/vehicleparking/noi/stations.json
new file mode 100644
index 00000000000..2bbb07ac98b
--- /dev/null
+++ b/src/ext-test/resources/org/opentripplanner/ext/vehicleparking/noi/stations.json
@@ -0,0 +1,159 @@
+{
+ "last_updated": 1711368767,
+ "ttl": 0,
+ "version": "3.0.0",
+ "data": {
+ "stations": [
+ {
+ "type": "station",
+ "station_id": "105",
+ "name": "P05 - Laurin",
+ "lat": 46.498174,
+ "lon": 11.357255,
+ "city": "Bolzano - Bozen",
+ "capacity": 90,
+ "free": 57
+ },
+ {
+ "type": "station",
+ "station_id": "TRENTO:areaexsitviacanestrinip1",
+ "name": "Area ex SIT via Canestrini - P1",
+ "lat": 46.0691,
+ "lon": 11.1162,
+ "address": "Lung'Adige Monte Grappa",
+ "city": "Trento",
+ "capacity": 300,
+ "free": 0
+ },
+ {
+ "type": "station",
+ "station_id": "ROVERETO:asm",
+ "name": "A.S.M.",
+ "lat": 45.893593,
+ "lon": 11.036507,
+ "address": "Piazzale ex-A.S.M - Via Manzoni - Rovereto",
+ "city": "Rovereto",
+ "capacity": 145,
+ "free": 42
+ },
+ {
+ "type": "station",
+ "station_id": "ROVERETO:centrostorico",
+ "name": "Centro Storico",
+ "lat": 45.890306,
+ "lon": 11.045004,
+ "address": "Viale dei Colli - Rovereto",
+ "city": "Rovereto",
+ "capacity": 143,
+ "free": 20
+ },
+ {
+ "type": "station",
+ "station_id": "ROVERETO:mart",
+ "name": "Mart",
+ "lat": 45.894705,
+ "lon": 11.044661,
+ "address": "Mart - Via Sticcotta - Rovereto",
+ "city": "Rovereto",
+ "capacity": 224,
+ "free": 224
+ },
+ {
+ "type": "sensor",
+ "station_id": "001bc50670100557-0.30188412882192206",
+ "group_name": "area viale Druso",
+ "group_id": "area_viale_druso",
+ "name": "piazzetta Mazzoni 3",
+ "lat": 46.495025,
+ "lon": 11.347069,
+ "address": "area viale Druso",
+ "city": "Bolzano - Bozen",
+ "free": false
+ },
+ {
+ "type": "sensor",
+ "station_id": "001bc50670100541-0.9632040952321754",
+ "group_name": "Via A. Rosmini 22-26",
+ "group_id": "via_a_rosmini_22_26",
+ "name": "Via A. Rosmini 22-26",
+ "lat": 46.498292,
+ "lon": 11.348031,
+ "address": "Via A. Rosmini 22-26",
+ "city": "Bolzano - Bozen",
+ "free": false
+ },
+ {
+ "type": "sensor",
+ "station_id": "001bc50670112a6b-0.6239539554369709",
+ "group_name": "Via Amalfi",
+ "group_id": "via_amalfi",
+ "name": "Via Amalfi angolo Via Druso",
+ "lat": 46.495283,
+ "lon": 11.332472,
+ "address": "Via Amalfi",
+ "city": "Bolzano - Bozen",
+ "free": false
+ },
+ {
+ "type": "sensor",
+ "station_id": "001bc5067010064d-0.18879954213280836",
+ "group_name": "area viale Druso",
+ "group_id": "area_viale_druso",
+ "name": "piazzetta Mazzoni 4",
+ "lat": 46.495056,
+ "lon": 11.347056,
+ "address": "area viale Druso",
+ "city": "Bolzano - Bozen",
+ "free": false
+ },
+ {
+ "type": "sensor",
+ "station_id": "001bc50670112976-0.4989211141789258",
+ "group_name": "Viale Druso 237",
+ "group_id": "viale_druso_237",
+ "name": "Viale Druso 237",
+ "lat": 46.495,
+ "lon": 11.328703,
+ "address": "Viale Druso 237",
+ "city": "Bolzano - Bozen",
+ "free": true
+ },
+ {
+ "type": "sensor",
+ "station_id": "9398a35b-ef3d-eb11-b9ed-0050f244b601-0.12775006754129703",
+ "group_id": "",
+ "name": "Parksensoren Bozen - PNI Parksensor Nr.3 Siegesplatz Parkplatz",
+ "lat": 46.501,
+ "lon": 11.3431,
+ "free": true
+ },
+ {
+ "type": "sensor",
+ "station_id": "7776d25f-f03d-eb11-b9ed-0050f244b601-0.4355636862513992",
+ "group_id": "",
+ "name": "Parksensoren Bozen - PNI Parksensor Nr.5 DucaDaostastrasse",
+ "lat": 46.4953,
+ "lon": 11.3396,
+ "free": false
+ },
+ {
+ "type": "sensor",
+ "station_id": "e3e26add-ee3d-eb11-b9ed-0050f244b601-0.8423578257530036",
+ "group_id": "",
+ "name": "Parksensoren Bozen - PNI Parksensor Nr.4 Bahnhof BZ Richtung Rittnerseilbahn",
+ "lat": 46.497,
+ "lon": 11.3583,
+ "free": false
+ },
+ {
+ "type": "sensor",
+ "station_id": "935af00d-aa5f-eb11-9889-501ac5928d31-0.8458736393052522",
+ "group_id": "",
+ "name": "Parksensoren Bozen - PNI Parksensor Nr.10 Commissariato - Viale Eugenio di savoia",
+ "lat": 46.5057,
+ "lon": 11.3395,
+ "free": false
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stations/DigitransitStationPropertyMapper.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stations/DigitransitStationPropertyMapper.java
index a828cd37a7c..18b4a5f388d 100644
--- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stations/DigitransitStationPropertyMapper.java
+++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stations/DigitransitStationPropertyMapper.java
@@ -1,13 +1,14 @@
package org.opentripplanner.ext.vectortiles.layers.stations;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
-import java.util.Map;
import java.util.stream.Collectors;
-import org.json.simple.JSONArray;
import org.opentripplanner.apis.support.mapping.PropertyMapper;
import org.opentripplanner.framework.i18n.I18NStringMapper;
+import org.opentripplanner.framework.json.ObjectMappers;
import org.opentripplanner.inspector.vector.KeyValue;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.opentripplanner.transit.model.site.Station;
@@ -16,6 +17,7 @@
public class DigitransitStationPropertyMapper extends PropertyMapper {
+ private static final ObjectMapper OBJECT_MAPPER = ObjectMappers.ignoringExtraFields();
private final TransitService transitService;
private final I18NStringMapper i18NStringMapper;
@@ -33,41 +35,47 @@ public static DigitransitStationPropertyMapper create(
@Override
public Collection map(Station station) {
- var childStops = station.getChildStops();
-
- return List.of(
- new KeyValue("gtfsId", station.getId().toString()),
- new KeyValue("name", i18NStringMapper.mapNonnullToApi(station.getName())),
- new KeyValue(
- "type",
- childStops
- .stream()
- .flatMap(stop -> transitService.getPatternsForStop(stop).stream())
- .map(tripPattern -> tripPattern.getMode().name())
- .distinct()
- .collect(Collectors.joining(","))
- ),
- new KeyValue(
- "stops",
- JSONArray.toJSONString(
- childStops.stream().map(StopLocation::getId).map(FeedScopedId::toString).toList()
- )
- ),
- new KeyValue(
- "routes",
- JSONArray.toJSONString(
+ try {
+ var childStops = station.getChildStops();
+ return List.of(
+ new KeyValue("gtfsId", station.getId().toString()),
+ new KeyValue("name", i18NStringMapper.mapNonnullToApi(station.getName())),
+ new KeyValue(
+ "type",
childStops
.stream()
- .flatMap(stop -> transitService.getRoutesForStop(stop).stream())
+ .flatMap(stop -> transitService.getPatternsForStop(stop).stream())
+ .map(tripPattern -> tripPattern.getMode().name())
.distinct()
- .map(route ->
- route.getShortName() == null
- ? Map.of("mode", route.getMode().name())
- : Map.of("mode", route.getMode().name(), "shortName", route.getShortName())
- )
- .collect(Collectors.toList())
+ .collect(Collectors.joining(","))
+ ),
+ new KeyValue(
+ "stops",
+ OBJECT_MAPPER.writeValueAsString(
+ childStops.stream().map(StopLocation::getId).map(FeedScopedId::toString).toList()
+ )
+ ),
+ new KeyValue(
+ "routes",
+ OBJECT_MAPPER.writeValueAsString(
+ childStops
+ .stream()
+ .flatMap(stop -> transitService.getRoutesForStop(stop).stream())
+ .distinct()
+ .map(route -> {
+ var obj = OBJECT_MAPPER.createObjectNode();
+ obj.put("mode", route.getMode().name());
+ if (route.getShortName() != null) {
+ obj.put("shortName", route.getShortName());
+ }
+ return obj;
+ })
+ .toList()
+ )
)
- )
- );
+ );
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
}
}
diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/DigitransitStopPropertyMapper.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/DigitransitStopPropertyMapper.java
index 643ed63b7f8..d10e221b1d5 100644
--- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/DigitransitStopPropertyMapper.java
+++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/stops/DigitransitStopPropertyMapper.java
@@ -1,16 +1,16 @@
package org.opentripplanner.ext.vectortiles.layers.stops;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
import org.opentripplanner.apis.support.mapping.PropertyMapper;
-import org.opentripplanner.framework.collection.ListUtils;
import org.opentripplanner.framework.i18n.I18NStringMapper;
+import org.opentripplanner.framework.json.ObjectMappers;
import org.opentripplanner.inspector.vector.KeyValue;
import org.opentripplanner.transit.model.network.TripPattern;
import org.opentripplanner.transit.model.site.RegularStop;
@@ -18,6 +18,7 @@
public class DigitransitStopPropertyMapper extends PropertyMapper {
+ private static final ObjectMapper OBJECT_MAPPER = ObjectMappers.ignoringExtraFields();
private final TransitService transitService;
private final I18NStringMapper i18NStringMapper;
@@ -59,17 +60,20 @@ protected static Collection getBaseKeyValues(
}
protected static String getRoutes(TransitService transitService, RegularStop stop) {
- return JSONArray.toJSONString(
- transitService
+ try {
+ var objects = transitService
.getRoutesForStop(stop)
.stream()
.map(route -> {
- JSONObject routeObject = new JSONObject();
+ var routeObject = OBJECT_MAPPER.createObjectNode();
routeObject.put("gtfsType", route.getGtfsType());
return routeObject;
})
- .toList()
- );
+ .toList();
+ return OBJECT_MAPPER.writeValueAsString(objects);
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
}
protected static String getType(TransitService transitService, RegularStop stop) {
diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/DigitransitVehicleParkingGroupPropertyMapper.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/DigitransitVehicleParkingGroupPropertyMapper.java
index 33f415c157a..efafc969619 100644
--- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/DigitransitVehicleParkingGroupPropertyMapper.java
+++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/DigitransitVehicleParkingGroupPropertyMapper.java
@@ -1,17 +1,19 @@
package org.opentripplanner.ext.vectortiles.layers.vehicleparkings;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
import org.opentripplanner.apis.support.mapping.PropertyMapper;
import org.opentripplanner.framework.i18n.I18NStringMapper;
+import org.opentripplanner.framework.json.ObjectMappers;
import org.opentripplanner.inspector.vector.KeyValue;
public class DigitransitVehicleParkingGroupPropertyMapper
extends PropertyMapper {
+ private static final ObjectMapper OBJECT_MAPPER = ObjectMappers.ignoringExtraFields();
private final I18NStringMapper i18NStringMapper;
public DigitransitVehicleParkingGroupPropertyMapper(Locale locale) {
@@ -24,25 +26,28 @@ public static DigitransitVehicleParkingGroupPropertyMapper create(Locale locale)
@Override
protected Collection map(VehicleParkingAndGroup parkingAndGroup) {
- var group = parkingAndGroup.vehicleParkingGroup();
- String parking = JSONArray.toJSONString(
- parkingAndGroup
+ try {
+ var group = parkingAndGroup.vehicleParkingGroup();
+ var lots = parkingAndGroup
.vehicleParking()
.stream()
.map(vehicleParkingPlace -> {
- JSONObject parkingObject = new JSONObject();
+ var parkingObject = OBJECT_MAPPER.createObjectNode();
parkingObject.put("carPlaces", vehicleParkingPlace.hasCarPlaces());
parkingObject.put("bicyclePlaces", vehicleParkingPlace.hasBicyclePlaces());
parkingObject.put("id", vehicleParkingPlace.getId().toString());
parkingObject.put("name", i18NStringMapper.mapToApi(vehicleParkingPlace.getName()));
return parkingObject;
})
- .toList()
- );
- return List.of(
- new KeyValue("id", group.id().toString()),
- new KeyValue("name", i18NStringMapper.mapToApi(group.name())),
- new KeyValue("vehicleParking", parking)
- );
+ .toList();
+ var string = OBJECT_MAPPER.writeValueAsString(lots);
+ return List.of(
+ new KeyValue("id", group.id().toString()),
+ new KeyValue("name", i18NStringMapper.mapToApi(group.name())),
+ new KeyValue("vehicleParking", string)
+ );
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
}
}
diff --git a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/StadtnaviVehicleParkingPropertyMapper.java b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/StadtnaviVehicleParkingPropertyMapper.java
index c938f9736fd..bccc2b4de4d 100644
--- a/src/ext/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/StadtnaviVehicleParkingPropertyMapper.java
+++ b/src/ext/java/org/opentripplanner/ext/vectortiles/layers/vehicleparkings/StadtnaviVehicleParkingPropertyMapper.java
@@ -1,11 +1,12 @@
package org.opentripplanner.ext.vectortiles.layers.vehicleparkings;
+import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
-import org.json.simple.JSONObject;
import org.opentripplanner.apis.support.mapping.PropertyMapper;
import org.opentripplanner.framework.i18n.I18NStringMapper;
+import org.opentripplanner.framework.json.ObjectMappers;
import org.opentripplanner.inspector.vector.KeyValue;
import org.opentripplanner.model.calendar.openinghours.OsmOpeningHoursSupport;
import org.opentripplanner.routing.vehicle_parking.VehicleParking;
@@ -13,6 +14,7 @@
public class StadtnaviVehicleParkingPropertyMapper extends PropertyMapper {
+ private static final ObjectMapper OBJECT_MAPPER = ObjectMappers.ignoringExtraFields();
private final DigitransitVehicleParkingPropertyMapper digitransitMapper;
private final I18NStringMapper i18NStringMapper;
@@ -57,13 +59,13 @@ private static List mapPlaces(String key, VehicleParkingSpaces places)
return List.of();
}
- var json = new JSONObject();
+ var json = OBJECT_MAPPER.createObjectNode();
json.put("bicyclePlaces", places.getBicycleSpaces());
json.put("carPlaces", places.getCarSpaces());
json.put("wheelchairAccessibleCarPlaces", places.getWheelchairAccessibleCarSpaces());
return List.of(
- new KeyValue(key, JSONObject.toJSONString(json)),
+ new KeyValue(key, json.toString()),
new KeyValue(subKey(key, "bicyclePlaces"), places.getBicycleSpaces()),
new KeyValue(subKey(key, "carPlaces"), places.getCarSpaces()),
new KeyValue(
diff --git a/src/ext/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdater.java b/src/ext/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdater.java
new file mode 100644
index 00000000000..d5ef7e63d13
--- /dev/null
+++ b/src/ext/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdater.java
@@ -0,0 +1,77 @@
+package org.opentripplanner.ext.vehicleparking.noi;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import org.opentripplanner.framework.geometry.WgsCoordinate;
+import org.opentripplanner.framework.i18n.NonLocalizedString;
+import org.opentripplanner.framework.tostring.ToStringBuilder;
+import org.opentripplanner.routing.vehicle_parking.VehicleParking;
+import org.opentripplanner.routing.vehicle_parking.VehicleParkingSpaces;
+import org.opentripplanner.routing.vehicle_parking.VehicleParkingState;
+import org.opentripplanner.transit.model.framework.FeedScopedId;
+import org.opentripplanner.updater.spi.GenericJsonDataSource;
+
+/**
+ * Vehicle parking updater class for NOI's open data hub format APIs.
+ */
+public class NoiUpdater extends GenericJsonDataSource {
+
+ private static final String JSON_PARSE_PATH = "data/stations";
+ private final NoiUpdaterParameters params;
+
+ public NoiUpdater(NoiUpdaterParameters parameters) {
+ super(parameters.url().toString(), JSON_PARSE_PATH, parameters.httpHeaders());
+ this.params = parameters;
+ }
+
+ @Override
+ protected VehicleParking parseElement(JsonNode jsonNode) {
+ var type = jsonNode.path("type").textValue();
+ VehicleParkingSpaces capacity, availability;
+ if (type.equals("station")) {
+ capacity = extractSpaces(jsonNode, "capacity");
+ availability = extractSpaces(jsonNode, "free");
+ } else if (type.equals("sensor")) {
+ capacity = VehicleParkingSpaces.builder().carSpaces(1).build();
+ var isFree = jsonNode.path("free").asBoolean();
+ availability = VehicleParkingSpaces.builder().carSpaces(isFree ? 1 : 0).build();
+ } else {
+ throw new IllegalArgumentException("Unknown type '%s'".formatted(type));
+ }
+
+ var vehicleParkId = new FeedScopedId(params.feedId(), jsonNode.path("station_id").asText());
+ var name = new NonLocalizedString(jsonNode.path("name").asText());
+ double lat = jsonNode.path("lat").asDouble();
+ double lon = jsonNode.path("lon").asDouble();
+ var coordinate = new WgsCoordinate(lat, lon);
+ VehicleParking.VehicleParkingEntranceCreator entrance = builder ->
+ builder
+ .entranceId(new FeedScopedId(params.feedId(), vehicleParkId.getId() + "/entrance"))
+ .coordinate(coordinate)
+ .walkAccessible(true)
+ .carAccessible(true);
+
+ return VehicleParking
+ .builder()
+ .id(vehicleParkId)
+ .name(name)
+ .state(VehicleParkingState.OPERATIONAL)
+ .coordinate(coordinate)
+ .capacity(capacity)
+ .availability(availability)
+ .carPlaces(true)
+ .entrance(entrance)
+ .build();
+ }
+
+ private static VehicleParkingSpaces extractSpaces(JsonNode jsonNode, String free) {
+ return VehicleParkingSpaces.builder().carSpaces(jsonNode.get(free).asInt()).build();
+ }
+
+ @Override
+ public String toString() {
+ return ToStringBuilder
+ .of(this.getClass())
+ .addStr("url", this.params.url().toString())
+ .toString();
+ }
+}
diff --git a/src/ext/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdaterParameters.java b/src/ext/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdaterParameters.java
new file mode 100644
index 00000000000..371ffdc9f33
--- /dev/null
+++ b/src/ext/java/org/opentripplanner/ext/vehicleparking/noi/NoiUpdaterParameters.java
@@ -0,0 +1,25 @@
+package org.opentripplanner.ext.vehicleparking.noi;
+
+import java.net.URI;
+import java.time.Duration;
+import org.opentripplanner.updater.spi.HttpHeaders;
+import org.opentripplanner.updater.vehicle_parking.VehicleParkingSourceType;
+import org.opentripplanner.updater.vehicle_parking.VehicleParkingUpdaterParameters;
+
+/**
+ * Class that extends {@link VehicleParkingUpdaterParameters} with parameters required by {@link
+ * NoiUpdater}.
+ */
+public record NoiUpdaterParameters(
+ String configRef,
+ URI url,
+ String feedId,
+ Duration frequency,
+ HttpHeaders httpHeaders
+)
+ implements VehicleParkingUpdaterParameters {
+ @Override
+ public VehicleParkingSourceType sourceType() {
+ return VehicleParkingSourceType.NOI_OPEN_DATA_HUB;
+ }
+}
diff --git a/src/main/java/org/opentripplanner/apis/transmodel/mapping/FilterMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/FilterMapper.java
index 9141ce4c104..71d2691e47a 100644
--- a/src/main/java/org/opentripplanner/apis/transmodel/mapping/FilterMapper.java
+++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/FilterMapper.java
@@ -83,7 +83,7 @@ static void mapFilterOldWay(
List tModes = new ArrayList<>();
if (GqlUtil.hasArgument(environment, "modes")) {
Map modesInput = environment.getArgument("modes");
- if (modesInput.containsKey("transportModes")) {
+ if (modesInput.get("transportModes") != null) {
List> transportModes = (List>) modesInput.get(
"transportModes"
);
diff --git a/src/main/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapper.java b/src/main/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapper.java
index 59259905944..e7a13dcacc9 100644
--- a/src/main/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapper.java
+++ b/src/main/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapper.java
@@ -15,7 +15,7 @@ class RequestModesMapper {
* Maps GraphQL Modes input type to RequestModes.
*
* This only maps access, egress, direct & transfer modes. Transport modes are set using filters.
- * Default modes are WALK for access, egress, direct & transfer.
+ * Default modes are WALK for access, egress & transfer.
*/
static RequestModes mapRequestModes(Map modesInput) {
RequestModesBuilder mBuilder = RequestModes.of();
@@ -28,9 +28,8 @@ static RequestModes mapRequestModes(Map modesInput) {
if (modesInput.containsKey(egressModeKey)) {
mBuilder.withEgressMode((StreetMode) modesInput.get(egressModeKey));
}
- if (modesInput.containsKey(directModeKey)) {
- mBuilder.withDirectMode((StreetMode) modesInput.get(directModeKey));
- }
+ // An unset directMode should overwrite the walk default, so we don't check for existence first.
+ mBuilder.withDirectMode((StreetMode) modesInput.get(directModeKey));
return mBuilder.build();
}
diff --git a/src/main/java/org/opentripplanner/framework/geometry/GeometryUtils.java b/src/main/java/org/opentripplanner/framework/geometry/GeometryUtils.java
index 87a225fc0b3..85915cfeb48 100644
--- a/src/main/java/org/opentripplanner/framework/geometry/GeometryUtils.java
+++ b/src/main/java/org/opentripplanner/framework/geometry/GeometryUtils.java
@@ -10,8 +10,6 @@
import java.util.stream.Stream;
import org.geojson.GeoJsonObject;
import org.geojson.LngLatAlt;
-import org.geotools.api.referencing.crs.CoordinateReferenceSystem;
-import org.geotools.referencing.CRS;
import org.locationtech.jts.algorithm.ConvexHull;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.CoordinateSequence;
@@ -28,30 +26,12 @@
import org.locationtech.jts.linearref.LengthLocationMap;
import org.locationtech.jts.linearref.LinearLocation;
import org.locationtech.jts.linearref.LocationIndexedLine;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
public class GeometryUtils {
- private static final Logger LOG = LoggerFactory.getLogger(GeometryUtils.class);
-
private static final CoordinateSequenceFactory csf = new PackedCoordinateSequenceFactory();
private static final GeometryFactory gf = new GeometryFactory(csf);
- /** A shared copy of the WGS84 CRS with longitude-first axis order. */
- public static final CoordinateReferenceSystem WGS84_XY;
-
- static {
- try {
- WGS84_XY = CRS.getAuthorityFactory(true).createCoordinateReferenceSystem("EPSG:4326");
- } catch (Exception ex) {
- LOG.error("Unable to create longitude-first WGS84 CRS", ex);
- throw new RuntimeException(
- "Could not create longitude-first WGS84 coordinate reference system."
- );
- }
- }
-
public static Geometry makeConvexHull(
Collection collection,
Function mapToCoordinate
diff --git a/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/PruneIslands.java b/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/PruneIslands.java
index 00404845349..26349c0d803 100644
--- a/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/PruneIslands.java
+++ b/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/PruneIslands.java
@@ -10,7 +10,6 @@
import java.util.List;
import java.util.Map;
import java.util.Queue;
-import java.util.Set;
import java.util.stream.Collectors;
import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore;
import org.opentripplanner.graph_builder.issues.GraphConnectivity;
@@ -33,7 +32,6 @@
import org.opentripplanner.street.search.TraverseMode;
import org.opentripplanner.street.search.request.StreetSearchRequest;
import org.opentripplanner.street.search.state.State;
-import org.opentripplanner.transit.model.basic.TransitMode;
import org.opentripplanner.transit.service.TransitModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -252,16 +250,7 @@ private int processIslands(
if (island.stopSize() > 0) {
//for islands with stops
islandsWithStops++;
- boolean onlyFerry = true;
- for (Iterator vIter = island.stopIterator(); vIter.hasNext();) {
- TransitStopVertex v = (TransitStopVertex) vIter.next();
- Set modes = v.getModes();
- // test if stop has other transit modes than FERRY
- if (!modes.isEmpty() && !modes.contains(TransitMode.FERRY)) {
- onlyFerry = false;
- break;
- }
- }
+ boolean onlyFerry = island.hasOnlyFerryStops();
// do not remove real islands which have only ferry stops
if (!onlyFerry && island.streetSize() < pruningThresholdWithStops * adaptivePruningFactor) {
double sizeCoeff = (adaptivePruningFactor > 1.0)
@@ -487,8 +476,8 @@ private boolean restrictOrRemove(
// note: do not unlink stop if only CAR mode is pruned
// maybe this needs more logic for flex routing cases
List stopLabels = new ArrayList<>();
- for (Iterator vIter = island.stopIterator(); vIter.hasNext();) {
- Vertex v = vIter.next();
+ for (Iterator vIter = island.stopIterator(); vIter.hasNext();) {
+ TransitStopVertex v = vIter.next();
stopLabels.add(v.getLabel());
Collection edges = new ArrayList<>(v.getOutgoing());
edges.addAll(v.getIncoming());
diff --git a/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/Subgraph.java b/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/Subgraph.java
index 019c1c12a19..94dcfaaf131 100644
--- a/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/Subgraph.java
+++ b/src/main/java/org/opentripplanner/graph_builder/module/islandpruning/Subgraph.java
@@ -17,11 +17,12 @@
import org.opentripplanner.street.model.vertex.OsmVertex;
import org.opentripplanner.street.model.vertex.TransitStopVertex;
import org.opentripplanner.street.model.vertex.Vertex;
+import org.opentripplanner.transit.model.basic.TransitMode;
class Subgraph {
private final Set streetVertexSet;
- private final Set stopsVertexSet;
+ private final Set stopsVertexSet;
Subgraph() {
streetVertexSet = new HashSet<>();
@@ -29,8 +30,8 @@ class Subgraph {
}
void addVertex(Vertex vertex) {
- if (vertex instanceof TransitStopVertex) {
- stopsVertexSet.add(vertex);
+ if (vertex instanceof TransitStopVertex transitStopVertex) {
+ stopsVertexSet.add(transitStopVertex);
} else {
streetVertexSet.add(vertex);
}
@@ -64,7 +65,7 @@ Iterator streetIterator() {
return streetVertexSet.iterator();
}
- Iterator stopIterator() {
+ Iterator stopIterator() {
return stopsVertexSet.iterator();
}
@@ -98,8 +99,7 @@ Iterator stopIterator() {
Vertex vx = vIter.next();
envelope.expandToInclude(vx.getCoordinate());
}
- for (Iterator vIter = stopIterator(); vIter.hasNext();) {
- Vertex vx = vIter.next();
+ for (TransitStopVertex vx : stopsVertexSet) {
envelope.expandToInclude(vx.getCoordinate());
}
envelope.expandBy(searchRadiusDegrees / xscale, searchRadiusDegrees);
@@ -127,4 +127,21 @@ Geometry getGeometry() {
return new MultiPoint(points.toArray(new Point[0]), geometryFactory);
}
+
+ /**
+ * Checks whether the subgraph has only transit-stops for ferries
+ *
+ * @return true if only ferries stop at the subgraph and false if other or no modes are
+ * stopping at the subgraph
+ */
+ boolean hasOnlyFerryStops() {
+ for (TransitStopVertex v : stopsVertexSet) {
+ Set modes = v.getModes();
+ // test if stop has other transit modes than FERRY
+ if (!modes.contains(TransitMode.FERRY)) {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java b/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java
index 592d34fb543..6bcab049bd4 100644
--- a/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java
+++ b/src/main/java/org/opentripplanner/graph_builder/module/ned/ElevationModule.java
@@ -20,13 +20,14 @@
import java.util.concurrent.atomic.AtomicInteger;
import org.geotools.api.coverage.Coverage;
import org.geotools.api.coverage.PointOutsideCoverageException;
+import org.geotools.api.referencing.crs.CoordinateReferenceSystem;
import org.geotools.api.referencing.operation.TransformException;
import org.geotools.geometry.Position2D;
+import org.geotools.referencing.CRS;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.impl.PackedCoordinateSequence;
import org.opentripplanner.framework.geometry.EncodedPolyline;
-import org.opentripplanner.framework.geometry.GeometryUtils;
import org.opentripplanner.framework.geometry.SphericalDistanceLibrary;
import org.opentripplanner.framework.lang.IntUtils;
import org.opentripplanner.framework.logging.ProgressTracker;
@@ -61,6 +62,25 @@
public class ElevationModule implements GraphBuilderModule {
private static final Logger LOG = LoggerFactory.getLogger(ElevationModule.class);
+ /**
+ * The WGS84 CRS with longitude-first axis order. The first time a CRS lookup is
+ * performed is surprisingly expensive (around 500ms), apparently due to initializing
+ * an HSQLDB JDBC connection. For this reason, the constant is defined in this
+ * narrower scope rather than a shared utility class, where it was seen to incur the
+ * initialization cost in a broader range of tests than is necessary.
+ */
+ private static final CoordinateReferenceSystem WGS84_XY;
+
+ static {
+ try {
+ WGS84_XY = CRS.getAuthorityFactory(true).createCoordinateReferenceSystem("EPSG:4326");
+ } catch (Exception ex) {
+ LOG.error("Unable to create longitude-first WGS84 CRS", ex);
+ throw new RuntimeException(
+ "Could not create longitude-first WGS84 coordinate reference system."
+ );
+ }
+ }
/** The elevation data to be used in calculating elevations. */
private final ElevationGridCoverageFactory gridCoverageFactory;
@@ -564,7 +584,7 @@ private double getElevation(Coverage coverage, double x, double y)
// GeoTIFFs in various projections. Note that GeoTools defaults to strict EPSG axis ordering of (lat, long)
// for DefaultGeographicCRS.WGS84, but OTP is using (long, lat) throughout and assumes unprojected DEM
// rasters to also use (long, lat).
- coverage.evaluate(new Position2D(GeometryUtils.WGS84_XY, x, y), values);
+ coverage.evaluate(new Position2D(WGS84_XY, x, y), values);
} catch (PointOutsideCoverageException e) {
nPointsOutsideDEM.incrementAndGet();
throw e;
diff --git a/src/main/java/org/opentripplanner/model/plan/legreference/LegReferenceSerializer.java b/src/main/java/org/opentripplanner/model/plan/legreference/LegReferenceSerializer.java
index 4f090a440b6..0ceae6cb456 100644
--- a/src/main/java/org/opentripplanner/model/plan/legreference/LegReferenceSerializer.java
+++ b/src/main/java/org/opentripplanner/model/plan/legreference/LegReferenceSerializer.java
@@ -51,8 +51,14 @@ public static LegReference decode(String legReference) {
return null;
}
- var buf = Base64.getUrlDecoder().decode(legReference);
- var input = new ByteArrayInputStream(buf);
+ byte[] serializedLegReference;
+ try {
+ serializedLegReference = Base64.getUrlDecoder().decode(legReference);
+ } catch (IllegalArgumentException e) {
+ LOG.info("Unable to decode leg reference (invalid base64 encoding): '{}'", legReference, e);
+ return null;
+ }
+ var input = new ByteArrayInputStream(serializedLegReference);
try (var in = new ObjectInputStream(input)) {
// The order must be the same in the encode and decode function
@@ -60,7 +66,11 @@ public static LegReference decode(String legReference) {
var type = readEnum(in, LegReferenceType.class);
return type.getDeserializer().read(in);
} catch (IOException e) {
- LOG.error("Unable to decode leg reference: '" + legReference + "'", e);
+ LOG.warn(
+ "Unable to decode leg reference (incompatible serialization format): '{}'",
+ legReference,
+ e
+ );
return null;
}
}
diff --git a/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapper.java b/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapper.java
index 765a9b5c47f..740224b4489 100644
--- a/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapper.java
+++ b/src/main/java/org/opentripplanner/netex/mapping/TripPatternMapper.java
@@ -67,7 +67,7 @@ class TripPatternMapper {
private final ReadOnlyHierarchicalMap routeById;
- private final Multimap serviceJourniesByPatternId = ArrayListMultimap.create();
+ private final Multimap serviceJourneysByPatternId = ArrayListMultimap.create();
private final ReadOnlyHierarchicalMapById operatingDayById;
@@ -152,12 +152,12 @@ class TripPatternMapper {
this.serviceJourneyById = serviceJourneyById;
// Index service journey by pattern id
for (ServiceJourney sj : serviceJourneyById.localValues()) {
- this.serviceJourniesByPatternId.put(sj.getJourneyPatternRef().getValue().getRef(), sj);
+ this.serviceJourneysByPatternId.put(sj.getJourneyPatternRef().getValue().getRef(), sj);
}
}
Optional mapTripPattern(JourneyPattern_VersionStructure journeyPattern) {
- Collection serviceJourneys = serviceJourniesByPatternId.get(
+ Collection serviceJourneys = serviceJourneysByPatternId.get(
journeyPattern.getId()
);
@@ -392,9 +392,12 @@ private Trip mapTrip(
JourneyPattern_VersionStructure journeyPattern,
ServiceJourney serviceJourney
) {
- return tripMapper.mapServiceJourney(
- serviceJourney,
- () -> findTripHeadsign(journeyPattern, serviceJourney)
+ return deduplicator.deduplicateObject(
+ Trip.class,
+ tripMapper.mapServiceJourney(
+ serviceJourney,
+ () -> findTripHeadsign(journeyPattern, serviceJourney)
+ )
);
}
diff --git a/src/main/java/org/opentripplanner/openstreetmap/model/OSMWay.java b/src/main/java/org/opentripplanner/openstreetmap/model/OSMWay.java
index c0cd049bd83..b1e90044bf2 100644
--- a/src/main/java/org/opentripplanner/openstreetmap/model/OSMWay.java
+++ b/src/main/java/org/opentripplanner/openstreetmap/model/OSMWay.java
@@ -109,20 +109,6 @@ public boolean isOneWayReverseBicycle() {
return "-1".equals(oneWayBicycle) || isTagFalse("bicycle:forward");
}
- /**
- * Returns true if bikes must use sidepath in forward direction
- */
- public boolean isForwardDirectionSidepath() {
- return "use_sidepath".equals(getTag("bicycle:forward"));
- }
-
- /**
- * Returns true if bikes must use sidepath in reverse direction
- */
- public boolean isReverseDirectionSidepath() {
- return "use_sidepath".equals(getTag("bicycle:backward"));
- }
-
/**
* Some cycleways allow contraflow biking.
*/
@@ -188,18 +174,6 @@ public StreetTraversalPermissionPair splitPermissions(StreetTraversalPermission
}
}
- //This needs to be after adding permissions for oneway:bicycle=no
- //removes bicycle permission when bicycles need to use sidepath
- //TAG: bicycle:forward=use_sidepath
- if (isForwardDirectionSidepath()) {
- permissionsFront = permissionsFront.remove(StreetTraversalPermission.BICYCLE);
- }
-
- //TAG bicycle:backward=use_sidepath
- if (isReverseDirectionSidepath()) {
- permissionsBack = permissionsBack.remove(StreetTraversalPermission.BICYCLE);
- }
-
if (isOpposableCycleway()) {
permissionsBack = permissionsBack.add(StreetTraversalPermission.BICYCLE);
}
diff --git a/src/main/java/org/opentripplanner/openstreetmap/model/OSMWithTags.java b/src/main/java/org/opentripplanner/openstreetmap/model/OSMWithTags.java
index 51bc9da1dd8..636584eb770 100644
--- a/src/main/java/org/opentripplanner/openstreetmap/model/OSMWithTags.java
+++ b/src/main/java/org/opentripplanner/openstreetmap/model/OSMWithTags.java
@@ -403,14 +403,10 @@ public boolean isVehicleExplicitlyAllowed() {
/**
* Returns true if bikes are explicitly denied access.
*
- * bicycle is denied if bicycle:no, bicycle:dismount, bicycle:license or bicycle:use_sidepath
+ * bicycle is denied if bicycle:no, bicycle:dismount or bicycle:license.
*/
public boolean isBicycleExplicitlyDenied() {
- return (
- isTagDeniedAccess("bicycle") ||
- "dismount".equals(getTag("bicycle")) ||
- "use_sidepath".equals(getTag("bicycle"))
- );
+ return (isTagDeniedAccess("bicycle") || "dismount".equals(getTag("bicycle")));
}
/**
diff --git a/src/main/java/org/opentripplanner/openstreetmap/tagmapping/DefaultMapper.java b/src/main/java/org/opentripplanner/openstreetmap/tagmapping/DefaultMapper.java
index 1463313203d..9989c102030 100644
--- a/src/main/java/org/opentripplanner/openstreetmap/tagmapping/DefaultMapper.java
+++ b/src/main/java/org/opentripplanner/openstreetmap/tagmapping/DefaultMapper.java
@@ -624,6 +624,9 @@ public void populateProperties(WayPropertySet props) {
props.setMixinProperties("foot=discouraged", ofWalkSafety(3));
props.setMixinProperties("bicycle=discouraged", ofBicycleSafety(3));
+ props.setMixinProperties("foot=use_sidepath", ofWalkSafety(5));
+ props.setMixinProperties("bicycle=use_sidepath", ofBicycleSafety(5));
+
populateNotesAndNames(props);
// slope overrides
diff --git a/src/main/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapper.java b/src/main/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapper.java
index 9bafe133f2a..5ea949e8d5c 100644
--- a/src/main/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapper.java
+++ b/src/main/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapper.java
@@ -1,5 +1,6 @@
package org.opentripplanner.openstreetmap.tagmapping;
+import static org.opentripplanner.openstreetmap.wayproperty.MixinPropertiesBuilder.ofWalkSafety;
import static org.opentripplanner.openstreetmap.wayproperty.WayPropertiesBuilder.withModes;
import static org.opentripplanner.street.model.StreetTraversalPermission.ALL;
import static org.opentripplanner.street.model.StreetTraversalPermission.CAR;
@@ -163,6 +164,10 @@ else if (speedLimit <= 16.65f) {
props.setProperties("highway=service;tunnel=yes;access=destination", withModes(NONE));
props.setProperties("highway=service;access=destination", withModes(ALL).bicycleSafety(1.1));
+ // Typically if this tag is used on a way, there is also a better option for walking.
+ // We don't need to set bicycle safety as cycling is not currently allowed on these ways.
+ props.setMixinProperties("bicycle=use_sidepath", ofWalkSafety(5));
+
// Automobile speeds in Finland.
// General speed limit is 80kph unless signs says otherwise.
props.defaultCarSpeed = 22.22f;
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayer.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayer.java
index 60cfb72ef7d..288f429a861 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayer.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayer.java
@@ -22,6 +22,8 @@ public class TransitLayer {
/**
* Transit data required for routing, indexed by each local date(Graph TimeZone) it runs through.
* A Trip "runs through" a date if any of its arrivals or departures is happening on that date.
+ * The same trip pattern can therefore have multiple running dates and trip pattern is not
+ * required to "run" on its service date.
*/
private final HashMap> tripPatternsRunningOnDate;
@@ -94,7 +96,12 @@ public StopLocation getStopByIndex(int stop) {
return stop == -1 ? null : this.stopModel.stopByIndex(stop);
}
- public Collection getTripPatternsForDate(LocalDate date) {
+ /**
+ * Returns trip patterns for the given running date. Running date is not necessarily the same
+ * as the service date. A Trip "runs through" a date if any of its arrivals or departures is
+ * happening on that date. Trip pattern can have multiple running dates.
+ */
+ public Collection getTripPatternsForRunningDate(LocalDate date) {
return tripPatternsRunningOnDate.getOrDefault(date, List.of());
}
@@ -112,16 +119,29 @@ public int getStopCount() {
return stopModel.stopIndexSize();
}
+ /**
+ * Returns a copy of the list of trip patterns for the given running date. Running date is not
+ * necessarily the same as the service date. A Trip "runs through" a date if any of its arrivals
+ * or departures is happening on that date. Trip pattern can have multiple running dates.
+ */
public List getTripPatternsRunningOnDateCopy(LocalDate runningPeriodDate) {
List tripPatternForDate = tripPatternsRunningOnDate.get(runningPeriodDate);
return tripPatternForDate != null ? new ArrayList<>(tripPatternForDate) : new ArrayList<>();
}
- public List getTripPatternsStartingOnDateCopy(LocalDate date) {
- List tripPatternsRunningOnDate = getTripPatternsRunningOnDateCopy(date);
- return tripPatternsRunningOnDate
+ /**
+ * Returns a copy of the list of trip patterns for the given service date. Service date is not
+ * necessarily the same as any of the trip pattern's running dates.
+ */
+ public List getTripPatternsOnServiceDateCopy(LocalDate date) {
+ List tripPatternsRunningOnDates = getTripPatternsRunningOnDateCopy(date);
+ // Trip pattern can run only after midnight. Therefore, we need to get the trip pattern's for
+ // the next running date as well and filter out duplicates.
+ tripPatternsRunningOnDates.addAll(getTripPatternsRunningOnDateCopy(date.plusDays(1)));
+ return tripPatternsRunningOnDates
.stream()
- .filter(t -> t.getLocalDate().equals(date))
+ .filter(t -> t.getServiceDate().equals(date))
+ .distinct()
.collect(Collectors.toList());
}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TripPatternForDate.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TripPatternForDate.java
index b86314aa42c..1411424dfc6 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TripPatternForDate.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TripPatternForDate.java
@@ -43,16 +43,16 @@ public class TripPatternForDate implements Comparable {
*/
private final FrequencyEntry[] frequencies;
- /** The date for which the filtering was performed. */
- private final LocalDate localDate;
+ /** The service date of the trip pattern. */
+ private final LocalDate serviceDate;
/**
- * The date on which the first trip departs.
+ * The running date on which the first trip departs. Not necessarily the same as the service date.
*/
private final LocalDate startOfRunningPeriod;
/**
- * The date on which the last trip arrives.
+ * The running date on which the last trip arrives.
*/
private final LocalDate endOfRunningPeriod;
@@ -60,19 +60,19 @@ public TripPatternForDate(
RoutingTripPattern tripPattern,
List tripTimes,
List frequencies,
- LocalDate localDate
+ LocalDate serviceDate
) {
this.tripPattern = tripPattern;
this.tripTimes = tripTimes.toArray(new TripTimes[0]);
this.frequencies = frequencies.toArray(new FrequencyEntry[0]);
- this.localDate = localDate;
+ this.serviceDate = serviceDate;
// TODO: We expect a pattern only containing trips or frequencies, fix ability to merge
if (hasFrequencies()) {
this.startOfRunningPeriod =
ServiceDateUtils
.asDateTime(
- localDate,
+ serviceDate,
frequencies
.stream()
.mapToInt(frequencyEntry -> frequencyEntry.startTime)
@@ -84,7 +84,7 @@ public TripPatternForDate(
this.endOfRunningPeriod =
ServiceDateUtils
.asDateTime(
- localDate,
+ serviceDate,
frequencies
.stream()
.mapToInt(frequencyEntry -> frequencyEntry.endTime)
@@ -96,11 +96,11 @@ public TripPatternForDate(
// These depend on the tripTimes array being sorted
var first = tripTimes.get(0);
this.startOfRunningPeriod =
- ServiceDateUtils.asDateTime(localDate, first.getDepartureTime(0)).toLocalDate();
+ ServiceDateUtils.asDateTime(serviceDate, first.getDepartureTime(0)).toLocalDate();
var last = tripTimes.get(tripTimes.size() - 1);
this.endOfRunningPeriod =
ServiceDateUtils
- .asDateTime(localDate, last.getArrivalTime(last.getNumStops() - 1))
+ .asDateTime(serviceDate, last.getArrivalTime(last.getNumStops() - 1))
.toLocalDate();
assertValidRunningPeriod(startOfRunningPeriod, endOfRunningPeriod, first, last);
}
@@ -126,18 +126,31 @@ public TripTimes getTripTimes(int i) {
return tripTimes[i];
}
- public LocalDate getLocalDate() {
- return localDate;
+ /**
+ * The service date for which the trip pattern belongs to. Not necessarily the same as the start
+ * of the running period in cases where the trip pattern only runs after midnight.
+ */
+ public LocalDate getServiceDate() {
+ return serviceDate;
}
public int numberOfTripSchedules() {
return tripTimes.length;
}
+ /**
+ * The start of the running period. This is determined by the first departure time for this
+ * pattern. Not necessarily the same as the service date if the pattern runs after midnight.
+ */
public LocalDate getStartOfRunningPeriod() {
return startOfRunningPeriod;
}
+ /**
+ * Returns the running dates. A Trip "runs through" a date if any of its arrivals or departures is
+ * happening on that date. The same trip pattern can therefore have multiple running dates and
+ * trip pattern is not required to "run" on its service date.
+ */
public List getRunningPeriodDates() {
// Add one day to ensure last day is included
return startOfRunningPeriod
@@ -151,14 +164,14 @@ public boolean hasFrequencies() {
@Override
public int compareTo(TripPatternForDate other) {
- return localDate.compareTo(other.localDate);
+ return serviceDate.compareTo(other.serviceDate);
}
@Override
public int hashCode() {
return Objects.hash(
tripPattern,
- localDate,
+ serviceDate,
Arrays.hashCode(tripTimes),
Arrays.hashCode(frequencies)
);
@@ -176,7 +189,7 @@ public boolean equals(Object o) {
return (
tripPattern.equals(that.tripPattern) &&
- localDate.equals(that.localDate) &&
+ serviceDate.equals(that.serviceDate) &&
Arrays.equals(tripTimes, that.tripTimes) &&
Arrays.equals(frequencies, that.frequencies)
);
@@ -184,7 +197,9 @@ public boolean equals(Object o) {
@Override
public String toString() {
- return "TripPatternForDate{" + "tripPattern=" + tripPattern + ", localDate=" + localDate + '}';
+ return (
+ "TripPatternForDate{" + "tripPattern=" + tripPattern + ", serviceDate=" + serviceDate + '}'
+ );
}
@Nullable
@@ -214,7 +229,7 @@ public TripPatternForDate newWithFilteredTripTimes(Predicate filter)
return this;
}
- return new TripPatternForDate(tripPattern, filteredTripTimes, filteredFrequencies, localDate);
+ return new TripPatternForDate(tripPattern, filteredTripTimes, filteredFrequencies, serviceDate);
}
private static void assertValidRunningPeriod(
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/TripFrequencyAlightSearch.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/TripFrequencyAlightSearch.java
index 451f51b2aa5..2f020e22cf5 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/TripFrequencyAlightSearch.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/TripFrequencyAlightSearch.java
@@ -55,7 +55,7 @@ public RaptorBoardOrAlightEvent search(
arrivalTime + headway,
headway,
offset,
- pattern.getLocalDate()
+ pattern.getServiceDate()
);
}
}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/TripFrequencyBoardSearch.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/TripFrequencyBoardSearch.java
index 897ce370a93..ea58e870547 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/TripFrequencyBoardSearch.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/frequency/TripFrequencyBoardSearch.java
@@ -54,7 +54,7 @@ public RaptorBoardOrAlightEvent search(
departureTime - headway,
headway,
offset,
- pattern.getLocalDate()
+ pattern.getServiceDate()
);
}
}
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/TransitLayerUpdater.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/TransitLayerUpdater.java
index bed27497587..fad5de83de0 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/TransitLayerUpdater.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/TransitLayerUpdater.java
@@ -96,7 +96,7 @@ public void update(
if (!tripPatternsStartingOnDateMapCache.containsKey(date)) {
Map map = realtimeTransitLayer
- .getTripPatternsStartingOnDateCopy(date)
+ .getTripPatternsOnServiceDateCopy(date)
.stream()
.collect(Collectors.toMap(t -> t.getTripPattern().getPattern(), t -> t));
tripPatternsStartingOnDateMapCache.put(date, map);
@@ -146,7 +146,7 @@ public void update(
} else {
LOG.debug(
"NEW TripPatternForDate: {} - {}",
- newTripPatternForDate.getLocalDate(),
+ newTripPatternForDate.getServiceDate(),
newTripPatternForDate.getTripPattern().debugInfo()
);
}
@@ -179,7 +179,7 @@ public void update(
}
for (TripPatternForDate tripPatternForDate : previouslyUsedPatterns) {
- if (tripPatternForDate.getLocalDate().equals(date)) {
+ if (tripPatternForDate.getServiceDate().equals(date)) {
TripPattern pattern = tripPatternForDate.getTripPattern().getPattern();
if (!pattern.isCreatedByRealtimeUpdater()) {
continue;
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RaptorRoutingRequestTransitDataCreator.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RaptorRoutingRequestTransitDataCreator.java
index 863a4ca9ae8..f987e4f7a21 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RaptorRoutingRequestTransitDataCreator.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/RaptorRoutingRequestTransitDataCreator.java
@@ -120,7 +120,7 @@ static List merge(
// Calculate offsets per date
int[] offsets = new int[patternsSorted.length];
for (int i = 0; i < patternsSorted.length; i++) {
- LocalDate serviceDate = patternsSorted[i].getLocalDate();
+ LocalDate serviceDate = patternsSorted[i].getServiceDate();
if (offsetCache.containsKey(serviceDate)) {
offsets[i] = offsetCache.get(serviceDate);
} else {
@@ -185,7 +185,9 @@ private static List filterActiveTripPatterns(
filter.tripTimesPredicate(tripTimes, filter.hasSubModeFilters());
Predicate tripTimesWithoutSubmodesPredicate = tripTimes ->
filter.tripTimesPredicate(tripTimes, false);
- Collection tripPatternsForDate = transitLayer.getTripPatternsForDate(date);
+ Collection tripPatternsForDate = transitLayer.getTripPatternsForRunningDate(
+ date
+ );
List result = new ArrayList<>(tripPatternsForDate.size());
for (TripPatternForDate p : tripPatternsForDate) {
if (firstDay || p.getStartOfRunningPeriod().equals(date)) {
diff --git a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleWithOffset.java b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleWithOffset.java
index 642dbd2d6e5..aca998b24ca 100644
--- a/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleWithOffset.java
+++ b/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/request/TripScheduleWithOffset.java
@@ -124,7 +124,7 @@ private void findTripTimes() {
if (index < numSchedules) {
this.tripTimes = tripPatternForDate.getTripTimes(index);
- this.serviceDate = tripPatternForDate.getLocalDate();
+ this.serviceDate = tripPatternForDate.getServiceDate();
this.secondsOffset = pattern.tripPatternForDateOffsets(i);
return;
}
diff --git a/src/main/java/org/opentripplanner/routing/vehicle_parking/VehicleParking.java b/src/main/java/org/opentripplanner/routing/vehicle_parking/VehicleParking.java
index e5b0fd083dc..6ebd34e1287 100644
--- a/src/main/java/org/opentripplanner/routing/vehicle_parking/VehicleParking.java
+++ b/src/main/java/org/opentripplanner/routing/vehicle_parking/VehicleParking.java
@@ -120,9 +120,10 @@ public class VehicleParking implements Serializable {
VehicleParkingSpaces availability,
VehicleParkingGroup vehicleParkingGroup
) {
- this.id = id;
+ this.id =
+ Objects.requireNonNull(id, "%s must have an ID".formatted(this.getClass().getSimpleName()));
this.name = name;
- this.coordinate = coordinate;
+ this.coordinate = Objects.requireNonNull(coordinate);
this.detailsUrl = detailsUrl;
this.imageUrl = imageUrl;
this.tags = tags;
diff --git a/src/main/java/org/opentripplanner/standalone/config/framework/json/OtpVersion.java b/src/main/java/org/opentripplanner/standalone/config/framework/json/OtpVersion.java
index 6caf9082cff..70b8e261ee4 100644
--- a/src/main/java/org/opentripplanner/standalone/config/framework/json/OtpVersion.java
+++ b/src/main/java/org/opentripplanner/standalone/config/framework/json/OtpVersion.java
@@ -10,7 +10,8 @@ public enum OtpVersion {
V2_2("2.2"),
V2_3("2.3"),
V2_4("2.4"),
- V2_5("2.5");
+ V2_5("2.5"),
+ V2_6("2.6");
private final String text;
diff --git a/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/VehicleParkingUpdaterConfig.java b/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/VehicleParkingUpdaterConfig.java
index e808ad6905c..f0306941547 100644
--- a/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/VehicleParkingUpdaterConfig.java
+++ b/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/VehicleParkingUpdaterConfig.java
@@ -2,6 +2,7 @@
import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_2;
import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_3;
+import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_6;
import java.time.Duration;
import java.time.ZoneId;
@@ -9,6 +10,7 @@
import java.util.Set;
import org.opentripplanner.ext.vehicleparking.bikely.BikelyUpdaterParameters;
import org.opentripplanner.ext.vehicleparking.hslpark.HslParkUpdaterParameters;
+import org.opentripplanner.ext.vehicleparking.noi.NoiUpdaterParameters;
import org.opentripplanner.ext.vehicleparking.parkapi.ParkAPIUpdaterParameters;
import org.opentripplanner.standalone.config.framework.json.NodeAdapter;
import org.opentripplanner.updater.vehicle_parking.VehicleParkingSourceType;
@@ -50,7 +52,7 @@ public static VehicleParkingUpdaterParameters create(String updaterRef, NodeAdap
);
case PARK_API, BICYCLE_PARK_API -> new ParkAPIUpdaterParameters(
updaterRef,
- c.of("url").since(V2_2).summary("URL of the resource.").asString(null),
+ c.of("url").since(V2_2).summary("URL of the resource.").asString(),
feedId,
c
.of("frequency")
@@ -66,7 +68,7 @@ public static VehicleParkingUpdaterParameters create(String updaterRef, NodeAdap
);
case BIKELY -> new BikelyUpdaterParameters(
updaterRef,
- c.of("url").since(V2_3).summary("URL of the locations endpoint.").asUri(null),
+ c.of("url").since(V2_3).summary("URL of the locations endpoint.").asUri(),
feedId,
c
.of("frequency")
@@ -75,6 +77,17 @@ public static VehicleParkingUpdaterParameters create(String updaterRef, NodeAdap
.asDuration(Duration.ofMinutes(1)),
HttpHeadersConfig.headers(c, V2_3)
);
+ case NOI_OPEN_DATA_HUB -> new NoiUpdaterParameters(
+ updaterRef,
+ c.of("url").since(V2_6).summary("URL of the locations endpoint.").asUri(),
+ feedId,
+ c
+ .of("frequency")
+ .since(V2_6)
+ .summary("How often to update the source.")
+ .asDuration(Duration.ofMinutes(1)),
+ HttpHeadersConfig.headers(c, V2_6)
+ );
};
}
diff --git a/src/main/java/org/opentripplanner/transit/model/basic/Money.java b/src/main/java/org/opentripplanner/transit/model/basic/Money.java
index e44994d1105..35278d8fbd8 100644
--- a/src/main/java/org/opentripplanner/transit/model/basic/Money.java
+++ b/src/main/java/org/opentripplanner/transit/model/basic/Money.java
@@ -206,4 +206,9 @@ public boolean equals(Object obj) {
return false;
}
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(currency, amount);
+ }
}
diff --git a/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingDataSourceFactory.java b/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingDataSourceFactory.java
index e0214fd9d57..3fe465a8cd5 100644
--- a/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingDataSourceFactory.java
+++ b/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingDataSourceFactory.java
@@ -4,6 +4,8 @@
import org.opentripplanner.ext.vehicleparking.bikely.BikelyUpdaterParameters;
import org.opentripplanner.ext.vehicleparking.hslpark.HslParkUpdater;
import org.opentripplanner.ext.vehicleparking.hslpark.HslParkUpdaterParameters;
+import org.opentripplanner.ext.vehicleparking.noi.NoiUpdater;
+import org.opentripplanner.ext.vehicleparking.noi.NoiUpdaterParameters;
import org.opentripplanner.ext.vehicleparking.parkapi.BicycleParkAPIUpdater;
import org.opentripplanner.ext.vehicleparking.parkapi.CarParkAPIUpdater;
import org.opentripplanner.ext.vehicleparking.parkapi.ParkAPIUpdaterParameters;
@@ -36,6 +38,7 @@ public static DataSource create(
openingHoursCalendarService
);
case BIKELY -> new BikelyUpdater((BikelyUpdaterParameters) parameters);
+ case NOI_OPEN_DATA_HUB -> new NoiUpdater((NoiUpdaterParameters) parameters);
};
}
}
diff --git a/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingSourceType.java b/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingSourceType.java
index 583bc9afc99..3a0cb7d31b3 100644
--- a/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingSourceType.java
+++ b/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingSourceType.java
@@ -5,4 +5,5 @@ public enum VehicleParkingSourceType {
BICYCLE_PARK_API,
HSL_PARK,
BIKELY,
+ NOI_OPEN_DATA_HUB,
}
diff --git a/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdater.java b/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdater.java
index 3d2e9b21e29..185de6bddb7 100644
--- a/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdater.java
+++ b/src/main/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdater.java
@@ -8,6 +8,7 @@
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
+import org.opentripplanner.framework.tostring.ToStringBuilder;
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.routing.linking.DisposableEdgeCollection;
import org.opentripplanner.routing.linking.LinkingDirection;
@@ -68,7 +69,7 @@ public void setGraphUpdaterManager(WriteToGraphCallback saveResultOnGraph) {
}
@Override
- protected void runPolling() throws Exception {
+ protected void runPolling() {
LOG.debug("Updating vehicle parkings from {}", source);
if (!source.update()) {
LOG.debug("No updates");
@@ -239,4 +240,9 @@ private void removeVehicleParkingEdgesFromGraph(
graph.remove(entranceVertex);
}
}
+
+ @Override
+ public String toString() {
+ return ToStringBuilder.of(this.getClass()).addObj("source", source).toString();
+ }
}
diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java
index 2f1e57ef4dc..fcc59af845f 100644
--- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java
+++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java
@@ -131,6 +131,7 @@ static void setup() {
VehicleParking
.builder()
.id(id("parking-1"))
+ .coordinate(WgsCoordinate.GREENWICH)
.name(NonLocalizedString.ofNullable("parking"))
.build()
),
diff --git a/src/test/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapperTest.java b/src/test/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapperTest.java
index 160014213d3..b8d08c7d7f5 100644
--- a/src/test/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapperTest.java
+++ b/src/test/java/org/opentripplanner/apis/transmodel/mapping/RequestModesMapperTest.java
@@ -13,9 +13,11 @@ class RequestModesMapperTest {
void testMapRequestModesEmptyMapReturnsDefaults() {
Map inputModes = Map.of();
+ RequestModes wantModes = RequestModes.of().withDirectMode(null).build();
+
RequestModes mappedModes = RequestModesMapper.mapRequestModes(inputModes);
- assertEquals(RequestModes.of().build(), mappedModes);
+ assertEquals(wantModes, mappedModes);
}
@Test
@@ -26,6 +28,7 @@ void testMapRequestModesAccessSetReturnsDefaultsForOthers() {
.of()
.withAccessMode(StreetMode.BIKE)
.withTransferMode(StreetMode.BIKE)
+ .withDirectMode(null)
.build();
RequestModes mappedModes = RequestModesMapper.mapRequestModes(inputModes);
@@ -37,7 +40,11 @@ void testMapRequestModesAccessSetReturnsDefaultsForOthers() {
void testMapRequestModesEgressSetReturnsDefaultsForOthers() {
Map inputModes = Map.of("egressMode", StreetMode.CAR);
- RequestModes wantModes = RequestModes.of().withEgressMode(StreetMode.CAR).build();
+ RequestModes wantModes = RequestModes
+ .of()
+ .withEgressMode(StreetMode.CAR)
+ .withDirectMode(null)
+ .build();
RequestModes mappedModes = RequestModesMapper.mapRequestModes(inputModes);
diff --git a/src/test/java/org/opentripplanner/graph_builder/module/VehicleParkingLinkingTest.java b/src/test/java/org/opentripplanner/graph_builder/module/VehicleParkingLinkingTest.java
index 95f4df79b7b..23f4ffc72ca 100644
--- a/src/test/java/org/opentripplanner/graph_builder/module/VehicleParkingLinkingTest.java
+++ b/src/test/java/org/opentripplanner/graph_builder/module/VehicleParkingLinkingTest.java
@@ -9,7 +9,6 @@
import org.junit.jupiter.api.Test;
import org.opentripplanner.framework.geometry.WgsCoordinate;
import org.opentripplanner.routing.graph.Graph;
-import org.opentripplanner.routing.vehicle_parking.VehicleParking;
import org.opentripplanner.routing.vehicle_parking.VehicleParkingHelper;
import org.opentripplanner.routing.vehicle_parking.VehicleParkingTestGraphData;
import org.opentripplanner.street.model.StreetTraversalPermission;
@@ -46,8 +45,8 @@ public void setup() {
@Test
public void entranceWithVertexLinkingTest() {
- var parking = VehicleParking
- .builder()
+ var parking = StreetModelForTest
+ .vehicleParking()
.entrance(builder ->
builder.entranceId(id("1")).coordinate(new WgsCoordinate(A.getCoordinate())).vertex(A)
)
@@ -65,8 +64,8 @@ public void entranceWithVertexLinkingTest() {
@Test
public void entranceWithoutVertexLinkingTest() {
- var parking = VehicleParking
- .builder()
+ var parking = StreetModelForTest
+ .vehicleParking()
.entrance(builder ->
builder
.entranceId(id("1"))
@@ -99,8 +98,8 @@ public void carParkingEntranceToAllTraversableStreetLinkingTest() {
StreetModelForTest.streetEdge(A, C, StreetTraversalPermission.NONE);
- var parking = VehicleParking
- .builder()
+ var parking = StreetModelForTest
+ .vehicleParking()
.entrance(builder ->
builder
.entranceId(id("1"))
@@ -123,9 +122,8 @@ public void carParkingEntranceToAllTraversableStreetLinkingTest() {
@Test
public void removeEntranceWithNonExistingVertexTest() {
- var vehicleParking = VehicleParking
- .builder()
- .id(id("VP"))
+ var vehicleParking = StreetModelForTest
+ .vehicleParking()
.bicyclePlaces(true)
.entrance(builder ->
builder
@@ -159,9 +157,8 @@ public void removeEntranceWithNonExistingVertexTest() {
@Test
public void removeVehicleParkingWithOneEntranceAndNonExistingVertexTest() {
- var vehicleParking = VehicleParking
- .builder()
- .id(id("VP"))
+ var vehicleParking = StreetModelForTest
+ .vehicleParking()
.bicyclePlaces(true)
.entrance(builder ->
builder
diff --git a/src/test/java/org/opentripplanner/graph_builder/module/islandpruning/SubgraphOnlyFerryTest.java b/src/test/java/org/opentripplanner/graph_builder/module/islandpruning/SubgraphOnlyFerryTest.java
new file mode 100644
index 00000000000..26aaf12896b
--- /dev/null
+++ b/src/test/java/org/opentripplanner/graph_builder/module/islandpruning/SubgraphOnlyFerryTest.java
@@ -0,0 +1,112 @@
+package org.opentripplanner.graph_builder.module.islandpruning;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Set;
+import org.junit.jupiter.api.Test;
+import org.opentripplanner.street.model.vertex.TransitStopVertex;
+import org.opentripplanner.street.model.vertex.TransitStopVertexBuilder;
+import org.opentripplanner.transit.model._data.TransitModelForTest;
+import org.opentripplanner.transit.model.basic.TransitMode;
+import org.opentripplanner.transit.model.site.RegularStop;
+
+class SubgraphOnlyFerryTest {
+
+ private static final TransitModelForTest TEST_MODEL = TransitModelForTest.of();
+ private static final RegularStop regularStop1 = TEST_MODEL.stop("TEST-1").build();
+ private static final RegularStop regularStop2 = TEST_MODEL.stop("TEST-2").build();
+
+ @Test
+ void subgraphHasOnlyFerry() {
+ TransitStopVertex transitStopVertex = new TransitStopVertexBuilder()
+ .withStop(regularStop1)
+ .withModes(Set.of(TransitMode.FERRY))
+ .build();
+
+ Subgraph subgraph = new Subgraph();
+ subgraph.addVertex(transitStopVertex);
+
+ assertTrue(subgraph.hasOnlyFerryStops());
+ }
+
+ @Test
+ void subgraphHasOnlyNoFerry() {
+ TransitStopVertex transitStopVertex1 = new TransitStopVertexBuilder()
+ .withStop(regularStop1)
+ .withModes(Set.of(TransitMode.BUS))
+ .build();
+
+ Subgraph subgraph = new Subgraph();
+ subgraph.addVertex(transitStopVertex1);
+
+ assertFalse(subgraph.hasOnlyFerryStops());
+ }
+
+ @Test
+ void subgraphHasOnlyNoMode() {
+ TransitStopVertex transitStopVertex1 = new TransitStopVertexBuilder()
+ .withStop(regularStop1)
+ .withModes(Set.of())
+ .build();
+
+ Subgraph subgraph = new Subgraph();
+ subgraph.addVertex(transitStopVertex1);
+
+ assertFalse(subgraph.hasOnlyFerryStops());
+ }
+
+ @Test
+ void subgraphHasOnlyFerryMoreStops() {
+ TransitStopVertex transitStopVertex1 = new TransitStopVertexBuilder()
+ .withStop(regularStop1)
+ .withModes(Set.of(TransitMode.FERRY))
+ .build();
+ TransitStopVertex transitStopVertex2 = new TransitStopVertexBuilder()
+ .withStop(regularStop2)
+ .withModes(Set.of(TransitMode.FERRY))
+ .build();
+
+ Subgraph subgraph = new Subgraph();
+ subgraph.addVertex(transitStopVertex1);
+ subgraph.addVertex(transitStopVertex2);
+
+ assertTrue(subgraph.hasOnlyFerryStops());
+ }
+
+ @Test
+ void subgraphHasNotOnlyFerryMoreStops() {
+ TransitStopVertex transitStopVertex1 = new TransitStopVertexBuilder()
+ .withStop(regularStop1)
+ .withModes(Set.of(TransitMode.FERRY))
+ .build();
+ TransitStopVertex transitStopVertex2 = new TransitStopVertexBuilder()
+ .withStop(regularStop2)
+ .withModes(Set.of(TransitMode.BUS))
+ .build();
+
+ Subgraph subgraph = new Subgraph();
+ subgraph.addVertex(transitStopVertex1);
+ subgraph.addVertex(transitStopVertex2);
+
+ assertFalse(subgraph.hasOnlyFerryStops());
+ }
+
+ @Test
+ void subgraphHasNoModeMoreStops() {
+ TransitStopVertex transitStopVertex1 = new TransitStopVertexBuilder()
+ .withStop(regularStop1)
+ .withModes(Set.of(TransitMode.FERRY))
+ .build();
+ TransitStopVertex transitStopVertex2 = new TransitStopVertexBuilder()
+ .withStop(regularStop2)
+ .withModes(Set.of())
+ .build();
+
+ Subgraph subgraph = new Subgraph();
+ subgraph.addVertex(transitStopVertex1);
+ subgraph.addVertex(transitStopVertex2);
+
+ assertFalse(subgraph.hasOnlyFerryStops());
+ }
+}
diff --git a/src/test/java/org/opentripplanner/model/plan/legreference/LegReferenceSerializerTest.java b/src/test/java/org/opentripplanner/model/plan/legreference/LegReferenceSerializerTest.java
index da295073e01..2d7df788ad3 100644
--- a/src/test/java/org/opentripplanner/model/plan/legreference/LegReferenceSerializerTest.java
+++ b/src/test/java/org/opentripplanner/model/plan/legreference/LegReferenceSerializerTest.java
@@ -2,6 +2,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
import java.time.LocalDate;
import org.junit.jupiter.api.Test;
@@ -86,4 +87,19 @@ void testScheduledTransitLegReferenceLegacyV2Deserialize() {
assertEquals(FROM_STOP_POS, ref.fromStopPositionInPattern());
assertEquals(TO_STOP_POS, ref.toStopPositionInPattern());
}
+
+ @Test
+ void testNullSerializedLegReference() {
+ assertNull(LegReferenceSerializer.decode(null));
+ }
+
+ @Test
+ void testEmptySerializedLegReference() {
+ assertNull(LegReferenceSerializer.decode(""));
+ }
+
+ @Test
+ void testIllegalBase64CharacterInSerializedLegReference() {
+ assertNull(LegReferenceSerializer.decode("RUT:Line:5"));
+ }
}
diff --git a/src/test/java/org/opentripplanner/netex/mapping/NetexTestDataSample.java b/src/test/java/org/opentripplanner/netex/mapping/NetexTestDataSample.java
index b8723fdbcf3..b72c9b05277 100644
--- a/src/test/java/org/opentripplanner/netex/mapping/NetexTestDataSample.java
+++ b/src/test/java/org/opentripplanner/netex/mapping/NetexTestDataSample.java
@@ -40,6 +40,7 @@
import org.rutebanken.netex.model.ScheduledStopPointRefStructure;
import org.rutebanken.netex.model.ServiceAlterationEnumeration;
import org.rutebanken.netex.model.ServiceJourney;
+import org.rutebanken.netex.model.ServiceJourneyRefStructure;
import org.rutebanken.netex.model.StopPointInJourneyPattern;
import org.rutebanken.netex.model.StopPointInJourneyPatternRefStructure;
import org.rutebanken.netex.model.TimetabledPassingTime;
@@ -50,9 +51,11 @@
public class NetexTestDataSample {
public static final String SERVICE_JOURNEY_ID = "RUT:ServiceJourney:1";
+ public static final String DATED_SERVICE_JOURNEY_ID_1 = "RUT:DatedServiceJourney:1";
+ public static final String DATED_SERVICE_JOURNEY_ID_2 = "RUT:DatedServiceJourney:2";
public static final List DATED_SERVICE_JOURNEY_ID = List.of(
- "RUT:DatedServiceJourney:1",
- "RUT:DatedServiceJourney:2"
+ DATED_SERVICE_JOURNEY_ID_1,
+ DATED_SERVICE_JOURNEY_ID_2
);
public static final List OPERATING_DAYS = List.of("2022-02-28", "2022-02-29");
private static final DayType EVERYDAY = new DayType()
@@ -174,6 +177,11 @@ public NetexTestDataSample() {
DatedServiceJourney datedServiceJourney = new DatedServiceJourney()
.withId(DATED_SERVICE_JOURNEY_ID.get(i))
+ .withJourneyRef(
+ List.of(
+ MappingSupport.createWrappedRef(SERVICE_JOURNEY_ID, ServiceJourneyRefStructure.class)
+ )
+ )
.withServiceAlteration(ServiceAlterationEnumeration.PLANNED)
.withOperatingDayRef(new OperatingDayRefStructure().withRef(operatingDay.getId()));
@@ -218,6 +226,15 @@ public HierarchicalMapById getServiceJourneyById() {
return serviceJourneyById;
}
+ public DatedServiceJourney getDatedServiceJourneyById(String id) {
+ return datedServiceJourneyBySjId
+ .values()
+ .stream()
+ .filter(datedServiceJourney -> datedServiceJourney.getId().equals(id))
+ .findFirst()
+ .orElse(null);
+ }
+
public ServiceJourney getServiceJourney() {
return serviceJourneyById.lookup(SERVICE_JOURNEY_ID);
}
diff --git a/src/test/java/org/opentripplanner/netex/mapping/TripPatternMapperTest.java b/src/test/java/org/opentripplanner/netex/mapping/TripPatternMapperTest.java
index 74448fb3638..95af8f623e5 100644
--- a/src/test/java/org/opentripplanner/netex/mapping/TripPatternMapperTest.java
+++ b/src/test/java/org/opentripplanner/netex/mapping/TripPatternMapperTest.java
@@ -1,9 +1,12 @@
package org.opentripplanner.netex.mapping;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.google.common.collect.ArrayListMultimap;
+import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.junit.jupiter.api.Test;
@@ -19,17 +22,19 @@
import org.opentripplanner.transit.model.timetable.TripOnServiceDate;
import org.opentripplanner.transit.model.timetable.TripTimes;
import org.rutebanken.netex.model.DatedServiceJourney;
+import org.rutebanken.netex.model.DatedServiceJourneyRefStructure;
import org.rutebanken.netex.model.OperatingDay;
+import org.rutebanken.netex.model.ServiceAlterationEnumeration;
/**
* @author Thomas Gran (Capra) - tgr@capraconsulting.no (29.11.2017)
*/
-public class TripPatternMapperTest {
+class TripPatternMapperTest {
private static final FeedScopedId SERVICE_ID = TransitModelForTest.id("S01");
@Test
- public void testMapTripPattern() {
+ void testMapTripPattern() {
NetexTestDataSample sample = new NetexTestDataSample();
TripPatternMapper tripPatternMapper = new TripPatternMapper(
@@ -88,9 +93,85 @@ public void testMapTripPattern() {
}
@Test
- public void testMapTripPattern_datedServiceJourney() {
+ void testMapTripPattern_datedServiceJourney() {
NetexTestDataSample sample = new NetexTestDataSample();
+ Optional res = mapTripPattern(sample);
+ assertTrue(res.isPresent());
+
+ var r = res.get();
+
+ assertEquals(2, r.tripOnServiceDates().size());
+
+ Trip trip = r.tripPattern().scheduledTripsAsStream().findFirst().get();
+
+ for (TripOnServiceDate tripOnServiceDate : r.tripOnServiceDates()) {
+ assertEquals(trip, tripOnServiceDate.getTrip());
+ assertEquals(TripAlteration.PLANNED, tripOnServiceDate.getTripAlteration());
+ assertEquals(
+ 1,
+ sample
+ .getOperatingDaysById()
+ .localValues()
+ .stream()
+ .map(OperatingDay::getId)
+ .filter(id -> id.equals(tripOnServiceDate.getServiceDate().toString()))
+ .count()
+ );
+ }
+ }
+
+ @Test
+ void testDatedServiceJourneyReplacement() {
+ NetexTestDataSample sample = new NetexTestDataSample();
+ DatedServiceJourney dsjReplaced = sample.getDatedServiceJourneyById(
+ NetexTestDataSample.DATED_SERVICE_JOURNEY_ID_1
+ );
+ dsjReplaced.setServiceAlteration(ServiceAlterationEnumeration.REPLACED);
+ DatedServiceJourney dsjReplacing = sample.getDatedServiceJourneyById(
+ NetexTestDataSample.DATED_SERVICE_JOURNEY_ID_2
+ );
+ dsjReplacing.withJourneyRef(
+ List.of(
+ MappingSupport.createWrappedRef(dsjReplaced.getId(), DatedServiceJourneyRefStructure.class)
+ )
+ );
+ Optional res = mapTripPattern(sample);
+
+ assertTrue(res.isPresent());
+ var r = res.get();
+ Optional replacedTripOnServiceDate = r
+ .tripOnServiceDates()
+ .stream()
+ .filter(tripOnServiceDate ->
+ NetexTestDataSample.DATED_SERVICE_JOURNEY_ID_1.equals(tripOnServiceDate.getId().getId())
+ )
+ .findFirst();
+
+ assertTrue(replacedTripOnServiceDate.isPresent());
+ assertEquals(TripAlteration.REPLACED, replacedTripOnServiceDate.get().getTripAlteration());
+
+ Optional replacingTripOnServiceDate = r
+ .tripOnServiceDates()
+ .stream()
+ .filter(tripOnServiceDate ->
+ NetexTestDataSample.DATED_SERVICE_JOURNEY_ID_2.equals(tripOnServiceDate.getId().getId())
+ )
+ .findFirst();
+
+ assertTrue(replacingTripOnServiceDate.isPresent());
+ assertEquals(TripAlteration.PLANNED, replacingTripOnServiceDate.get().getTripAlteration());
+ assertFalse(replacingTripOnServiceDate.get().getReplacementFor().isEmpty());
+
+ // the replaced trip should refer to the same object (object identity) whether it is accessed
+ // directly from the replaced DSJ or indirectly through the replacing DSJ.
+ assertSame(
+ replacingTripOnServiceDate.get().getReplacementFor().getFirst().getTrip(),
+ replacedTripOnServiceDate.get().getTrip()
+ );
+ }
+
+ private static Optional mapTripPattern(NetexTestDataSample sample) {
HierarchicalMapById datedServiceJourneys = new HierarchicalMapById<>();
datedServiceJourneys.addAll(sample.getDatedServiceJourneyBySjId().values());
@@ -121,28 +202,6 @@ public void testMapTripPattern_datedServiceJourney() {
Optional res = tripPatternMapper.mapTripPattern(
sample.getJourneyPattern()
);
-
- assertTrue(res.isPresent());
-
- var r = res.get();
-
- assertEquals(2, r.tripOnServiceDates().size());
-
- Trip trip = r.tripPattern().scheduledTripsAsStream().findFirst().get();
-
- for (TripOnServiceDate tripOnServiceDate : r.tripOnServiceDates()) {
- assertEquals(trip, tripOnServiceDate.getTrip());
- assertEquals(TripAlteration.PLANNED, tripOnServiceDate.getTripAlteration());
- assertEquals(
- 1,
- sample
- .getOperatingDaysById()
- .localValues()
- .stream()
- .map(OperatingDay::getId)
- .filter(id -> id.equals(tripOnServiceDate.getServiceDate().toString()))
- .count()
- );
- }
+ return res;
}
}
diff --git a/src/test/java/org/opentripplanner/openstreetmap/model/OSMWayTest.java b/src/test/java/org/opentripplanner/openstreetmap/model/OSMWayTest.java
index c316793ad8c..c0af4cf2701 100644
--- a/src/test/java/org/opentripplanner/openstreetmap/model/OSMWayTest.java
+++ b/src/test/java/org/opentripplanner/openstreetmap/model/OSMWayTest.java
@@ -92,21 +92,6 @@ void testIsOneWayBicycle() {
assertTrue(way.isOneWayReverseBicycle());
}
- @Test
- void testIsOneDirectionSidepath() {
- OSMWay way = new OSMWay();
- assertFalse(way.isForwardDirectionSidepath());
- assertFalse(way.isReverseDirectionSidepath());
-
- way.addTag("bicycle:forward", "use_sidepath");
- assertTrue(way.isForwardDirectionSidepath());
- assertFalse(way.isReverseDirectionSidepath());
-
- way.addTag("bicycle:backward", "use_sidepath");
- assertTrue(way.isForwardDirectionSidepath());
- assertTrue(way.isReverseDirectionSidepath());
- }
-
@Test
void testIsOpposableCycleway() {
OSMWay way = new OSMWay();
diff --git a/src/test/java/org/opentripplanner/openstreetmap/model/OSMWithTagsTest.java b/src/test/java/org/opentripplanner/openstreetmap/model/OSMWithTagsTest.java
index 18d92a5eec8..3c060150714 100644
--- a/src/test/java/org/opentripplanner/openstreetmap/model/OSMWithTagsTest.java
+++ b/src/test/java/org/opentripplanner/openstreetmap/model/OSMWithTagsTest.java
@@ -136,7 +136,7 @@ void testBicycleDenied() {
assertFalse(tags.isBicycleExplicitlyDenied(), "bicycle=" + allowedValue);
}
- for (var deniedValue : List.of("no", "dismount", "license", "use_sidepath")) {
+ for (var deniedValue : List.of("no", "dismount", "license")) {
tags.addTag("bicycle", deniedValue);
assertTrue(tags.isBicycleExplicitlyDenied(), "bicycle=" + deniedValue);
}
diff --git a/src/test/java/org/opentripplanner/openstreetmap/tagmapping/DefaultMapperTest.java b/src/test/java/org/opentripplanner/openstreetmap/tagmapping/DefaultMapperTest.java
index 9a16f6a8e2e..2a8988dda61 100644
--- a/src/test/java/org/opentripplanner/openstreetmap/tagmapping/DefaultMapperTest.java
+++ b/src/test/java/org/opentripplanner/openstreetmap/tagmapping/DefaultMapperTest.java
@@ -147,6 +147,48 @@ void bicycleDiscouraged() {
assertEquals(2.94, discouragedProps.bicycleSafety().forward(), epsilon);
}
+ @Test
+ void footUseSidepath() {
+ var regular = WayTestData.pedestrianTunnel();
+ var props = wps.getDataForWay(regular);
+ assertEquals(PEDESTRIAN_AND_BICYCLE, props.getPermission());
+ assertEquals(1, props.walkSafety().forward());
+
+ var useSidepath = WayTestData.pedestrianTunnel().addTag("foot", "use_sidepath");
+ var useSidepathProps = wps.getDataForWay(useSidepath);
+ assertEquals(PEDESTRIAN_AND_BICYCLE, useSidepathProps.getPermission());
+ assertEquals(5, useSidepathProps.walkSafety().forward());
+ }
+
+ @Test
+ void bicycleUseSidepath() {
+ var regular = WayTestData.southeastLaBonitaWay();
+ var props = wps.getDataForWay(regular);
+ assertEquals(ALL, props.getPermission());
+ assertEquals(.98, props.bicycleSafety().forward());
+
+ var useSidepath = WayTestData.southeastLaBonitaWay().addTag("bicycle", "use_sidepath");
+ var useSidepathProps = wps.getDataForWay(useSidepath);
+ assertEquals(ALL, useSidepathProps.getPermission());
+ assertEquals(4.9, useSidepathProps.bicycleSafety().forward(), epsilon);
+
+ var useSidepathForward = WayTestData
+ .southeastLaBonitaWay()
+ .addTag("bicycle:forward", "use_sidepath");
+ var useSidepathForwardProps = wps.getDataForWay(useSidepathForward);
+ assertEquals(ALL, useSidepathForwardProps.getPermission());
+ assertEquals(4.9, useSidepathForwardProps.bicycleSafety().forward(), epsilon);
+ assertEquals(0.98, useSidepathForwardProps.bicycleSafety().back(), epsilon);
+
+ var useSidepathBackward = WayTestData
+ .southeastLaBonitaWay()
+ .addTag("bicycle:backward", "use_sidepath");
+ var useSidepathBackwardProps = wps.getDataForWay(useSidepathBackward);
+ assertEquals(ALL, useSidepathBackwardProps.getPermission());
+ assertEquals(0.98, useSidepathBackwardProps.bicycleSafety().forward(), epsilon);
+ assertEquals(4.9, useSidepathBackwardProps.bicycleSafety().back(), epsilon);
+ }
+
/**
* Test that two values are within epsilon of each other.
*/
diff --git a/src/test/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapperTest.java b/src/test/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapperTest.java
index a2f84873f20..4dd52195acb 100644
--- a/src/test/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapperTest.java
+++ b/src/test/java/org/opentripplanner/openstreetmap/tagmapping/FinlandMapperTest.java
@@ -162,6 +162,13 @@ public void testSafetyWithMixins() {
wps.getDataForWay(wayWithMixinsAndCustomSafety).walkSafety().forward(),
epsilon
);
+
+ OSMWithTags wayWithBicycleSidePath = new OSMWithTags();
+ wayWithBicycleSidePath.addTag("bicycle", "use_sidepath");
+ assertEquals(8, wps.getDataForWay(wayWithBicycleSidePath).walkSafety().forward(), epsilon);
+ OSMWithTags wayWithFootSidePath = new OSMWithTags();
+ wayWithFootSidePath.addTag("foot", "use_sidepath");
+ assertEquals(8, wps.getDataForWay(wayWithFootSidePath).walkSafety().forward(), epsilon);
}
@Test
diff --git a/src/test/java/org/opentripplanner/openstreetmap/wayproperty/WayPropertySetTest.java b/src/test/java/org/opentripplanner/openstreetmap/wayproperty/WayPropertySetTest.java
index e8f5b6e51d3..24360539b6f 100644
--- a/src/test/java/org/opentripplanner/openstreetmap/wayproperty/WayPropertySetTest.java
+++ b/src/test/java/org/opentripplanner/openstreetmap/wayproperty/WayPropertySetTest.java
@@ -256,65 +256,6 @@ void testMotorVehicleTagDeniedPermissions() {
assertTrue(permissionPair.main().allowsNothing());*/
}
- @Test
- void testSidepathPermissions() {
- OSMWay way = new OSMWay();
- way.addTag("bicycle", "use_sidepath");
- way.addTag("highway", "primary");
- way.addTag("lanes", "2");
- way.addTag("maxspeed", "70");
- way.addTag("oneway", "yes");
- var permissionPair = getWayProperties(way);
-
- assertFalse(permissionPair.main().allows(StreetTraversalPermission.BICYCLE));
- assertFalse(permissionPair.back().allows(StreetTraversalPermission.BICYCLE));
-
- assertTrue(permissionPair.main().allows(StreetTraversalPermission.CAR));
- assertFalse(permissionPair.back().allows(StreetTraversalPermission.CAR));
-
- way = new OSMWay();
- way.addTag("bicycle:forward", "use_sidepath");
- way.addTag("highway", "tertiary");
- permissionPair = getWayProperties(way);
-
- assertFalse(permissionPair.main().allows(StreetTraversalPermission.BICYCLE));
- assertTrue(permissionPair.back().allows(StreetTraversalPermission.BICYCLE));
-
- assertTrue(permissionPair.main().allows(StreetTraversalPermission.CAR));
- assertTrue(permissionPair.back().allows(StreetTraversalPermission.CAR));
-
- way = new OSMWay();
- way.addTag("bicycle:backward", "use_sidepath");
- way.addTag("highway", "tertiary");
- permissionPair = getWayProperties(way);
-
- assertTrue(permissionPair.main().allows(StreetTraversalPermission.BICYCLE));
- assertFalse(permissionPair.back().allows(StreetTraversalPermission.BICYCLE));
-
- assertTrue(permissionPair.main().allows(StreetTraversalPermission.CAR));
- assertTrue(permissionPair.back().allows(StreetTraversalPermission.CAR));
-
- way = new OSMWay();
- way.addTag("highway", "tertiary");
- way.addTag("oneway", "yes");
- way.addTag("oneway:bicycle", "no");
- permissionPair = getWayProperties(way);
-
- assertTrue(permissionPair.main().allows(StreetTraversalPermission.BICYCLE));
- assertTrue(permissionPair.back().allows(StreetTraversalPermission.BICYCLE));
-
- assertTrue(permissionPair.main().allows(StreetTraversalPermission.CAR));
- assertFalse(permissionPair.back().allows(StreetTraversalPermission.CAR));
-
- way.addTag("bicycle:forward", "use_sidepath");
- permissionPair = getWayProperties(way);
- assertFalse(permissionPair.main().allows(StreetTraversalPermission.BICYCLE));
- assertTrue(permissionPair.back().allows(StreetTraversalPermission.BICYCLE));
-
- assertTrue(permissionPair.main().allows(StreetTraversalPermission.CAR));
- assertFalse(permissionPair.back().allows(StreetTraversalPermission.CAR));
- }
-
private StreetTraversalPermissionPair getWayProperties(OSMWay way) {
WayPropertySet wayPropertySet = new WayPropertySet();
WayProperties wayData = wayPropertySet.getDataForWay(way);
diff --git a/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayerTest.java b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayerTest.java
new file mode 100644
index 00000000000..7c674252e6a
--- /dev/null
+++ b/src/test/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/TransitLayerTest.java
@@ -0,0 +1,201 @@
+package org.opentripplanner.routing.algorithm.raptoradapter.transit;
+
+import static java.util.Map.entry;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+import org.opentripplanner.model.StopTime;
+import org.opentripplanner.transit.model._data.TransitModelForTest;
+import org.opentripplanner.transit.model.framework.Deduplicator;
+import org.opentripplanner.transit.model.network.RoutingTripPattern;
+import org.opentripplanner.transit.model.network.StopPattern;
+import org.opentripplanner.transit.model.network.TripPattern;
+import org.opentripplanner.transit.model.timetable.TripTimes;
+import org.opentripplanner.transit.model.timetable.TripTimesFactory;
+
+class TransitLayerTest {
+
+ private static final TransitModelForTest TEST_MODEL = TransitModelForTest.of();
+ private static final TripTimes TRIP_TIMES;
+
+ private static final RoutingTripPattern TRIP_PATTERN;
+
+ static {
+ var stop = TEST_MODEL.stop("TEST:STOP", 0, 0).build();
+ var stopTime = new StopTime();
+ stopTime.setStop(stop);
+ var stopPattern = new StopPattern(List.of(stopTime));
+ var route = TransitModelForTest.route("1").build();
+ TRIP_PATTERN =
+ TripPattern
+ .of(TransitModelForTest.id("P1"))
+ .withRoute(route)
+ .withStopPattern(stopPattern)
+ .build()
+ .getRoutingTripPattern();
+ TRIP_TIMES =
+ TripTimesFactory.tripTimes(
+ TransitModelForTest.trip("1").withRoute(route).build(),
+ List.of(new StopTime()),
+ new Deduplicator()
+ );
+ }
+
+ @Test
+ void testGetTripPatternsRunningOnDateCopy() {
+ var date = LocalDate.of(2024, 1, 1);
+
+ var tripPatternForDate = new TripPatternForDate(
+ TRIP_PATTERN,
+ List.of(TRIP_TIMES),
+ List.of(),
+ date
+ );
+ var tripPatterns = List.of(tripPatternForDate);
+ var transitLayer = new TransitLayer(
+ Map.of(date, tripPatterns),
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ );
+ var runningOnDate = transitLayer.getTripPatternsRunningOnDateCopy(date);
+ assertEquals(1, runningOnDate.size());
+ assertEquals(tripPatterns, runningOnDate);
+ assertFalse(tripPatterns == runningOnDate);
+ assertEquals(0, transitLayer.getTripPatternsRunningOnDateCopy(date.minusDays(1)).size());
+ assertEquals(0, transitLayer.getTripPatternsRunningOnDateCopy(date.plusDays(1)).size());
+ }
+
+ @Test
+ void testGetTripPatternsForRunningDate() {
+ var date = LocalDate.of(2024, 1, 1);
+
+ var tripPatternForDate = new TripPatternForDate(
+ TRIP_PATTERN,
+ List.of(TRIP_TIMES),
+ List.of(),
+ date
+ );
+ var tripPatterns = List.of(tripPatternForDate);
+ var transitLayer = new TransitLayer(
+ Map.of(date, tripPatterns),
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ );
+ var runningOnDate = transitLayer.getTripPatternsForRunningDate(date);
+ assertEquals(1, runningOnDate.size());
+ assertEquals(tripPatterns, runningOnDate);
+ assertTrue(tripPatterns == runningOnDate);
+ assertEquals(0, transitLayer.getTripPatternsForRunningDate(date.minusDays(1)).size());
+ assertEquals(0, transitLayer.getTripPatternsForRunningDate(date.plusDays(1)).size());
+ }
+
+ @Test
+ void testGetTripPatternsOnServiceDateCopyWithSameRunningAndServiceDate() {
+ var date = LocalDate.of(2024, 1, 1);
+
+ var tripPatternForDate = new TripPatternForDate(
+ TRIP_PATTERN,
+ List.of(TRIP_TIMES),
+ List.of(),
+ date
+ );
+ var transitLayer = new TransitLayer(
+ Map.of(date, List.of(tripPatternForDate)),
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ );
+ var startingOnDate = transitLayer.getTripPatternsOnServiceDateCopy(date);
+ assertEquals(1, startingOnDate.size());
+ assertEquals(tripPatternForDate, startingOnDate.getFirst());
+ assertEquals(0, transitLayer.getTripPatternsOnServiceDateCopy(date.minusDays(1)).size());
+ assertEquals(0, transitLayer.getTripPatternsOnServiceDateCopy(date.plusDays(1)).size());
+ }
+
+ @Test
+ void testGetTripPatternsOnServiceDateCopyWithServiceRunningAfterMidnight() {
+ var runningDate = LocalDate.of(2024, 1, 1);
+ var serviceDate = runningDate.minusDays(1);
+
+ var tripPatternForDate = new TripPatternForDate(
+ TRIP_PATTERN,
+ List.of(TRIP_TIMES),
+ List.of(),
+ serviceDate
+ );
+ var transitLayer = new TransitLayer(
+ Map.of(runningDate, List.of(tripPatternForDate)),
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ );
+ var startingOnDate = transitLayer.getTripPatternsOnServiceDateCopy(serviceDate);
+ // starting date should be determined by service date, not running date which refers to the
+ // normal calendar date that the trip pattern is running on
+ assertEquals(1, startingOnDate.size());
+ assertEquals(tripPatternForDate, startingOnDate.getFirst());
+ assertEquals(0, transitLayer.getTripPatternsOnServiceDateCopy(runningDate).size());
+ }
+
+ @Test
+ void testGetTripPatternsOnServiceDateCopyWithServiceRunningBeforeAndAfterMidnight() {
+ // This is same as the service date
+ var firstRunningDate = LocalDate.of(2024, 1, 1);
+ var secondRunningDate = firstRunningDate.plusDays(1);
+
+ var tripPatternForDate = new TripPatternForDate(
+ TRIP_PATTERN,
+ List.of(TRIP_TIMES),
+ List.of(),
+ firstRunningDate
+ );
+ var transitLayer = new TransitLayer(
+ Map.ofEntries(
+ entry(firstRunningDate, List.of(tripPatternForDate)),
+ entry(secondRunningDate, List.of(tripPatternForDate))
+ ),
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ );
+ var startingOnDate = transitLayer.getTripPatternsOnServiceDateCopy(firstRunningDate);
+ // Transit layer indexes trip patterns by running date and to get trip patterns for certain
+ // service date, we need to look up the trip patterns for the next running date as well, but
+ // we don't want to return duplicates
+ assertEquals(1, startingOnDate.size());
+ assertEquals(tripPatternForDate, startingOnDate.getFirst());
+ assertEquals(0, transitLayer.getTripPatternsOnServiceDateCopy(secondRunningDate).size());
+ }
+}
diff --git a/src/test/java/org/opentripplanner/routing/core/MoneyTest.java b/src/test/java/org/opentripplanner/routing/core/MoneyTest.java
index 5f197708f1d..01392e64493 100644
--- a/src/test/java/org/opentripplanner/routing/core/MoneyTest.java
+++ b/src/test/java/org/opentripplanner/routing/core/MoneyTest.java
@@ -102,4 +102,9 @@ void greaterThan() {
void serializable() {
assertInstanceOf(Serializable.class, oneDollar);
}
+
+ @Test
+ void equalHashCode() {
+ assertEquals(Money.usDollars(5).hashCode(), Money.usDollars(5).hashCode());
+ }
}
diff --git a/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingHelperTest.java b/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingHelperTest.java
index 9c80cb9cda9..90bdeb015a4 100644
--- a/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingHelperTest.java
+++ b/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingHelperTest.java
@@ -10,6 +10,7 @@
import org.opentripplanner.framework.i18n.NonLocalizedString;
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.routing.vehicle_parking.VehicleParking.VehicleParkingEntranceCreator;
+import org.opentripplanner.street.model._data.StreetModelForTest;
import org.opentripplanner.street.model.edge.VehicleParkingEdge;
import org.opentripplanner.street.model.vertex.VehicleParkingEntranceVertex;
import org.opentripplanner.transit.model.framework.FeedScopedId;
@@ -41,8 +42,8 @@ void linkThreeVerticesTest() {
@Test
void linkSkippingEdgesTest() {
Graph graph = new Graph();
- var vehicleParking = VehicleParking
- .builder()
+ var vehicleParking = StreetModelForTest
+ .vehicleParking()
.entrances(
IntStream
.rangeClosed(1, 3)
@@ -67,8 +68,8 @@ void linkSkippingEdgesTest() {
}
private VehicleParking createParingWithEntrances(int entranceNumber) {
- return VehicleParking
- .builder()
+ return StreetModelForTest
+ .vehicleParking()
.bicyclePlaces(true)
.entrances(
IntStream
diff --git a/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingTestUtil.java b/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingTestUtil.java
index 078d7350dcc..fca20322ebe 100644
--- a/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingTestUtil.java
+++ b/src/test/java/org/opentripplanner/routing/vehicle_parking/VehicleParkingTestUtil.java
@@ -2,6 +2,7 @@
import org.opentripplanner.framework.geometry.WgsCoordinate;
import org.opentripplanner.framework.i18n.NonLocalizedString;
+import org.opentripplanner.street.model._data.StreetModelForTest;
import org.opentripplanner.transit.model.framework.FeedScopedId;
public class VehicleParkingTestUtil {
@@ -25,8 +26,8 @@ public static VehicleParking createParkingWithEntrances(
.coordinate(new WgsCoordinate(y, x))
.walkAccessible(true);
- return VehicleParking
- .builder()
+ return StreetModelForTest
+ .vehicleParking()
.id(new FeedScopedId(TEST_FEED_ID, id))
.bicyclePlaces(true)
.capacity(vehiclePlaces)
diff --git a/src/test/java/org/opentripplanner/street/model/_data/StreetModelForTest.java b/src/test/java/org/opentripplanner/street/model/_data/StreetModelForTest.java
index 94ebaec73c4..4a0a0d1b848 100644
--- a/src/test/java/org/opentripplanner/street/model/_data/StreetModelForTest.java
+++ b/src/test/java/org/opentripplanner/street/model/_data/StreetModelForTest.java
@@ -9,6 +9,7 @@
import org.opentripplanner.framework.geometry.SphericalDistanceLibrary;
import org.opentripplanner.framework.geometry.WgsCoordinate;
import org.opentripplanner.framework.i18n.I18NString;
+import org.opentripplanner.routing.vehicle_parking.VehicleParking;
import org.opentripplanner.service.vehiclerental.model.TestFreeFloatingRentalVehicleBuilder;
import org.opentripplanner.service.vehiclerental.street.VehicleRentalPlaceVertex;
import org.opentripplanner.street.model.RentalFormFactor;
@@ -111,4 +112,8 @@ public static VehicleRentalPlaceVertex rentalVertex(RentalFormFactor formFactor)
}
return new VehicleRentalPlaceVertex(rentalVehicleBuilder.build());
}
+
+ public static VehicleParking.VehicleParkingBuilder vehicleParking() {
+ return VehicleParking.builder().id(id("vehicle-parking-1")).coordinate(WgsCoordinate.GREENWICH);
+ }
}
diff --git a/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingEdgeTest.java b/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingEdgeTest.java
index 7dad61fbd6b..81bee23ad54 100644
--- a/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingEdgeTest.java
+++ b/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingEdgeTest.java
@@ -10,6 +10,7 @@
import org.opentripplanner.routing.api.request.StreetMode;
import org.opentripplanner.routing.vehicle_parking.VehicleParking;
import org.opentripplanner.routing.vehicle_parking.VehicleParkingSpaces;
+import org.opentripplanner.street.model._data.StreetModelForTest;
import org.opentripplanner.street.model.vertex.VehicleParkingEntranceVertex;
import org.opentripplanner.street.search.request.StreetSearchRequest;
import org.opentripplanner.street.search.state.State;
@@ -130,8 +131,8 @@ private VehicleParking createVehicleParking(
boolean carPlaces,
VehicleParkingSpaces availability
) {
- return VehicleParking
- .builder()
+ return StreetModelForTest
+ .vehicleParking()
.id(TransitModelForTest.id("VehicleParking"))
.bicyclePlaces(bicyclePlaces)
.carPlaces(carPlaces)
diff --git a/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingPreferredTagsTest.java b/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingPreferredTagsTest.java
index 5969121b6d6..579ae4e964d 100644
--- a/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingPreferredTagsTest.java
+++ b/src/test/java/org/opentripplanner/street/model/edge/VehicleParkingPreferredTagsTest.java
@@ -11,9 +11,9 @@
import org.opentripplanner.framework.geometry.WgsCoordinate;
import org.opentripplanner.framework.i18n.NonLocalizedString;
import org.opentripplanner.routing.api.request.StreetMode;
-import org.opentripplanner.routing.vehicle_parking.VehicleParking;
import org.opentripplanner.routing.vehicle_parking.VehicleParkingEntrance;
import org.opentripplanner.routing.vehicle_parking.VehicleParkingSpaces;
+import org.opentripplanner.street.model._data.StreetModelForTest;
import org.opentripplanner.street.model.vertex.VehicleParkingEntranceVertex;
import org.opentripplanner.street.model.vertex.Vertex;
import org.opentripplanner.street.search.request.StreetSearchRequest;
@@ -62,9 +62,8 @@ private void runTest(
double expectedCost,
boolean arriveBy
) {
- var parking = VehicleParking
- .builder()
- .coordinate(COORDINATE)
+ var parking = StreetModelForTest
+ .vehicleParking()
.tags(parkingTags)
.availability(VehicleParkingSpaces.builder().bicycleSpaces(100).build())
.bicyclePlaces(true)
diff --git a/src/test/java/org/opentripplanner/transit/speed_test/support/AssertSpeedTestSetup.java b/src/test/java/org/opentripplanner/transit/speed_test/support/AssertSpeedTestSetup.java
index 031df343a9a..4113d5979b1 100644
--- a/src/test/java/org/opentripplanner/transit/speed_test/support/AssertSpeedTestSetup.java
+++ b/src/test/java/org/opentripplanner/transit/speed_test/support/AssertSpeedTestSetup.java
@@ -15,7 +15,7 @@ public static void assertTestDateHasData(
) {
int numberOfPatternForTestDate = transitModel
.getTransitLayer()
- .getTripPatternsForDate(config.testDate)
+ .getTripPatternsForRunningDate(config.testDate)
.size();
if (numberOfPatternForTestDate < 10) {
diff --git a/src/test/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdaterTest.java b/src/test/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdaterTest.java
index 2bcb49defae..a31b5cfb387 100644
--- a/src/test/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdaterTest.java
+++ b/src/test/java/org/opentripplanner/updater/vehicle_parking/VehicleParkingUpdaterTest.java
@@ -16,6 +16,7 @@
import org.opentripplanner.routing.vehicle_parking.VehicleParkingState;
import org.opentripplanner.routing.vehicle_parking.VehicleParkingTestGraphData;
import org.opentripplanner.routing.vehicle_parking.VehicleParkingTestUtil;
+import org.opentripplanner.street.model._data.StreetModelForTest;
import org.opentripplanner.street.model.edge.StreetVehicleParkingLink;
import org.opentripplanner.street.model.edge.VehicleParkingEdge;
import org.opentripplanner.street.model.vertex.VehicleParkingEntranceVertex;
@@ -142,7 +143,10 @@ void deleteVehicleParkingTest() {
@Test
void addNotOperatingVehicleParkingTest() {
- var vehicleParking = VehicleParking.builder().state(VehicleParkingState.CLOSED).build();
+ var vehicleParking = StreetModelForTest
+ .vehicleParking()
+ .state(VehicleParkingState.CLOSED)
+ .build();
when(dataSource.getUpdates()).thenReturn(List.of(vehicleParking));
runUpdaterOnce();
@@ -155,8 +159,8 @@ void addNotOperatingVehicleParkingTest() {
void updateNotOperatingVehicleParkingTest() {
var vehiclePlaces = VehicleParkingSpaces.builder().bicycleSpaces(1).build();
- var vehicleParking = VehicleParking
- .builder()
+ var vehicleParking = StreetModelForTest
+ .vehicleParking()
.availability(vehiclePlaces)
.state(VehicleParkingState.CLOSED)
.build();
@@ -175,8 +179,8 @@ void updateNotOperatingVehicleParkingTest() {
vehiclePlaces = VehicleParkingSpaces.builder().bicycleSpaces(2).build();
vehicleParking =
- VehicleParking
- .builder()
+ StreetModelForTest
+ .vehicleParking()
.availability(vehiclePlaces)
.state(VehicleParkingState.CLOSED)
.build();
@@ -194,7 +198,10 @@ void updateNotOperatingVehicleParkingTest() {
@Test
void deleteNotOperatingVehicleParkingTest() {
- var vehicleParking = VehicleParking.builder().state(VehicleParkingState.CLOSED).build();
+ var vehicleParking = StreetModelForTest
+ .vehicleParking()
+ .state(VehicleParkingState.CLOSED)
+ .build();
when(dataSource.getUpdates()).thenReturn(List.of(vehicleParking));
runUpdaterOnce();
diff --git a/src/test/resources/standalone/config/router-config.json b/src/test/resources/standalone/config/router-config.json
index 3a07cddfeb8..f5eaa1f942b 100644
--- a/src/test/resources/standalone/config/router-config.json
+++ b/src/test/resources/standalone/config/router-config.json
@@ -334,6 +334,12 @@
"Authorization": "${BIKELY_AUTHORIZATION}"
}
},
+ {
+ "type": "vehicle-parking",
+ "feedId": "noi",
+ "sourceType": "noi-open-data-hub",
+ "url": "https://parking.otp.opendatahub.com/parking/all.json"
+ },
{
"type": "stop-time-updater",
"frequency": "1m",