Skip to content

feat(jetty): configure Jetty server with custom settings and replace Tomcat dependencies#3028

Open
balazs-szucs wants to merge 8 commits intobooklore-app:developfrom
balazs-szucs:jetty
Open

feat(jetty): configure Jetty server with custom settings and replace Tomcat dependencies#3028
balazs-szucs wants to merge 8 commits intobooklore-app:developfrom
balazs-szucs:jetty

Conversation

@balazs-szucs
Copy link
Collaborator

@balazs-szucs balazs-szucs commented Feb 26, 2026

📝 Description

This pull request updates the Booklore API to switch the embedded servlet container from Tomcat to Jetty, ensuring compatibility with query parameters that use certain special characters. It also updates exception handling to work with the new server and adjusts related configuration files.

Linked Issue: Fixes #

Required. Every PR must reference an approved issue. If no issue exists, open one and wait for maintainer approval before submitting a PR. Unsolicited PRs without a linked issue will be closed.

🏷️ Type of Change

  • Bug fix
  • New feature
  • Enhancement to existing feature
  • Refactor (no behavior change)
  • Breaking change (existing functionality affected)
  • Documentation update

🔧 Changes

Switch to Jetty and related configuration:

  • Replaces the default Tomcat server with Jetty by excluding spring-boot-starter-tomcat from the spring-boot-starter-web and spring-boot-starter-websocket dependencies, and adds spring-boot-starter-jetty in build.gradle.
  • Updates application.yaml to remove Tomcat-specific settings and add Jetty-specific thread and connection timeout configurations.

Jetty URI compliance customization:

  • Adds a new JettyConfig.java configuration class to set Jetty's UriCompliance to LEGACY, allowing query-string characters such as [, ], %, {, }, and |, matching the previous Tomcat relaxed query chars behavior.

Exception handling adjustments:

  • Updates GlobalExceptionHandler.java to handle client-aborted requests using IOException (which is generic and compatible with Jetty) instead of the Tomcat-specific ClientAbortException.

Motivation

