MarketStream is a Java 17 Swing coursework application demonstrating a real-time financial market dashboard built with producer-consumer concurrency, background indicator calculation, dynamic custom chart rendering, validation, monitoring and graceful shutdown.
The application uses hypothetical stock quotes for supported symbols and calculates Simple Moving Average (SMA) and Exponential Moving Average (EMA) values from retained in-memory history.
The project addresses a multithreaded desktop-dashboard problem requiring:
ArrayBlockingQueue with backpressure.Future cancellation.ArrayBlockingQueueThreadPoolExecutorThe controller coordinates Swing components and concurrency services. Background services do not access Swing directly; they report events to DashboardController, which marshals UI updates onto the Swing EDT.
See docs/ARCHITECTURE.md for diagrams covering the main runtime architecture, quote flow, indicator flow and shutdown flow.
| Thread | Responsibility |
|---|---|
| Swing EDT | Handles UI events, component mutation, painting and monitor timer events. |
MarketStream-Producer |
Generates stock quotes and inserts them into the queue. |
MarketStream-Consumer |
Removes quotes from the queue and stores history. |
MarketStream-Indicator-* |
Runs background SMA/EMA tasks. |
MarketStream-Shutdown |
Performs bounded service termination waits during window close. |
Start Feed
↓
StockDataProducer generates quotes
↓
QuoteQueueManager stores bounded queue items
↓
StockDataConsumer takes quotes
↓
HistoricalDataStore retains history
↓
Swing EDT updates table and statistics
Indicator workflow:
Calculate Indicators
↓
Swing EDT validates input
↓
HistoricalDataStore returns defensive price snapshot
↓
IndicatorExecutorManager runs IndicatorTask
↓
IndicatorEngine calculates SMA and EMA
↓
IndicatorResult returned
↓
Swing EDT updates result panel and chart
StockDataProducer uses StockPriceGenerator to generate hypothetical quotes for AAPL, GOOG and MSFT. Quotes are placed into QuoteQueueManager, which wraps an ArrayBlockingQueue.
StockDataConsumer removes quotes with take(), stores them in HistoricalDataStore, and notifies the controller. Producer and consumer lifecycle methods are cooperative and interrupt blocking operations during shutdown.
HistoricalDataStore is separate from the queue. The queue is temporary transport; history is retained after consumption for indicator calculations.
The store:
ReentrantReadWriteLock,UIConstants.MAX_HISTORICAL_QUOTES_PER_SYMBOL.IndicatorEngine.calculateSma(List<Double>, int) uses a sliding window:
Leading unavailable positions are Double.NaN.
Complexity:
IndicatorEngine.calculateEma(List<Double>, int) uses:
multiplier = 2.0 / (period + 1.0)
The first EMA value is initialized from the SMA of the first complete period. Later values use the recursive EMA formula. Leading unavailable positions are Double.NaN.
Complexity:
IndicatorExecutorManager owns a configurable fixed-size ThreadPoolExecutor. Worker threads are named with the MarketStream-Indicator- prefix.
The configured worker count controls pool capacity for concurrent indicator tasks. A single SMA/EMA calculation is sequential and does not claim to use every worker in the pool.
IndicatorTask implements Callable<IndicatorResult>, reports staged progress and supports cooperative cancellation.
Swing components are updated only from:
Timer events,SwingUtilities.invokeLater,Producer, consumer and indicator worker classes do not import or mutate Swing components.
StockChartPanel renders real data from IndicatorResult:
The chart refreshes after an explicit indicator calculation. It does not continuously recalculate indicators for every new quote.
InputValidator validates numeric fields and produces natural-language messages. IndicatorSettingsPanel highlights invalid fields with subtle red styling and tooltips.
ErrorMessageMapper maps expected exceptions to safe GUI messages and avoids exposing stack traces or raw exception class names to the user.
ThreadMonitorDialog is a non-modal Swing dialog available from View → Thread Monitor.
It displays:
The dialog receives immutable ThreadMonitorSnapshot values from the controller and refreshes with a Swing Timer only while visible.
Window close triggers a safe shutdown path:
SHUTTING_DOWN,MarketStream-Shutdown,No production code uses Thread.stop().
src/main/java/com/marketstream/
Main.java
concurrency/ producer, consumer, queue, indicator task and executor
controller/ dashboard coordination and EDT-safe delivery
model/ immutable domain and monitoring models
service/ stock generation, historical storage, indicators
util/ constants, validation, component helpers, error messages
view/ main frame and thread monitor dialog
view/chart/ chart data mapping helpers
view/components/ Swing dashboard panels
src/test/java/com/marketstream/
concurrency/ lifecycle, pipeline, executor and stress tests
model/ immutable model validation tests
service/ algorithm and history tests
util/ validation tests
view/ Swing dialog/component tests
view/chart/ chart mapping tests
Build the project:
mvn clean package
Launch the GUI:
mvn exec:java
Main class:
com.marketstream.Main
The generated standard Maven JAR is located under target/. It is not configured as a standalone shaded executable JAR.
Run all automated tests:
mvn clean test
Run package verification, including tests:
mvn clean package
Manual GUI verification should be completed with docs/MANUAL_TEST_CHECKLIST.md.
Use docs/SCREENSHOT_CHECKLIST.md for report screenshots, including:
See docs/REQUIREMENTS_TRACEABILITY.md for the final requirement-by-requirement implementation matrix.
MarketStream is ready for final coursework verification and release preparation. Automated tests cover core models, algorithms, queue behaviour, producer/consumer lifecycle, historical storage, indicator executor behaviour, chart data mapping and monitoring support. Final manual evidence should be collected using the provided checklists before submission.