# Com / Github / Blaxk3

## Overview

The `com.github.blaxk3` package is a **desktop Currency Converter** application built in Java with Swing. It provides a complete end-to-end capability: users open a window, enter an amount, select a source and target currency, and receive a real-time conversion result fetched from the [ExchangeRate API (v6)](https://www.exchangerate-api.com/).

The package is organized into three cohesive sub-modules that follow a layered architecture:

| Sub-module | Role | Class |
|---|---|---|
| `api` | Data access layer | `CurrencyRateAPI` |
| `ui` | Presentation layer | `UI` (extends `JFrame`) |
| `converter` | Application bootstrap | `CurrencyConverter` |

At a high level, the flow is simple: **the `converter` module starts the app, which creates the `UI` window, which talks to the `api` module to fetch live exchange rates from a remote HTTP service.** There is no separate domain or service layer — the `UI` class orchestrates directly with the API client, making this a thin, desktop-first architecture.

## Sub-module Guide

### `api` — The Currency Rate Client

This sub-module is the sole bridge between the application and the outside world. It contains a single class, `CurrencyRateAPI`, which:

- Loads an API key from `config.properties` on the classpath.
- Assembles authenticated URLs against the ExchangeRate API v6 base endpoint (`https://v6.exchangerate-api.com/v6/{apiKey}`).
- Sends HTTP GET requests and parses JSON responses via Gson.
- Exposes two public operations: `getCurrencyCode()` (returns all supported ISO 4217 currency codes) and `convert(from, to, amount)` (returns a converted amount as a string).

**What it does not do:** It has no caching, no retry logic, no timeout configuration, and no entity models. It returns raw JSON (`JsonObject`) and strings. This is by design — the package is a lean, single-responsibility HTTP client.

### `ui` — The Graphical Frontend

This sub-module owns every pixel on the screen. The `UI` class (extending `JFrame`) constructs the entire application window programmatically — no GUI builder, no FXML, no layouts defined in XML. It provides:

- A two-panel layout (source currency + amount entry on the left; result + target currency + action buttons on the right).
- Input validation via a custom `NumericFilter` (a `DocumentFilter`) that restricts the amount field to digits and at most one decimal point.
- Background currency code fetching via a `CurrencyCode` `SwingWorker`, keeping the UI responsive during startup while the API is queried.
- Three action buttons: **Convert** (fetches and displays the conversion), **Swap** (exchanges the two currency selections), and **Clear** (resets input and output).

**What it does not do:** It contains no business logic beyond input validation and UI orchestration. It does not store data, perform calculations itself, or manage configuration.

### `converter` — The Entry Point

This sub-module is the smallest and most focused. It contains the `CurrencyConverter` class with a single `main` method:

```java
SwingUtilities.invokeLater(UI::new);
```

That's it. Its only responsibility is to launch the `UI` on the Swing Event Dispatch Thread (EDT). All application logic lives in the `api` and `ui` sub-modules. This keeps the entry point trivial and ensures the UI always starts on the correct thread.

### How the Sub-modules Relate

The three sub-modules form a clear **bootstrap → presentation → data** chain:

1. **`converter`** starts the JVM and schedules `UI` construction on the EDT.
2. **`ui`** builds the window, spawns background workers to populate currency dropdowns, and wires up button listeners.
3. **`api`** is called by `ui` — first to fetch currency codes (during startup) and then to perform conversions (on demand).

The `ui` module depends on `api`; `converter` depends on `ui`. There are no circular dependencies and no shared mutable state between modules.

## Architecture Diagram

```mermaid
flowchart TD
    Entry["CurrencyConverter<br/>Entry Point"] --> UI["UI JFrame<br/>Presentation Layer"]
    Entry --> API["CurrencyRateAPI<br/>API Client Layer"]
    UI --> API
    UI --> NC["NumericFilter<br/>Input Validation"]
    UI --> CW["CurrencyCode<br/>SwingWorker"]
    API --> ER["External ExchangeRate API v6"]
    CW --> API
    NC --> UI
```

This diagram shows the three layers and the internal components within the `UI` layer:

- **CurrencyConverter** bootstraps the application and creates the `UI` window on the EDT.
- **UI** owns the window and its components. It delegates currency code fetching to `CurrencyCode` (a `SwingWorker`) and currency conversion to `CurrencyRateAPI`. Input is validated by `NumericFilter`.
- **CurrencyRateAPI** is the data access layer. It makes HTTP requests to the external ExchangeRate API v6 service.
- **NumericFilter** is an internal component of `UI` that restricts the amount field to numeric input.
- **CurrencyCode** is a `SwingWorker` nested in `UI` that fetches currency codes off the EDT.

## Key Patterns and Architecture

### Layered Architecture with Thin Boundaries

The package uses a three-layer structure:

- **Presentation** (`ui`) — handles all user interaction.
- **Data Access** (`api`) — handles all external communication.
- **Bootstrap** (`converter`) — initializes the application.

There is no domain model or service layer. The `UI` class calls `CurrencyRateAPI` directly. This is intentional for a simple desktop utility but means the architecture has limited testability — unit tests would need to exercise Swing components or mock `CurrencyRateAPI`.

### Request-Response Pattern in the API Layer

`CurrencyRateAPI` follows a straightforward request-response pattern:

1. Load API key from properties.
2. Build URL via string concatenation.
3. Open `HttpURLConnection`, send GET, read response stream.
4. Parse JSON with Gson, extract the needed field.
5. Return a raw value (array of strings or a single result string).

The only abstraction is `getJsonObject(URL)`, which centralizes HTTP communication. This is the natural extension point for adding timeouts, retries, or custom headers.

### Composition Over Inheritance in the UI

The `UI` class uses factory methods (`comboBox1()`, `comboBox2()`, `button()`, `textField()`, `label()`) to create self-contained `JPanel` components. Each method configures and returns a complete piece of the UI. This keeps component creation encapsulated and makes each panel independent, which aids readability and potential reuse.

### SwingWorker for Non-Blocking Startup

Both currency dropdowns independently spawn a `CurrencyCode` `SwingWorker` to fetch currency codes from the API. This keeps the EDT responsive during startup — the user sees the window immediately while the background workers populate the dropdowns. The `done()` method runs on the EDT and updates the `JComboBox` instances directly.

### Decimal Precision Strategy

The `convert()` method accepts a `BigDecimal` for the input amount (correct for financial calculations) but returns the result as a `String`. The `UI` layer formats this string with `DecimalFormat("#,###.###")` for display. If downstream code needs numeric precision, it must parse the returned string back into a `BigDecimal`.

### Input Validation via DocumentFilter

`NumericFilter` extends `DocumentFilter` and intercepts every insert and replace operation on the amount text field. It reconstructs the document content with the new characters and validates that:

- The string is empty (allows clearing the field).
- There is at most one decimal point.
- All other characters are digits.

This prevents invalid input at the AWT level rather than waiting for button-click validation.

## Dependencies and Integration

### External Dependencies

| Dependency | Purpose | Consumed By |
|---|---|---|
| **ExchangeRate API v6** | Live exchange rate data via HTTP | `CurrencyRateAPI` |
| **Gson** | JSON parsing of API responses | `CurrencyRateAPI` |
| **SLF4J** | Structured logging | `CurrencyRateAPI`, `UI` (via `CurrencyCode`) |
| **Java Swing** | Desktop GUI components | `UI`, `CurrencyConverter` |
| **Java AWT / Math** | Layout, colors, fonts, `BigDecimal` | `UI`, `CurrencyRateAPI` |

### Configuration

The application requires a `config.properties` file on the classpath containing:

```
API_KEY=<your-exchangerate-api-key>
```

If the file is missing or the `API_KEY` property is absent, `getApiKeyService()` returns `null`, which propagates through the URL-building chain and causes API calls to fail silently (they return `null`). Logs will contain the message `Unable to find config.properties`.

### Integration with the Rest of the System

This module operates as a standalone desktop application. It does not integrate with other modules within a larger codebase — it is self-contained. Its only external connection is the HTTP call to `https://v6.exchangerate-api.com/v6/`. There are no cross-module dependencies in the project index.

## Notes for Developers

### Configuration and Deployment

- **API key management:** The API key is stored as a plain text property in `config.properties`. This is suitable for development but should not be committed to version control in production. Consider using an environment variable or a secrets manager for deployed applications.
- **Classpath:** The properties file must be on the application classpath at runtime. If the application is packaged as a JAR, include it in the resources directory.

### Error Handling Gaps

- **Conversion failures are silent or catastrophic:** When `CurrencyRateAPI.convert()` fails (e.g., network error, invalid API key), `getJsonObject()` returns `null`. The `UI` layer catches `MalformedURLException` and `URISyntaxException` but wraps them in a `RuntimeException` — this crashes the application rather than showing a user-friendly error. Consider replacing this with an error dialog.
- **Empty dropdowns have no feedback:** If `CurrencyCode` fails to fetch currency codes (e.g., network unreachable), the `SwingWorker` logs the error but gives the user no visual indication that the dropdowns are empty. A placeholder message or error banner would improve the experience.
- **No loading state during conversion:** The "Convert" button blocks the EDT while the HTTP request is in flight. For slow network conditions, the UI will freeze. This should be offloaded to a `SwingWorker` or similar background task.

### Concurrency Considerations

- The class is effectively stateless — the only field is a static logger, which is thread-safe. Multiple threads can safely share a `CurrencyRateAPI` instance.
- Under high concurrent load, each call opens a new `HttpURLConnection`. Consider connection pooling at a higher level if this becomes a bottleneck.

### Precision Caveats

The `convert()` method returns the result as a `String`. Callers that need to perform further arithmetic must parse it back into a `BigDecimal`. Be aware that `DecimalFormat` in the UI applies rounding (`#,###.###` — up to 3 decimal places), so the displayed value may not match the raw API result exactly.

### Extending the Application

Natural extension points include:

- **Additional API endpoints:** Extend `CurrencyRateAPI` to support historical rates, time-series data, or currency pairs endpoints by following the existing URL construction pattern.
- **New UI features:** Add rows to `panel()`, new buttons in `button()`, or extended validation in `NumericFilter`.
- **Background conversion:** Move the `convert()` call from the EDT into a `SwingWorker` to prevent UI freezing.
- **Error recovery:** Add retry logic in `getJsonObject()` with exponential backoff, or add a user-facing error dialog in the UI.
- **Theming / styling:** The UI uses hardcoded colors (`Color.GRAY`, `Color.WHITE`). Extract these into constants or a theme config for easier customization.

### Testing Considerations

The lack of a domain layer makes unit testing difficult. To improve testability:

- Extract the conversion logic into a separate service class that accepts currency codes and amounts and returns a result — this class would be easy to unit test.
- Mock `CurrencyRateAPI` in UI tests, or inject a test double via a constructor parameter.
- Consider using a headless testing framework (e.g., Jemmy or Robot) for integration tests of the Swing UI.