Migrating from Tomcat (Spring Boot's default) to Jetty provides several architectural and performance benefits:

  • Lower memory footprint: Jetty is highly modular and generally consumes less base memory than Tomcat. This is ideal for self-hosted setups (like small VPS instances, Raspberry Pis, or resource-constrained Docker containers) where minimizing overhead is a priority.

  • Faster startup times: Because of its streamlined architecture, Jetty typically boots faster than Tomcat, allowing for quicker deployments, restarts, and scaling.

  • Designed for embedding: While Tomcat can be embedded (as Spring Boot does by default), Jetty was designed from the ground up specifically to be an embedded web server. It plays exceptionally well inside standalone, self-contained applications.

  • Concurrency efficiency: Jetty's event-driven, asynchronous architecture handles a high number of concurrent connections highly efficiently without needing a massive thread pool (hence our tuned max: 200, min: 8 thread configuration).

🧪 Testing (MANDATORY)

PRs without this section filled out will be closed. "Tests pass" or "Tested locally" is not sufficient. You must provide specifics.

Manual testing steps you performed:

  1. Tried all the necessary core feature e.g., websocket, auth workflow etc.

Regression testing:

Edge cases covered:

Test output:

Backend test output (./gradlew test)
bszuc@brios:~/booklore/booklore-api$ ./gradlew clean test

> Task :compileJava
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
Management of bidirectional association persistent attributes is deprecated and will be removed. Set the value to 'false' to get rid of this warning

> Task :compileTestJava
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
WARNING: sun.misc.Unsafe::objectFieldOffset has been called by net.bytebuddy.dynamic.loading.ClassInjector$UsingUnsafe$Dispatcher$CreationAction (file:/home/bszuc/.gradle/caches/modules-2/files-2.1/net.bytebuddy/byte-buddy/1.17.8/af5735f63d00ca47a9375fae5c7471a36331c6ed/byte-buddy-1.17.8.jar)
WARNING: Please consider reporting this to the maintainers of class net.bytebuddy.dynamic.loading.ClassInjector$UsingUnsafe$Dispatcher$CreationAction
WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release
2026-02-26T17:20:06.028+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.s.m.s.b.SimpleBrokerMessageHandler     : Stopping...
2026-02-26T17:20:06.028+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.s.m.s.b.SimpleBrokerMessageHandler     : BrokerAvailabilityEvent[available=false, SimpleBrokerMessageHandler [org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry@61318f54]]
2026-02-26T17:20:06.028+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.s.m.s.b.SimpleBrokerMessageHandler     : Stopped.
2026-02-26T17:20:06.041+01:00  INFO 602153 --- [booklore-api] [opFolderWatcher] o.b.s.b.BookdropMonitoringService        : Bookdrop monitor thread interrupted
2026-02-26T17:20:06.041+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.b.s.b.BookdropMonitoringService        : Stopped bookdrop folder monitor
2026-02-26T17:20:06.422+01:00  INFO 602153 --- [booklore-api] [opFileProcessor] o.b.s.b.BookdropEventHandlerService      : File processing thread interrupted, shutting down.
2026-02-26T17:20:06.423+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.b.s.monitoring.MonitoringService       : Shutting down monitoring service...
2026-02-26T17:20:06.424+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.b.s.watcher.LibraryFileEventProcessor  : Shutting down LibraryFileEventProcessor...
2026-02-26T17:20:06.424+01:00  WARN 602153 --- [booklore-api] [        async-0] o.b.service.monitoring.MonitoringTask    : WatchService has been closed. Stopping monitoring.
2026-02-26T17:20:06.429+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2026-02-26T17:20:06.447+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : BookloreHikariPool - Shutdown initiated...
2026-02-26T17:20:06.448+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : BookloreHikariPool - Shutdown completed.
2026-02-26T17:20:06.454+01:00  INFO 602153 --- [booklore-api] [opFolderWatcher] o.b.s.b.BookdropMonitoringService        : Bookdrop monitor thread interrupted
2026-02-26T17:20:06.454+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.b.s.b.BookdropMonitoringService        : Stopped bookdrop folder monitor
2026-02-26T17:20:06.454+01:00  INFO 602153 --- [booklore-api] [opFileProcessor] o.b.s.b.BookdropEventHandlerService      : File processing thread interrupted, shutting down.
2026-02-26T17:20:06.455+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.b.s.monitoring.MonitoringService       : Shutting down monitoring service...
2026-02-26T17:20:06.456+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.b.s.watcher.LibraryFileEventProcessor  : Shutting down LibraryFileEventProcessor...
2026-02-26T17:20:06.456+01:00  WARN 602153 --- [booklore-api] [        async-0] o.b.service.monitoring.MonitoringTask    : WatchService has been closed. Stopping monitoring.
2026-02-26T17:20:06.464+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2026-02-26T17:20:06.466+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : BookloreHikariPool - Shutdown initiated...
2026-02-26T17:20:06.467+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : BookloreHikariPool - Shutdown completed.
2026-02-26T17:20:06.475+01:00  INFO 602153 --- [booklore-api] [opFolderWatcher] o.b.s.b.BookdropMonitoringService        : Bookdrop monitor thread interrupted
2026-02-26T17:20:06.475+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.b.s.b.BookdropMonitoringService        : Stopped bookdrop folder monitor
2026-02-26T17:20:06.475+01:00  INFO 602153 --- [booklore-api] [opFileProcessor] o.b.s.b.BookdropEventHandlerService      : File processing thread interrupted, shutting down.
2026-02-26T17:20:06.476+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.b.s.monitoring.MonitoringService       : Shutting down monitoring service...
2026-02-26T17:20:06.476+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.b.s.watcher.LibraryFileEventProcessor  : Shutting down LibraryFileEventProcessor...
2026-02-26T17:20:06.476+01:00  WARN 602153 --- [booklore-api] [        async-0] o.b.service.monitoring.MonitoringTask    : WatchService has been closed. Stopping monitoring.
2026-02-26T17:20:06.481+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2026-02-26T17:20:06.488+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : BookloreHikariPool - Shutdown initiated...
2026-02-26T17:20:06.489+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : BookloreHikariPool - Shutdown completed.
2026-02-26T17:20:06.493+01:00  INFO 602153 --- [booklore-api] [opFolderWatcher] o.b.s.b.BookdropMonitoringService        : Bookdrop monitor thread interrupted
2026-02-26T17:20:06.494+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.b.s.b.BookdropMonitoringService        : Stopped bookdrop folder monitor
2026-02-26T17:20:06.494+01:00  INFO 602153 --- [booklore-api] [opFileProcessor] o.b.s.b.BookdropEventHandlerService      : File processing thread interrupted, shutting down.
2026-02-26T17:20:06.495+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.b.s.monitoring.MonitoringService       : Shutting down monitoring service...
2026-02-26T17:20:06.495+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.b.s.watcher.LibraryFileEventProcessor  : Shutting down LibraryFileEventProcessor...
2026-02-26T17:20:06.495+01:00  WARN 602153 --- [booklore-api] [        async-0] o.b.service.monitoring.MonitoringTask    : WatchService has been closed. Stopping monitoring.
2026-02-26T17:20:06.503+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2026-02-26T17:20:06.511+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : BookloreHikariPool - Shutdown initiated...
2026-02-26T17:20:06.512+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : BookloreHikariPool - Shutdown completed.
2026-02-26T17:20:06.523+01:00  INFO 602153 --- [booklore-api] [opFolderWatcher] o.b.s.b.BookdropMonitoringService        : Bookdrop monitor thread interrupted
2026-02-26T17:20:06.524+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.b.s.b.BookdropMonitoringService        : Stopped bookdrop folder monitor
2026-02-26T17:20:06.524+01:00  INFO 602153 --- [booklore-api] [opFileProcessor] o.b.s.b.BookdropEventHandlerService      : File processing thread interrupted, shutting down.
2026-02-26T17:20:06.525+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.b.s.monitoring.MonitoringService       : Shutting down monitoring service...
2026-02-26T17:20:06.525+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.b.s.watcher.LibraryFileEventProcessor  : Shutting down LibraryFileEventProcessor...
2026-02-26T17:20:06.526+01:00  WARN 602153 --- [booklore-api] [        async-0] o.b.service.monitoring.MonitoringTask    : WatchService has been closed. Stopping monitoring.
2026-02-26T17:20:06.531+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2026-02-26T17:20:06.540+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : BookloreHikariPool - Shutdown initiated...
2026-02-26T17:20:06.541+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : BookloreHikariPool - Shutdown completed.
2026-02-26T17:20:06.546+01:00  INFO 602153 --- [booklore-api] [opFolderWatcher] o.b.s.b.BookdropMonitoringService        : Bookdrop monitor thread interrupted
2026-02-26T17:20:06.546+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.b.s.b.BookdropMonitoringService        : Stopped bookdrop folder monitor
2026-02-26T17:20:06.547+01:00  INFO 602153 --- [booklore-api] [opFileProcessor] o.b.s.b.BookdropEventHandlerService      : File processing thread interrupted, shutting down.
2026-02-26T17:20:06.548+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.b.s.monitoring.MonitoringService       : Shutting down monitoring service...
2026-02-26T17:20:06.549+01:00  WARN 602153 --- [booklore-api] [        async-0] o.b.service.monitoring.MonitoringTask    : WatchService has been closed. Stopping monitoring.
2026-02-26T17:20:06.549+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] o.b.s.watcher.LibraryFileEventProcessor  : Shutting down LibraryFileEventProcessor...
2026-02-26T17:20:06.556+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2026-02-26T17:20:06.564+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : BookloreHikariPool - Shutdown initiated...
2026-02-26T17:20:06.565+01:00  INFO 602153 --- [booklore-api] [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : BookloreHikariPool - Shutdown completed.

[Incubating] Problems report is available at: file:///home/bszuc/booklore/booklore-api/build/reports/problems/problems-report.html

BUILD SUCCESSFUL in 1m 37s
7 actionable tasks: 7 executed
Consider enabling configuration cache to speed up this build: https://docs.gradle.org/9.3.1/userguide/configuration_cache_enabling.html
Frontend test output (ng test)
bszuc@brios:~/booklore/booklore-ui$ npm run test

> booklore@0.0.0 test
> ng test

Using Vitest configuration file: /home/bszuc/booklore/booklore-ui/vitest-base.config.ts
Initial chunk files                                                            | Names                                                                       |  Raw size
spec-app-features-magic-shelf-component-magic-shelf-component.js               | spec-app-features-magic-shelf-component-magic-shelf-component               |   1.09 MB | 
spec-app-features-magic-shelf-service-book-rule-evaluator.service.js           | spec-app-features-magic-shelf-service-book-rule-evaluator.service           |  65.08 kB | 
spec-app-app.component.js                                                      | spec-app-app.component                                                      |  58.63 kB | 
chunk-AD2BXOLH.js                                                              | -                                                                           |  53.30 kB | 
styles.css                                                                     | styles                                                                      |  30.99 kB | 
chunk-WIKGF6O7.js                                                              | -                                                                           |  24.50 kB | 
spec-app-features-magic-shelf-service-book-rule-evaluator-metadata-presence.js | spec-app-features-magic-shelf-service-book-rule-evaluator-metadata-presence |  23.21 kB | 
chunk-ZRYX4BS5.js                                                              | -                                                                           |  15.97 kB | 
spec-app-features-magic-shelf-service-magic-shelf-utils.js                     | spec-app-features-magic-shelf-service-magic-shelf-utils                     |  11.36 kB | 
spec-app-core-security-auth-initializer.js                                     | spec-app-core-security-auth-initializer                                     |   8.69 kB | 
chunk-PUIDBMXW.js                                                              | -                                                                           |   6.10 kB | 
chunk-Y7BNZHZM.js                                                              | -                                                                           |   4.86 kB | 
chunk-3J3QIHZF.js                                                              | -                                                                           |   2.19 kB | 
chunk-HPNCK62B.js                                                              | -                                                                           |   1.33 kB | 
init-testbed.js                                                                | init-testbed                                                                |   1.27 kB | 
spec-app-app.js                                                                | spec-app-app                                                                | 202 bytes | 
polyfills.js                                                                   | polyfills                                                                   | 121 bytes | 

                                                                               | Initial total                                                               |   1.40 MB

Application bundle generation complete. [7.327 seconds] - 2026-02-26T16:18:46.346Z

Watch mode enabled. Watching for file changes...

 DEV  v4.0.18 /home/bszuc/booklore/booklore-ui

 ✓  booklore  src/app/features/magic-shelf/service/magic-shelf-utils.spec.ts (46 tests) 14ms
 ✓  booklore  src/app/app.spec.ts (1 test) 2ms
 ✓  booklore  src/app/core/security/auth-initializer.spec.ts (2 tests) 22ms
 ✓  booklore  src/app/features/magic-shelf/service/book-rule-evaluator-metadata-presence.spec.ts (85 tests) 150ms
 ✓  booklore  src/app/features/magic-shelf/service/book-rule-evaluator.service.spec.ts (199 tests) 285ms
 ✓  booklore  src/app/app.component.spec.ts (7 tests) 231ms
 ✓  booklore  src/app/features/magic-shelf/component/magic-shelf-component.spec.ts (73 tests) 864ms

 Test Files  7 passed (7)
      Tests  413 passed (413)
   Start at  17:18:46
   Duration  3.64s (transform 2.14s, setup 2.14s, import 3.84s, tests 1.57s, environment 5.25s)

JUNIT report written to /home/bszuc/booklore/booklore-ui/test-results/vitest-results.xml
 PASS  Waiting for file changes...
       press h to show help, press q to quit

📸 Screen Recording / Screenshots (MANDATORY)

Every PR must include a screen recording or screenshots showing the change working end-to-end in a running local instance (both backend and frontend). This means you must have actually built, run, and tested the code yourself. PRs without visual proof will be closed without review.


✅ Pre-Submission Checklist

All boxes must be checked before requesting review. Incomplete PRs will be closed without review. No exceptions.

  • This PR is linked to an approved issue
  • Code follows project style guidelines and conventions
  • Branch is up to date with develop (merge conflicts resolved)
  • I ran the full stack locally (backend + frontend + database) and verified the change works
  • Automated tests added or updated to cover changes (backend and frontend)
  • All tests pass locally and output is pasted above
  • Screen recording or screenshots are attached above proving the change works
  • PR is a single focused change (one bug fix OR one feature, not multiple unrelated changes)
  • PR is reasonably scoped (PRs over 1000+ changed lines will be closed, split into smaller PRs)
  • No unsolicited refactors, cleanups, or "improvements" are bundled in
  • Flyway migration versioning is correct (if schema was modified)
  • Documentation PR submitted to booklore-docs (if user-facing changes)

🤖 AI-Assisted Contributions

If any part of this PR was generated or assisted by AI tools (Copilot, Claude, ChatGPT, etc.), all items below are mandatory. You are fully responsible for every line you submit. "The AI wrote it" is not an excuse, and AI-generated PRs that clearly haven't been reviewed are the #1 reason PRs get closed.

  • I have read and understand every line of this PR and can explain any part of it during review
  • I personally ran the code and verified it works (not just trusted the AI's output)
  • PR is scoped to a single logical change, not a dump of everything the AI suggested
  • Tests validate actual behavior, not just coverage (AI-generated tests often assert nothing meaningful)
  • No dead code, placeholder comments, TODOs, or unused scaffolding left behind by AI
  • I did not submit refactors, style changes, or "improvements" the AI suggested beyond the scope of the issue

💬 Additional Context (optional)

Startup logs:


backend-1   | 
backend-1   | > Task :compileJava
backend-1   | Management of bidirectional association persistent attributes is deprecated and will be removed. Set the value to 'false' to get rid of this warning
backend-1   | 
backend-1   | > Task :processResources
backend-1   | > Task :classes
backend-1   | > Task :resolveMainClassName
backend-1   | 
backend-1   | > Task :bootRun
backend-1   | Listening for transport dt_socket at address: 5005
backend-1   | 
backend-1   | ▀█████████▄   ▄██████▄   ▄██████▄     ▄█   ▄█▄  ▄█        ▄██████▄     ▄████████    ▄████████
backend-1   |   ███    ███ ███    ███ ███    ███   ███ ▄███▀ ███       ███    ███   ███    ███   ███    ███
backend-1   |   ███    ███ ███    ███ ███    ███   ███▐██▀   ███       ███    ███   ███    ███   ███    █▀
backend-1   |  ▄███▄▄▄██▀  ███    ███ ███    ███  ▄█████▀    ███       ███    ███  ▄███▄▄▄▄██▀  ▄███▄▄▄
backend-1   | ▀▀███▀▀▀██▄  ███    ███ ███    ███ ▀▀█████▄    ███       ███    ███ ▀▀███▀▀▀▀▀   ▀▀███▀▀▀
backend-1   |   ███    ██▄ ███    ███ ███    ███   ███▐██▄   ███       ███    ███ ▀███████████   ███    █▄
backend-1   |   ███    ███ ███    ███ ███    ███   ███ ▀███▄ ███▌    ▄ ███    ███   ███    ███   ███    ███
backend-1   | ▄█████████▀   ▀██████▀   ▀██████▀    ███   ▀█▀ █████▄▄██  ▀██████▀    ███    ███   ██████████
backend-1   |                                      ▀         ▀                      ███    ███                (development)
backend-1   | 
backend-1   | Powered By Spring Boot : 4.0.3
backend-1   | 
backend-1   | 2026-02-26T16:12:46.831Z  INFO 338 --- [booklore-api] [           main] org.booklore.BookloreApplication         : Starting BookloreApplication using Java 25.0.2 with PID 338 (/booklore-api/build/classes/java/main started by root in /booklore-api)
backend-1   | 2026-02-26T16:12:46.834Z  INFO 338 --- [booklore-api] [           main] org.booklore.BookloreApplication         : No active profile set, falling back to 1 default profile: "default"
backend-1   | 2026-02-26T16:12:47.886Z  INFO 338 --- [booklore-api] [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
backend-1   | 2026-02-26T16:12:48.086Z  INFO 338 --- [booklore-api] [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 193 ms. Found 61 JPA repository interfaces.
backend-1   | 2026-02-26T16:12:48.929Z  INFO 338 --- [booklore-api] [           main] o.s.b.j.s.JettyServletWebServerFactory   : Server initialized with port: 6060
backend-1   | 2026-02-26T16:12:48.934Z  INFO 338 --- [booklore-api] [           main] org.eclipse.jetty.server.Server          : jetty-12.1.6; built: 2026-01-27T18:53:19.182Z; git: 88ca559572b1c8858b3c5684bb0293fa64e5e90f; jvm 25.0.2+10-LTS
backend-1   | 2026-02-26T16:12:48.955Z  INFO 338 --- [booklore-api] [           main] b.w.c.s.WebApplicationContextInitializer : Root WebApplicationContext: initialization completed in 2084 ms
backend-1   | 2026-02-26T16:12:49.244Z  INFO 338 --- [booklore-api] [           main] com.zaxxer.hikari.HikariDataSource       : BookloreHikariPool - Starting...
backend-1   | 2026-02-26T16:12:49.303Z  INFO 338 --- [booklore-api] [           main] com.zaxxer.hikari.pool.HikariPool        : BookloreHikariPool - Added connection org.mariadb.jdbc.Connection@75288f47
backend-1   | 2026-02-26T16:12:49.304Z  INFO 338 --- [booklore-api] [           main] com.zaxxer.hikari.HikariDataSource       : BookloreHikariPool - Start completed.
backend-1   | 2026-02-26T16:12:49.326Z  INFO 338 --- [booklore-api] [           main] org.flywaydb.core.FlywayExecutor         : Database: jdbc:mariadb://backend_db/booklore?user=booklore&password=******** (MariaDB 11.4)
backend-1   | 2026-02-26T16:12:49.390Z  INFO 338 --- [booklore-api] [           main] o.f.core.internal.command.DbValidate     : Successfully validated 122 migrations (execution time 00:00.049s)
backend-1   | 2026-02-26T16:12:49.397Z  INFO 338 --- [booklore-api] [           main] o.f.core.internal.command.DbMigrate      : Current version of schema `booklore`: 124
backend-1   | 2026-02-26T16:12:49.399Z  INFO 338 --- [booklore-api] [           main] o.f.core.internal.command.DbMigrate      : Schema `booklore` is up to date. No migration necessary.
backend-1   | 2026-02-26T16:12:49.488Z  INFO 338 --- [booklore-api] [           main] org.hibernate.orm.jpa                    : HHH008540: Processing PersistenceUnitInfo [name: default]
backend-1   | 2026-02-26T16:12:49.521Z  INFO 338 --- [booklore-api] [           main] org.hibernate.orm.core                   : HHH000001: Hibernate ORM core version 7.2.4.Final
backend-1   | 2026-02-26T16:12:49.796Z  INFO 338 --- [booklore-api] [           main] o.s.o.j.p.SpringPersistenceUnitInfo      : No LoadTimeWeaver setup: ignoring JPA class transformer
backend-1   | 2026-02-26T16:12:50.991Z  INFO 338 --- [booklore-api] [           main] org.hibernate.orm.core                   : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
backend-1   | 2026-02-26T16:12:50.993Z  INFO 338 --- [booklore-api] [           main] org.hibernate.orm.jdbc.batch             : HHH100501: Automatic JDBC statement batching enabled (maximum batch size 500)
backend-1   | 2026-02-26T16:12:50.996Z  INFO 338 --- [booklore-api] [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
backend-1   | 2026-02-26T16:12:51.069Z  INFO 338 --- [booklore-api] [           main] o.s.d.j.r.query.QueryEnhancerFactories   : Hibernate is in classpath; If applicable, HQL parser will be used.
backend-1   | 2026-02-26T16:12:52.103Z  INFO 338 --- [booklore-api] [           main] o.e.j.session.DefaultSessionIdManager    : Session workerName=node0
backend-1   | 2026-02-26T16:12:52.107Z  INFO 338 --- [booklore-api] [           main] o.e.jetty.server.handler.ContextHandler  : Started osbjs.JettyEmbeddedWebAppContext@5f4db912{application,/,b=[file:/tmp/jetty-docbase.6060.18249891958181182473/, jar:file:///home/gradle/.gradle/caches/modules-2/files-2.1/org.webjars/swagger-ui/5.31.0/21769bdc10659d15b32063d3dd09ca2a2a2e5bbe/swagger-ui-5.31.0.jar!/META-INF/resources/],a=AVAILABLE,h=oeje11s.SessionHandler@1bf6f5bb{STARTED}}
backend-1   | 2026-02-26T16:12:52.107Z  INFO 338 --- [booklore-api] [           main] o.e.j.e.servlet.ServletContextHandler    : Started osbjs.JettyEmbeddedWebAppContext@5f4db912{application,/,b=[file:/tmp/jetty-docbase.6060.18249891958181182473/, jar:file:///home/gradle/.gradle/caches/modules-2/files-2.1/org.webjars/swagger-ui/5.31.0/21769bdc10659d15b32063d3dd09ca2a2a2e5bbe/swagger-ui-5.31.0.jar!/META-INF/resources/],a=AVAILABLE,h=oeje11s.SessionHandler@1bf6f5bb{STARTED}}
backend-1   | 2026-02-26T16:12:52.108Z  INFO 338 --- [booklore-api] [           main] org.eclipse.jetty.server.Server          : Started oejs.Server@18593a44{STARTING}[12.1.6,sto=0] @3174ms
backend-1   | 2026-02-26T16:12:53.772Z  INFO 338 --- [booklore-api] [           main] o.b.s.f.BookFileProcessorRegistry        : Initialized BookFileProcessorRegistry with 7 processors for 7 types
backend-1   | 2026-02-26T16:12:53.797Z  INFO 338 --- [booklore-api] [     virtual-61] o.b.s.watcher.LibraryFileEventProcessor  : LibraryFileEventProcessor virtual thread started.
backend-1   | 2026-02-26T16:12:53.810Z  INFO 338 --- [booklore-api] [           main] o.b.s.monitoring.MonitoringService       : Starting file change processor...
backend-1   | 2026-02-26T16:12:53.891Z  INFO 338 --- [booklore-api] [           main] o.b.s.b.BookdropMonitoringService        : Starting bookdrop folder monitor: /bookdrop
backend-1   | 2026-02-26T16:12:55.102Z  INFO 338 --- [booklore-api] [           main] org.booklore.service.IconService         : Loaded 20 SVG icons into cache
backend-1   | 2026-02-26T16:12:56.040Z  INFO 338 --- [booklore-api] [           main] org.booklore.config.WebSocketConfig      : WebSocket endpoint registered at /ws with allowed origins: [http://localhost:4200]
backend-1   | 2026-02-26T16:12:56.075Z  WARN 338 --- [booklore-api] [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
backend-1   | 2026-02-26T16:12:57.649Z  INFO 338 --- [booklore-api] [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 1 endpoint beneath base path '/actuator'
backend-1   | 2026-02-26T16:12:57.723Z  INFO 338 --- [booklore-api] [           main] o.s.m.s.b.SimpleBrokerMessageHandler     : Starting...
backend-1   | 2026-02-26T16:12:57.723Z  INFO 338 --- [booklore-api] [           main] o.s.m.s.b.SimpleBrokerMessageHandler     : BrokerAvailabilityEvent[available=true, SimpleBrokerMessageHandler [org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry@c4b4734]]
backend-1   | 2026-02-26T16:12:57.724Z  INFO 338 --- [booklore-api] [           main] o.s.m.s.b.SimpleBrokerMessageHandler     : Started.
backend-1   | 2026-02-26T16:12:57.728Z  INFO 338 --- [booklore-api] [           main] o.e.j.s.h.ContextHandler.application     : Initializing Spring DispatcherServlet 'dispatcherServlet'
backend-1   | 2026-02-26T16:12:57.728Z  INFO 338 --- [booklore-api] [           main] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
backend-1   | 2026-02-26T16:12:57.731Z  INFO 338 --- [booklore-api] [           main] o.s.web.servlet.DispatcherServlet        : Completed initialization in 3 ms
backend-1   | 2026-02-26T16:12:57.740Z  INFO 338 --- [booklore-api] [           main] o.e.jetty.server.AbstractConnector       : Started oejs.ServerConnector@53dca0c3{HTTP/1.1, (http/1.1)}{0.0.0.0:6060}
backend-1   | 2026-02-26T16:12:57.742Z  INFO 338 --- [booklore-api] [           main] o.s.boot.jetty.JettyWebServer            : Jetty started on port 6060 (http/1.1) with context path '/'
backend-1   | 2026-02-26T16:12:57.751Z  INFO 338 --- [booklore-api] [           main] org.booklore.BookloreApplication         : Started BookloreApplication in 11.262 seconds (process running for 11.539)
backend-1   | 2026-02-26T16:12:57.759Z  INFO 338 --- [booklore-api] [           main] o.booklore.config.TaskSchedulerConfig    : Application ready, initializing scheduled tasks
backend-1   | 2026-02-26T16:12:57.765Z  INFO 338 --- [booklore-api] [           main] org.booklore.service.task.TaskService    : Initializing 4 scheduled tasks
backend-1   | 2026-02-26T16:12:57.770Z  INFO 338 --- [booklore-api] [           main] org.booklore.service.task.TaskService    : Scheduled task CLEANUP_DELETED_BOOKS with cron expression: 0 40 0 * * 1
backend-1   | 2026-02-26T16:12:57.770Z  INFO 338 --- [booklore-api] [           main] org.booklore.service.task.TaskService    : Scheduled task CLEANUP_TEMP_METADATA with cron expression: 0 45 0 * * 1
backend-1   | 2026-02-26T16:12:57.770Z  INFO 338 --- [booklore-api] [           main] org.booklore.service.task.TaskService    : Scheduled task SYNC_LIBRARY_FILES with cron expression: 0 0 1 * * *
backend-1   | 2026-02-26T16:12:57.771Z  INFO 338 --- [booklore-api] [           main] org.booklore.service.task.TaskService    : Scheduled task UPDATE_BOOK_RECOMMENDATIONS with cron expression: 0 30 1 * * *
backend-1   | 2026-02-26T16:12:57.804Z  INFO 338 --- [booklore-api] [           main] o.b.s.monitoring.MonitoringService       : Registered 1 libraries for recursive monitoring
backend-1   | 2026-02-26T16:12:57.804Z  INFO 338 --- [booklore-api] [           main] o.b.service.library.LibraryService       : Monitoring initialized with 1 libraries

@balazs-szucs balazs-szucs marked this pull request as ready for review February 26, 2026 16:22
@balazs-szucs balazs-szucs requested a review from Copilot February 26, 2026 16:22
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates the Booklore API embedded servlet container from Tomcat to Jetty to improve compatibility with special characters in query strings, and updates related configuration and error handling to match Jetty behavior.

Changes:

  • Replaces Tomcat with Jetty in Gradle dependencies and updates application.yaml with Jetty server settings.
  • Adds a Jetty server customizer to relax URI parsing compliance for legacy query-string character support.
  • Updates async exception handling to avoid Tomcat-specific exceptions; enables Caffeine cache stats recording.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
booklore-api/src/main/resources/application.yaml Removes Tomcat-specific settings; adds Jetty threads/timeout config and header-size setting.
booklore-api/src/main/java/org/booklore/exception/GlobalExceptionHandler.java Replaces Tomcat ClientAbortException handling with IOException for broader Jetty compatibility.
booklore-api/src/main/java/org/booklore/config/JettyConfig.java Adds Jetty URI compliance customization to allow legacy/special query characters.
booklore-api/src/main/java/org/booklore/config/CacheConfig.java Enables Caffeine cache stats recording.
booklore-api/build.gradle Excludes Tomcat starters and adds Jetty starter dependency.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@acx10
Copy link
Collaborator

acx10 commented Feb 27, 2026

Hey, thanks for the PR! Just curious, what's the motivation for switching to Jetty? The special characters in query strings are already working fine with Tomcat's current config, so wondering if there's something else driving this.

Want to make sure there's a clear reason before taking on a server swap since that touches a lot of stuff under the hood.

@balazs-szucs
Copy link
Collaborator Author

Hi, see the motivation part of my pr message

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants