A minimal Java web application that replaces Tomcat's default ROOT webapp ($TOMCAT_HOME/webapps/ROOT). Displays server info, request headers, and cookies via a servlet and JSP page.
Supports Tomcat 9, 10, and 11 via Maven profiles.
flowchart LR
user(["User<br/>(web browser)"])
subgraph sc["Servlet container — Tomcat 9/10/11 or embedded Jetty · ROOT.war at /"]
direction LR
html["index.html<br/>welcome page"]
servlet["InfoServlet<br/>/infoservlet"]
jsp["index.jsp<br/>server info · headers · cookies"]
end
user -->|GET /| html
user -->|GET /infoservlet| servlet
user -->|GET /index.jsp| jsp
servlet -->|forwards via RequestDispatcher| jsp
The WAR deploys at context path / (replacing the container's default ROOT app). A single codebase targets both the javax.servlet (Tomcat 9) and jakarta.servlet (Tomcat 10/11) namespaces via Maven profiles that select the matching source tree (src/main/java vs src/main/java-jakarta).
make deps # install the toolchain (JDK, Maven, node, act) via mise
make build # build ROOT.war (Tomcat 9 by default)
make jetty-run # run locally with embedded Jetty
# open http://localhost:8080/The toolchain (JDK, Maven, node, act) is managed by mise and pinned in .mise.toml. Install mise once, then make deps installs everything else.
| Tool | Version | Purpose |
|---|---|---|
| GNU Make | 3.81+ | Build orchestration |
| mise | latest | Toolchain version manager (provides JDK, Maven, node, act) |
| JDK | 21 (Temurin) | Java compiler/runtime — provided by mise; local dev builds every profile with JDK 21 (bytecode targets 11/17/21) |
| Maven | 3.9+ | Build and dependency management (provided by mise) |
| act | pinned | Local GitHub Actions testing (provided by mise, optional) |
Install mise (see the mise docs), then install all pinned tools:
curl https://mise.run | sh # one-time mise install
make deps # install JDK, Maven, node, act from .mise.tomlEach profile targets a specific Tomcat version with the appropriate Servlet API:
| Profile | Tomcat | Servlet API | Java release | CI-tested JDKs |
|---|---|---|---|---|
tomcat9 (default) |
9.0.x | javax.servlet 4.0 |
11 | 11, 17, 18, 21, 25 |
tomcat10 |
10.1.x | jakarta.servlet 6.1 |
17 | 17, 18, 25 |
tomcat11 |
11.0.x | jakarta.servlet 6.1 |
21 | 21, 25 |
Select a profile with PROFILE=:
make build # Tomcat 9 (default)
make build PROFILE=tomcat10 # Tomcat 10
make build PROFILE=tomcat11 # Tomcat 11Run make help to see all available targets.
| Target | Description |
|---|---|
make build |
Build ROOT.war (use PROFILE=tomcat9|tomcat10|tomcat11) |
make test |
Run the JUnit 5 + Mockito unit tests (use PROFILE=tomcat9|tomcat10|tomcat11) |
make lint |
Validate POM and project structure (mvn validate) |
make clean |
Cleanup build artifacts |
make run |
Run locally with Jetty (alias for jetty-run) |
make jetty-run |
Run locally with embedded Jetty server |
make verify-all |
Verify build compiles for all Tomcat profiles |
| Target | Description |
|---|---|
make static-check |
Run all static analysis (lint + trivy-fs + gitleaks-scan + mermaid-lint) |
make trivy-fs |
Scan the filesystem for vulnerabilities and secrets (Trivy) |
make gitleaks-scan |
Scan the working tree for committed secrets (gitleaks) |
make mermaid-lint |
Validate the README Mermaid diagram with mermaid-cli (GitHub's renderer) |
| Target | Description |
|---|---|
make deploy |
Build and deploy ROOT.war to Tomcat |
make tomcat-install |
Download and install Tomcat 9, 10, 11 to ~/tomcat/ |
make tomcat-switch |
Switch active Tomcat version |
| Target | Description |
|---|---|
make ci |
Run full local CI pipeline |
make ci-run |
Run GitHub Actions workflow locally via act |
| Target | Description |
|---|---|
make deps |
Install the toolchain (JDK, Maven, node, act) via mise |
make deps-print-updates |
Print project dependency updates |
make deps-update |
Update dependencies to latest releases |
make renovate-validate |
Validate Renovate configuration |
make release |
Create and push a new tag |
All profile-aware targets default to tomcat9. Set PROFILE=tomcat10 or PROFILE=tomcat11 to override.
Downloads and installs Tomcat 9, 10, and 11 to ~/tomcat/{9,10,11} with a ~/tomcat/current symlink:
make tomcat-installThe install script can also be called directly:
./scripts/install-tomcat.sh # install all versions
./scripts/install-tomcat.sh --versions 10,11 # install specific versions
./scripts/install-tomcat.sh --current 10 # switch current symlink to Tomcat 10Add these to your shell profile (~/.bashrc or ~/.zshrc):
export TOMCAT_HOME=~/tomcat/current
export CATALINA_HOME=$TOMCAT_HOMEBuild ROOT.war and deploy it to the matching Tomcat installation:
make deploy # Tomcat 9
make deploy PROFILE=tomcat10 # Tomcat 10
make deploy PROFILE=tomcat11 # Tomcat 11Manual deployment
Edit $TOMCAT_HOME/conf/server.xml — set autoDeploy and deployOnStartUp to false:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="false" deployOnStartUp="false">Then copy the WAR:
rm -rf $TOMCAT_HOME/webapps/ROOT/
rm -f $TOMCAT_HOME/webapps/ROOT.war
cp ./target/ROOT.war $TOMCAT_HOME/webapps/ROOT.war~/tomcat/current/bin/startup.sh # start
xdg-open http://localhost:8080/ # open in browser
tail -f ~/tomcat/current/logs/catalina.out # view logs
~/tomcat/current/bin/shutdown.sh # stopTo run a specific version instead of current:
~/tomcat/10/bin/startup.sh
~/tomcat/10/bin/shutdown.shTo switch which version current points to:
make tomcat-switch PROFILE=tomcat11make jetty-run # Tomcat 9
make jetty-run PROFILE=tomcat10 # Tomcat 10
make jetty-run PROFILE=tomcat11 # Tomcat 11Then open http://localhost:8080/index.html
rm -rf ~/tomcat/9 # remove a specific version
rm -rf ~/tomcat # remove everythingRemove the TOMCAT_HOME and CATALINA_HOME exports from your shell profile.
If your environment enforces SSL certificate validation:
mvn clean install \
-Daether.connector.https.securityMode=insecure \
-Dmaven.wagon.http.ssl.insecure=true \
-Dmaven.wagon.http.ssl.allowall=true \
-Dmaven.wagon.http.ssl.ignore.validity.dates=truejar tf ./target/ROOT.warGitHub Actions runs on every push to master, tags v*, and pull requests.
| Job | Triggers | Purpose |
|---|---|---|
| changes | push (master, tags), PR | Detect whether code paths changed (skips the build on docs-only changes) |
| static-check | when changes reports code |
make static-check — lint + trivy-fs + gitleaks-scan + mermaid-lint |
| build | when changes reports code |
make lint + make build + make test across the JDK × Tomcat matrix |
| ci-pass | always | Aggregator gate — succeeds only if every job passed; the single required status check on master (repository ruleset) |
The build job uses a matrix strategy testing across JDK 11/17/18/21/25 with Tomcat 9, JDK 17/18/25 with Tomcat 10, and JDK 21/25 with Tomcat 11. The JDK for each leg is provided by mise via the MISE_JAVA_VERSION override.
Renovate keeps dependencies up to date and automerges PRs once CI is green.
Default welcome page — http://localhost:8080/
JSP — http://localhost:8080/index.jsp
Servlet — http://localhost:8080/infoservlet



