Skip to content

Add ConfigTool for unified site configuration management#104

Merged
bertysentry merged 4 commits intomainfrom
103-prompt-for-maven-skin-tools-create-a-configtool-for-unified-skin-configuration
Feb 11, 2026
Merged

Add ConfigTool for unified site configuration management#104
bertysentry merged 4 commits intomainfrom
103-prompt-for-maven-skin-tools-create-a-configtool-for-unified-skin-configuration

Conversation

@bertysentry
Copy link
Member

Add ConfigTool for Unified Site Configuration Management

Overview

This PR introduces a new ConfigTool that provides unified configuration management for Maven sites, merging site-wide settings from site.xml with per-page overrides from Markdown front matter.

Problem

Previously, handling configuration with front matter overrides required verbose manual code in Velocity templates for each variable:

#set($interpolation = $site.getCustomValue("interpolation", "maven"))
#set($tempHeadElement = $htmlTool.parseContent($headContent))
#if($tempHeadElement)
    #set($pageInterpolation = $htmlTool.getAttr($tempHeadElement, "meta[name=interpolation]", "content"))
    #if($pageInterpolation && !$pageInterpolation.isEmpty())
        #set($interpolation = $pageInterpolation.get(0))
    #end
#end

This pattern needed to be repeated for every configuration variable, making the code verbose and error-prone.

Solution

The new ConfigTool provides a clean, type-safe API:

#set($interpolation = $configTool.getValue($site, $headContent, "interpolation", "maven"))
#set($showToc = $configTool.getBooleanValue($site, $headContent, "showToc", true))
#set($tocMaxDepth = $configTool.getIntValue($site, $headContent, "tocMaxDepth", 3))

Features

Configuration Precedence

  1. Front matter (per-page) - highest priority
  2. Site-wide configuration (site.xml)
  3. Default value - specified in the method call

API Methods

  • getValue() - Get string configuration values
  • getBooleanValue() - Get boolean values with intelligent parsing
    • Recognizes "true", "yes", "1" as true (case-insensitive)
    • Recognizes "false", "no", "0" as false (case-insensitive)
  • getIntValue() - Get integer values with proper error handling

Technical Highlights

  • ✅ Weak reference caching to avoid re-parsing headContent multiple times
  • ✅ Reflection-based site model access (compatible with Maven Site Plugin 3.x and 4.x)
  • ✅ Null-safe handling of all inputs
  • ✅ Comprehensive error handling with sensible defaults

Testing

  • 31 new unit tests covering all functionality
  • Tests for precedence order, type conversion, null safety, caching, and edge cases
  • All 108 tests pass (including existing tests)

Code Quality

  • Checkstyle: 0 violations
  • PMD: 0 violations
  • SpotBugs: 0 bugs
  • Javadoc: Complete and valid
  • Code formatting: Compliant
  • License headers: Present

Documentation

Updated src/site/markdown/index.md with:

  • Usage examples
  • Configuration precedence explanation
  • Front matter and site.xml examples

Files Changed

  • New: src/main/java/org/sentrysoftware/maven/skin/ConfigTool.java
  • New: src/test/java/org/sentrysoftware/maven/skin/ConfigToolTest.java
  • 📝 Modified: src/main/resources/tools.xml (registered $configTool)
  • 📝 Modified: src/site/markdown/index.md (added documentation)

Usage Example

Markdown Front Matter

---
interpolation: none
showToc: false
tocMaxDepth: 2
---

# My Page

Content here...

Site-wide Configuration (site.xml)

<project>
  <custom>
    <interpolation>maven</interpolation>
    <showToc>true</showToc>
    <tocMaxDepth>3</tocMaxDepth>
  </custom>
</project>

Velocity Template Usage

#set($interpolation = $configTool.getValue($site, $headContent, "interpolation", "maven"))
#set($showToc = $configTool.getBooleanValue($site, $headContent, "showToc", true))
#set($tocMaxDepth = $configTool.getIntValue($site, $headContent, "tocMaxDepth", 3))

#if($showToc)
  <!-- Render table of contents with max depth $tocMaxDepth -->
#end

Closes

Fixes #103

Implements a new ConfigTool that provides a clean API for retrieving
configuration values with proper precedence handling:
- Front matter (Markdown) overrides site-wide settings (site.xml)
- Site-wide settings override default values

Features:
- getValue() for string configuration values
- getBooleanValue() with smart parsing (true/yes/1, false/no/0)
- getIntValue() with proper error handling
- Weak reference caching for performance
- Compatible with Maven Site Plugin 3.x and 4.x via reflection
- Comprehensive test coverage (31 unit tests)

This eliminates the verbose manual pattern previously required for
each configuration variable in Velocity templates.

Fixes #103
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces a new Velocity ConfigTool to centralize configuration lookup for Maven sites, applying the precedence order of per-page front matter overrides (via <meta> tags) over site.xml <custom> values, with call-site defaults as fallback.

Changes:

  • Added ConfigTool with getValue, getBooleanValue, and getIntValue helpers plus a headContent meta-tag parsing cache.
  • Registered $configTool in tools.xml for application-scope use in Velocity templates.
  • Added unit tests and updated site documentation with usage and precedence examples.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
src/main/java/org/sentrysoftware/maven/skin/ConfigTool.java New tool implementing merged config lookup and caching for meta tags.
src/test/java/org/sentrysoftware/maven/skin/ConfigToolTest.java New unit tests covering precedence and type conversion scenarios.
src/main/resources/tools.xml Registers the new tool as configTool in the application toolbox.
src/site/markdown/index.md Documents the new tool’s API, precedence rules, and examples.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Addresses code review feedback to fix critical issues with the cache:

- Fix hash collision issue by using headContent string directly as cache
  key instead of Objects.hash(), preventing different pages from sharing
  cached meta values

- Add thread safety by wrapping cache with Collections.synchronizedMap()
  since ConfigTool is in application-scope and can be accessed concurrently
  during parallel page rendering

- Replace HashMap+WeakReference with WeakHashMap to allow automatic
  garbage collection of cache entries when headContent strings are no
  longer referenced, preventing unbounded growth

- Simplify implementation using computeIfAbsent() instead of manual
  get-check-put pattern

- Add getCacheSize() method and enhance testCaching() to actually verify
  caching behavior rather than just checking returned values

All tests pass. No functional changes to the public API.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Addresses additional code review feedback:

1. Cache resolved Method per siteModel class
   - Use ConcurrentHashMap<Class<?>, Optional<Method>> to cache the
     reflective method lookup result
   - Optional.empty() indicates "looked up but not found" to avoid
     repeated failed lookups
   - Eliminates overhead of getMethod() on every getSiteCustomValue() call

2. Log parse failures and don't cache failed results
   - parseMetaTags() now returns null on failure instead of empty map
   - Failed parses are not cached, allowing retry on subsequent calls
   - Logs WARNING with exception details when parsing fails

3. Log reflection failures for easier debugging
   - Log FINE (debug) level when getCustomValue method not found on class
   - Log WARNING with exception when method invocation fails
   - Messages include class name for easier diagnosis

All tests pass. No functional changes to the public API.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@bertysentry bertysentry merged commit 5c5f4dd into main Feb 11, 2026
10 checks passed
@bertysentry bertysentry deleted the 103-prompt-for-maven-skin-tools-create-a-configtool-for-unified-skin-configuration branch February 11, 2026 14:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create a ConfigTool for Unified Skin Configuration

1 participant