The Poster Demo Store, or just Posters, is a simple e-commerce application for demoing load testing as well as test automation.
This application is built to demonstrate powerful Java Flight Recorder (JFR) functionality for business-level transactions. It contains custom jdk.jfr.Event integrations designed specifically for profiling eCommerce workflows.
For instance, the Order Processing function will emit custom events (com.xceptance.posters.OrderProcessing) encompassing parameters like orderId, itemCount, and totalAmount. It also deliberately injects exponentially increasing latency into large orders or specific credit card processors to show how JVM tooling (JMC) can be utilized to trace application-level business bottlenecks across millions of events.
To ensure these events are recorded offline, launch the application with JFR enabled:
java -XX:StartFlightRecording=filename=recording.jfr,settings=profile -jar target/posters-demo-store-3.0.0-SNAPSHOT.jarReal-Time Event Streaming:
This demo also natively utilizes the JFR Event Streaming API (jdk.jfr.consumer.RecordingStream) via the JfrEventStreamer component. It continuously monitors the internal system for our custom OrderProcessing event in real-time, completely in-memory. If an order processing event exceeds 3 seconds (simulating an anomaly, such as placing an order with 10+ items using an Amex card), it automatically outputs a severe [JFR ALERT] directly to the application logs—perfectly fusing diagnostics with real-time alerting without generating massive log overhead.
Posters comes with the basic functionality that you would expect from a typical online shop. This includes:
- A product catalog with categories and products, in our case, posters
- A search function in the shop using Lucene
- Customers may register with the shop
- Customers can manage their account, including shipping and billing addresses as well as credit cards
- There is a shopping cart
- Customers may place orders as guests or as registered customers
- A selection of different languages for the shop (EN-US, EN-GB, DE-DE, SV-SE)
- Comprehensive Cross-Site Request Forgery (CSRF) protection for all state-changing operations
- 🤖 AI-Ready WebMCP Integration: Browser-native tool schemas allowing AI agents to seamlessly search the catalog, configure carts, and execute end-to-end checkout processing natively. (See the Developer Integration Guide for architecture rules).
- A selection of incorrect behavior can be switched on and off at will (not yet implemented again)
Please note that this application is for demo purposes only.
Posters is built with the following technologies:
| Component | Technology |
|---|---|
| Framework | Spring Boot 4.0.5 |
| Language | Java 25 |
| Template Engine | Thymeleaf with Layout Dialect |
| Database | H2 (file-based) |
| ORM | JPA / Hibernate |
| Search | Apache Lucene 9.1 |
| Build Tool | Maven |
| Password Hashing | jBCrypt |
- JDK 25 or later
- Maven 3.9+ (if building from source)
The latest version of Posters can be downloaded at the Releases page.
Clone this repository to your local disk and run:
mvn clean packageIf all went well, you will find the build artifact in the target subdirectory: posters-demo-store-3.0.0-SNAPSHOT.jar. This file contains the Posters code and all required libraries (including an embedded Tomcat server) in a single, ready-to-run JAR file.
To only compile (without running tests):
mvn clean compilejava -jar target/posters-demo-store-3.0.0-SNAPSHOT.jarFor development, you can run Posters directly with the Spring Boot Maven plugin:
mvn spring-boot:runYou can run the application in an isolated container using Docker/Docker Compose. This does not require Java or Maven to be installed locally.
To build and start the application in the background:
docker-compose up -dThis will automatically mount ./db and ./log to your host machine for persistence. To stop it:
docker-compose downTo build the image manually from the Dockerfile:
docker build -t posters-demo-store .To run the container:
docker run -p 8080:8080 -v ./db:/app/db -v ./log:/app/log posters-demo-storeInstead of the Dockerfile, you can utilize Spring Boot's built-in Paketo Cloud Native Buildpacks to automatically construct a highly-optimized layered image directly from Maven:
mvn spring-boot:build-image -Dspring-boot.build-image.imageName=posters-demo-storeBy default, the shop is available at http://localhost:8080/.
When Posters is started for the first time, it will populate its database with a basic product catalog and a default storefront customer:
- Email:
johndoe@example.com - Password:
topsecret
Luhn-valid card numbers for demo and testing use. These are not real credit cards — they are standard test numbers that pass the Luhn checksum.
| Vendor | Card Number | CVV | Expiry |
|---|---|---|---|
| Visa | 4111 1111 1111 1111 | 123 | 12/30 |
| Mastercard | 5500 0000 0000 0004 | 123 | 12/30 |
| American Express | 3400 000000 00009 | 1234 | 12/30 |
| UnionPay | 6200 0000 0000 0003 | 123 | 12/30 |
| JCB | 3530 1113 3330 0000 | 123 | 12/30 |
| Discover | 6011 0000 0000 0004 | 123 | 12/30 |
| Diners Club | 3056 930902 5904 | 123 | 12/30 |
| Maestro | 5018 0000 0009 | 123 | 12/30 |
Note: Amex cards are 15 digits and require a 4-digit CVV. All other vendors use a 3-digit CVV.
Posters stores its data in:
| Directory | Purpose |
|---|---|
./db/ |
H2 database files |
./db/lucene-index/ |
Lucene search index |
./log/ |
Application log files |
If you want to start over with a clean database, simply stop the app and delete the db subdirectory. On the next start, Posters will recreate the directory and the database.
Configuration is managed via src/main/resources/application.yml. You can override any property using standard Spring Boot mechanisms.
| Property | Default | Description |
|---|---|---|
server.port |
8080 |
The HTTP port |
spring.datasource.url |
jdbc:h2:file:./db/posters |
JDBC URL for the H2 database |
spring.h2.console.enabled |
true |
Enable the H2 web console |
spring.h2.console.path |
/h2-console |
Path to the H2 web console |
spring.jpa.hibernate.ddl-auto |
update |
Schema management strategy |
posters.currency |
$ |
Currency symbol |
posters.shipping-costs |
7.00 |
Shipping costs |
posters.tax |
0.06 |
Tax rate |
posters.page-size |
8 |
Products per page |
posters.languages |
en-US,en-GB,de-DE,sv-SE |
Available languages |
You can override properties via command-line arguments:
java -jar target/posters-demo-store-3.0.0-SNAPSHOT.jar \
--server.port=9090 \
--posters.currency="€"Or via an external configuration file:
java -jar target/posters-demo-store-3.0.0-SNAPSHOT.jar \
--spring.config.additional-location=file:./conf/posters.ymlPosters ships with the H2 web console enabled. While the application is running, navigate to http://localhost:8080/h2-console and use the following settings:
| Setting | Value |
|---|---|
| Driver Class | org.h2.Driver |
| JDBC URL | jdbc:h2:file:./db/posters |
| User Name | sa |
| Password | (empty) |
mvn testTo activate or deactivate incorrect behavior or just to view the current status of this functionality go to one of two pages. The content on both pages is the same. The difference between the two designs is the sorting and style of the options:
The first design is compact and shows non-customizable options on the left and customizable options on the right. To access it go to:
[baseURL]/[YourLocale]/ok3ok2ru8udqx7gZGS9n/statusInfo
The second design groups options below each other based on the site functionality they alter. To access it go to:
[baseURL]/[YourLocale]/ok3ok2ru8udqx7gZGS9n/statusInfoDesign2
| Option | Description |
|---|---|
| Category shift | Calling a category will call a different category (ID + 1, or wraps to first) |
| Random quantities | Products are added to cart in incorrect, randomized quantities |
| Order block | Orders will not go through; carts will not be cleared |
| Search mixup | Search delivers results from a different locale (swaps EN and DE) |
| Cart randomization | Adding to cart adds a random product instead |
| Open login | Account logins accept anything as a valid password |
| Random history | Order history shows a different random history on each access |
| Option | Description |
|---|---|
| Product block | Block a single product from being added to cart (by product ID) |
| Product blocking order | Block all orders containing a specified product (by product ID) |
| Falsify result counter | Add/subtract from the search result count display |
| Block search | Block searches for a specific term (returns no results) |
| Quantity limit | Set a maximum quantity per product in the cart |
| Total cart limit | Set a maximum total item count for the cart |
Copyright (c) 2013-2026 Xceptance Software Technologies GmbH