* perf(rest): fix range download to use real seek
FileStreamingUtil.copyStreams called IOUtils.skipFully(from, start),
which reads start bytes through a 2KB scratch buffer. Combined with
ArtifactStream not overriding skip(long), a Range request at offset
600MB on an 800MB artifact made the server read+discard 600MB before
serving any payload. With 80 concurrent devices this saturated CPU.
Fix:
- ArtifactStream.skip(long) now delegates to the wrapped stream so a
FileInputStream can lseek(2). Non-seekable backends (CipherInputStream
for encrypted artifacts, S3 streams) keep their existing behaviour.
- FileStreamingUtil.copyStreams uses InputStream.skipNBytes(start)
instead of IOUtils.skipFully so the call chain reaches the underlying
skip().
JMH (single thread, 600MB offset, 1MB read): 27.21 ms -> 0.034 ms (800x).
Real stack (80 parallel curl, 1MB range at 600MB offset): avg 728 ms ->
28 ms (26x), p99 966 ms -> 54 ms.
Adds JMH test-scope dep and FileStreamingBenchmark/BufferSizeBenchmark
for regression detection. Both gated on -Dperf=true so default test
runs stay fast.
* perf(rest): drop JMH benchmarks per upstream review
Eclipse hawkBit minimizes dependencies. Drop jmh-core / jmh-generator-annprocess
test-scope deps (also GPL-2.0 — not EPL-2.0 compatible) and the two
JMH benchmarks added with the seek fix. Move the BUFFER_SIZE rationale
into an inline comment in FileStreamingUtil so the empirical reasoning
behind keeping the 8 KiB constant stays discoverable.
The benchmarks may be reintroduced as a separate PR if upstream wants a
perf-regression harness later.
Notes:
1. (!) Eclipselink shall be migrated to 5.0 (in 4.0.8 there are incompatible classes, e.g EJBQueryImpl doesn't implement some newer methods). In the moment is with beta (5.0.0-B12) - JUST for testing!
2. (!) Ethlo plugin doesn't work with Eclipselink 5.0, it builds with Eclipselink 4.0.8 (could be a problem)
3. Dependencies - new starters, test starters changes, some dependencies refactoring
4. Auto-configs split - package changes, some properties classes changes
5. Spring nullable org.springframework.lang.Nullable/NonNull are depecated and replaced with jspcify -> org.jspecify.annotations.Nullable/NonNull (NullMarked)
6. Lombok config - adding lombok.addNullAnnotations=jspecify - to do not mess annotations
7. Distributed lock table changes - SP_LOCK table db migration
8. Spring Retry replaced with Spring Core Retry - does repace retry in hawkbit
9. Specifications -> added Update/Delete(/Predicate) Specifications and JpaSpecificationExecutor changed
10. HawkbitBaseRepositoryFactoryBean modified to register properly
11. Jackson - 2 -> 3, package migrations, finals are not deserialized by default(enable finals deserialization, consider make non-final), too ‘smart’ tries to set complex objects instead of using non args constructor (-> @JsonIgnore), some other default configs made
Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
* remove generic 405 - put only where needed
* remove 429 from get/post update where not expected (not quota related in general)
Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This functionallity seems to get via AMQP (after some authentication)
a private (wihtout need of authentication) url to an artifact assigned
to the controller.
By default, DDI or DMF shall provide proper urls (for direct download)
to devices and if they have to be without authentication this shall be
solved in different ways - for instance separate download server providing
dedicated private / signed urls.
This functinallity is not a real hawkBit part but more like something
intended to solve some edge cases.
Since it is complicated, heeds support, doesn't solve wide spread use
cases, and could be achieved with other means - better to be removed.
Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
Make use of RequestContextHolder which provides access to request / response out of the box
Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
HandlerMethodValidationException is thrown in some validations instead MethodArgumentNotValidException
handle it also
Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
* [#1383] Spring Boot 3 migration Step 2
Some of the steps:
1. Change spring version parent and versions in root pom.xml
2. update eclipselink versions
3. javax.annotation -> jakarta.annotation (*.java)
4. javax.persistence -> jakarta.persistence (*.java)
5. javax.servlet -> jakarta.servlet (*.java, pom.xml)
6. javax.validation:validation-api -> jakarta.validation:jakarta.validation-api (pom.xml)
7. javax.validation -> jakarta.validation (*.java)
8. javax.transaction -> jakarta.transaction (*.java)
9. replace spring-cloud-stream-binder-test (hawkbit-repository-test) with
```
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-test-binder</artifactId>
</dependency>
```
, TestSupportBinderAutoConfiguration.class }) -> })
@Import(TestChannelBinderConfiguration.class)
10. Set to Simple UI standard parent
11. requestMatchers to securityMatcher
12. @SpringBootApplication(scanBasePackages = "org.eclipse.hawkbit") (otherwise for instance flyway doesn't work - suffix is default ".sql", not H2.sql and don't differentiate dbs? strange is there a change?)
13. @NonEmpty for Long leads to validation exception - replaced with @NotNull
14. RSQLUtilityTest.correctRsqlBuildsPredicate - fixed - mock query builder add method
15. https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide#spring-mvc-and-webflux-url-matching-changes - aliases as targers/ return 404 - remove trailing slash
16. firewall tests (allowedHostNameWithNotAllowedHost) doesn't throw 'rejected exception' but return 400 instead (as probably is expected anyway)
Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com
* Fix tenant listing to do not mix with multitenancy
Tenant metadata is not multitenancy aware while depend on distribution set type
which is. Thus querying all tenant metadata (in non tenant context) sometimes leads to
resolution of distribution set type which is tenant scoped and leads to problems.
So, now listing tenant lists just their ids - not fill entities.
Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
---------
Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com
Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
* Add DDI Authentication (using apikey)
* Gateway token by passing as apikey "GatewayToken: <token>"
* Target token by passing as apikey "TargetToken: <token>"
* Removed Bearer auth as not supported
* Authentication schemes are set to the correspondent groups in order to be visible only where needed
* Optional OpenAPI (with property _hawkbit.server.swagger.enabled_, by default _true_)
Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
* Expose forceTime and startAt fields in rollout representation in Mgmt API
* Change "forceTime" to "forcetime"
* Add checks when making a POST request in the tests
* Change forced to timeforced in tests and extend validity check
* Pass aforcetime and startat arguments as test checks
* remove unused import
Signed-off-by: Stanislav Trailov <stanislav.trailov@bosch.io>
* Prevent losing headers (like CORS related ones) when resetting the response headers due to artifact stream.
* add comment
* Extend CORS tests to verify provided header.