This project uses Apache Maven with the Maven Wrapper (./mvnw).
| Task | Command |
|---|---|
| Full build | ./mvnw install |
| Fast build (skip checks) | ./mvnw install -Pfastinstall |
| Compile only | ./mvnw compile |
| Run tests | ./mvnw test |
| Run single test | ./mvnw test -pl modules/cpr -Dtest=BroadcasterTest |
| Skip tests | ./mvnw install -DskipTests |
| Checkstyle only | ./mvnw checkstyle:checkstyle |
| PMD only | ./mvnw pmd:check |
Build a specific module (faster iteration):
# Build only atmosphere-runtime (cpr)
./mvnw install -pl modules/cpr -DskipTests
# Build only spring-boot-starter
./mvnw install -pl modules/spring-boot-starter -DskipTests
# Build only quarkus extension
./mvnw install -pl modules/quarkus-extension -DskipTestsRun this at the START OF EVERY SESSION:
git config core.hooksPath .githooksThis enables pre-commit, commit-msg, and pre-push hooks. Sessions get archived/revived, so this must run EVERY time you start working.
NEVER use --no-verify when committing or pushing. The hooks enforce:
- Apache 2.0 copyright headers on all Java source files
- No unused or duplicate imports in staged Java files
- Commit message format (max 2 lines, conventional commits recommended)
- No AI-generated commit signatures
- Pre-push: Maven build must pass (via validation marker)
Use conventional commit prefixes. The commit-msg hook warns if missing:
type(scope): description
Types: feat, fix, docs, style, refactor, test, chore, perf, ci, build, revert
Examples:
feat(cpr): add WebSocket reconnection support
fix(spring-boot): resolve auto-configuration ordering
chore: update Jetty to 12.0.16
Rules enforced by hooks:
- Maximum 2 non-empty lines (summary + optional detail)
- First line under 100 characters (50-72 recommended)
- No AI-generated signatures (
Co-Authored-By: Claude,Generated with, etc.) - NEVER add
Co-authored-by: Copilotor any AI co-author trailer — the commit-msg hook will reject it - Do not add ANY trailer lines (Co-authored-by, Signed-off-by, etc.) to commit messages
- Main branch:
main(development),atmosphere-2.6.x(legacy) - Feature branches for new features
- Bug fixes go directly to
main
atmosphere/
├── config/ (checkstyle, PMD rulesets)
├── modules/
│ ├── cpr/ (atmosphere-runtime - core framework)
│ ├── spring-boot-starter/ (Spring Boot 4.0 integration)
│ └── quarkus-extension/ (Quarkus 3.21+ integration)
│ ├── runtime/
│ └── deployment/
├── samples/
│ ├── chat/ (Jetty embedded sample)
│ ├── embedded-jetty-websocket-chat/
│ ├── spring-boot-chat/
│ └── quarkus-chat/
├── atmosphere.js/ (TypeScript client library)
├── assembly/
└── pom.xml (4.0.2-SNAPSHOT, JDK 21)
| Module | ArtifactId | Description |
|---|---|---|
| Core | atmosphere-runtime |
Main framework JAR |
| Spring Boot | atmosphere-spring-boot-starter |
Spring Boot 4.0 auto-configuration |
| Quarkus Runtime | atmosphere-quarkus-extension |
Quarkus 3.21+ runtime |
| Quarkus Deployment | atmosphere-quarkus-extension-deployment |
Quarkus build-time processing |
- Java version: 21 (configured in root pom.xml
<release>21</release>) - License: Apache 2.0
- All Java files MUST have the copyright header (enforced by pre-commit hook)
- Commit without AI assistant-related commit messages
- Do not add AI-generated commit text in commit messages
- NEVER add
Co-authored-by:trailers to commits — no Copilot, no Claude, no AI attribution of any kind - NEVER USE
--no-verifyWHEN COMMITTING CODE - Match the style and formatting of surrounding code
- Make the smallest reasonable changes to get to the desired outcome
- NEVER remove code comments unless you can prove they are actively false
All Java source files must start with:
/*
* Copyright 2008-2026 Async-IO.org
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/- Prefer composition over inheritance
- Use
try-with-resourcesfor allAutoCloseableresources - Prefer
Optionalover null returns for public APIs - Use
varfor local variables when the type is obvious from context - Prefer
switchexpressions (JDK 21) over if/else chains for enum handling - Use sealed classes/interfaces where appropriate
- Use records for immutable data carriers
- Use pattern matching (
instanceofpatterns, switch patterns) where it improves readability - Avoid raw types - always parameterize generics
- Use
@Overrideon all overriding methods - Prefer
StringBuilderover string concatenation in loops - Use
List.of(),Map.of(),Set.of()for unmodifiable collections - All tests use JUnit 5 (
org.junit.jupiter)
- Compiler:
javac -Xlint:all,-processing,-serialis enabled — the compiler flags unused imports, unchecked casts, deprecation usage, raw types, and other issues as warnings. Zero compiler warnings are required. - Checkstyle: runs in
validatephase (failsOnError=true). EnforcesUnusedImportsandRedundantImportrules — the build fails if unused or duplicate imports are present. Config inconfig/atmosphere-checkstyle.xml. - PMD: runs in
validatephase (failsOnError=true). Config inconfig/atmosphere-pmd-ruleset.xml. - Pre-commit hook: blocks commits containing unused or duplicate imports in staged Java files
- All checks can be skipped with
-Pfastinstallfor local iteration, but you MUST run a full./mvnw compile(without-Pfastinstall) before committing to verify zero warnings. - Do NOT introduce new
@SuppressWarningsannotations without justification. If a suppression is necessary (e.g., unavoidable raw type from a third-party API), add a comment explaining why.
# Run all tests in a specific module
./mvnw test -pl modules/cpr
# Run a single test class
./mvnw test -pl modules/cpr -Dtest=BroadcasterTest
# Run a single test method
./mvnw test -pl modules/cpr -Dtest=BroadcasterTest#testBroadcast
# Run with debug output
./mvnw test -pl modules/cpr -Dtest=BroadcasterTest -Dsurefire.useFile=false- Surefire uses
--add-opensfor concurrent locks (configured in root pom.xml) - Some tests excluded on JDK 25+ (BlockingIOCometSupport incompatibility)
JSR356WebSocketTestexcluded (Mockito cannot mock sealed interfaces on JDK 21+)BroadcasterCacheTestexcluded (BlockingIOCometSupport incompatibility)- JUnit 5 is the test framework for all modules
- Spring Boot starter uses JUnit 5 via
spring-boot-starter-test - Quarkus extension uses JUnit 5 via
quarkus-junit5
# 1. Build the module you changed
./mvnw compile -pl modules/cpr
# 2. Run targeted tests
./mvnw test -pl modules/cpr -Dtest=YourTest# 1. Compile and verify ZERO warnings (mandatory — do not skip)
./mvnw compile -pl modules/cpr
# 2. Full build of changed module with tests
./mvnw install -pl modules/cpr
# 3. Verify checkstyle and PMD pass
./mvnw checkstyle:checkstyle pmd:check -pl modules/cprDo NOT commit or push if the build produces warnings. Treat compiler warnings, deprecation warnings, and static analysis warnings as errors. Fix them before committing. The compiler runs with -Xlint:all,-processing,-serial and Checkstyle enforces UnusedImports/RedundantImport — both will catch common issues.
The pre-push hook blocks git push unless you run the validation script first:
# Full build + tests (recommended)
./scripts/pre-push-validate.sh
# Compile only (faster iteration)
./scripts/pre-push-validate.sh --fastThe script stamps a marker valid for 30 minutes. The pre-push hook checks the marker is fresh and matches the current commit.
# Full build with all checks
./mvnw install- Target: Spring Boot 4.0.2, Spring Framework 7.0
- Set object factory BEFORE init()
- Expose AtmosphereFramework bean but NOT BroadcasterFactory
- Override parent POM's SLF4J/Logback versions for Spring Boot 4 compatibility
- Target: Quarkus 3.21+
- Config prefix:
quarkus.atmosphere.* loadOnStartupmust be > 0 (Quarkus skips if <=0)- Use
BUILD_AND_RUN_TIME_FIXEDfor config used in@BuildStep Recordercannot passClass<?>objects; use class name strings
- Location:
atmosphere.js/ - Package manager: npm (uses package-lock.json)
- Build:
npm run build - Test:
npm test - Version: 5.0.0
Samples in samples/ are the first thing users see — they must be production-quality, not stubs.
- Actually use the integration you claim to demonstrate. If a sample is called
spring-boot-embabel-chat, it MUST use the real EmbabelAgentPlatformAPI — not fake it with a wrapper around a raw LLM client. If you can't make the real integration work, say so and ask for help. - No mock/stub implementations disguised as real code. Comments like "in a real app, you would call X" are a red flag — the sample should BE the real app.
- Read the third-party library's actual API (use
javap, inspect JARs, read source) before writing integration code. Do not guess at APIs. - Each sample must compile. Run
./mvnw compile -pl samples/<name>before committing. - Each sample must have a README.md explaining what it does, how to run it, and what the key code does.
When writing code that integrates with an external library (Embabel, LangChain4j, Spring AI, etc.):
- Inspect the actual dependency JARs in
~/.m2/repository/to find real class names and method signatures - Use
javap -publicto read the public API of key classes - Never invent API calls — if
agentPlatform.runAgent(prompt)doesn't exist, don't write it - Check for auto-configuration — most Spring ecosystem libraries provide starter/autoconfigure modules; use them instead of manual wiring
- Always ask for clarification rather than making assumptions
- If you're having trouble with something, stop and ask for help