diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b9093b6..9567aee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,8 +2,22 @@ name: CI on: push: branches: [develop] + paths-ignore: + - '**.md' + - 'docs/**' + - 'tutorials/**' + - 'examples/**/README.md' + - 'LICENSE' + - '.gitignore' pull_request: branches: [develop, main] + paths-ignore: + - '**.md' + - 'docs/**' + - 'tutorials/**' + - 'examples/**/README.md' + - 'LICENSE' + - '.gitignore' workflow_dispatch: inputs: triggered-by: @@ -13,10 +27,5 @@ on: jobs: build: uses: fireflyframework/.github/.github/workflows/java-ci.yml@main - permissions: - packages: read - contents: read - actions: write with: java-version: '25' - secrets: inherit diff --git a/README.md b/README.md index 48ab614..9700218 100644 --- a/README.md +++ b/README.md @@ -1,611 +1,79 @@ -# lib-utils +# Firefly Framework - Utilities [![CI](https://github.com/fireflyframework/fireflyframework-utils/actions/workflows/ci.yml/badge.svg)](https://github.com/fireflyframework/fireflyframework-utils/actions/workflows/ci.yml) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE) +[![Java](https://img.shields.io/badge/Java-21%2B-orange.svg)](https://openjdk.org) +[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.x-green.svg)](https://spring.io/projects/spring-boot) -A collection of utility classes for common operations in Java applications. +> Utility library providing template rendering, PDF generation, and filtering annotations for Firefly Framework applications. -## Overview - -The lib-utils library provides a set of powerful utilities to simplify common tasks in Java applications. The primary component is the `TemplateRenderUtil` class, which offers comprehensive template rendering capabilities using FreeMarker. +--- -## Features +## Table of Contents -### Template Rendering (FreeMarker) +- [Overview](#overview) +- [Features](#features) +- [Requirements](#requirements) +- [Installation](#installation) +- [Quick Start](#quick-start) +- [Configuration](#configuration) +- [Documentation](#documentation) +- [Contributing](#contributing) +- [License](#license) -The `TemplateRenderUtil` class provides utilities for rendering FreeMarker templates to HTML, PDF, and image formats with extensive customization options. Key capabilities include: +## Overview -- **Flexible Template Sources**: Render templates from files or strings -- **Multiple Output Formats**: Generate HTML, PDF, or image outputs -- **Direct HTML to PDF Conversion**: Convert HTML strings directly to PDF files or byte arrays -- **Customizable PDF Options**: Control page size, margins, fonts, and security -- **Performance Optimization**: Template caching for improved performance -- **Advanced Features**: Processing hooks, shared variables, and asynchronous rendering +Firefly Framework Utilities provides a set of common utility classes used across the framework ecosystem. It includes template rendering powered by FreeMarker, PDF generation via Flying Saucer with OpenPDF, and filtering annotations for domain entity identification. -### Tutorial Documentation +This library is a lightweight foundation module with minimal dependencies, designed to be included wherever utility functions are needed without pulling in the full framework stack. -Detailed tutorials are available in the `tutorials` directory: +## Features -1. **Introduction to TemplateRenderUtil**: Basic concepts and usage -2. **Template Syntax and Structure**: FreeMarker template syntax guide -3. **PDF Customization Options**: Detailed PDF configuration options -4. **Advanced Features**: Template caching, hooks, async rendering, and more +- Template rendering with FreeMarker via `TemplateRenderUtil` +- PDF generation using Flying Saucer and OpenPDF +- `@FilterableId` annotation for marking domain entity identifiers +- Lightweight with minimal transitive dependencies -## Table of Contents +## Requirements -- [Installation](#installation) -- [Quick Start Guide](#quick-start-guide) -- [Template Configuration](#template-configuration) -- [Rendering Templates to HTML](#rendering-templates-to-html) -- [Converting HTML to PDF](#converting-html-to-pdf) -- [PDF Customization Options](#pdf-customization-options) -- [Template Caching](#template-caching) -- [Template Validation](#template-validation) -- [HTML to Image Conversion](#html-to-image-conversion) -- [Template Processing Hooks](#template-processing-hooks) -- [Asynchronous Rendering](#asynchronous-rendering) -- [Security Features](#security-features) -- [Advanced Usage](#advanced-usage) -- [Error Handling](#error-handling) -- [Complete Examples](#complete-examples) +- Java 21+ +- Spring Boot 3.x +- Maven 3.9+ ## Installation -To use the utilities in this library, simply add the lib-utils dependency to your Maven `pom.xml` file: - ```xml - org.fireflyframework - lib-utils - 1.0.0 + fireflyframework-utils + 26.01.01 ``` -The lib-utils library already includes all necessary dependencies: - -- FreeMarker Template Engine (for template processing) -- Flying Saucer with OpenPDF (for PDF generation) -- SLF4J API (for logging) - -No additional dependencies are required to use the functionality provided by this library. - -## Template Configuration - -### Setting Template Directory - -Configure FreeMarker to load templates from a specific directory: - -```java -// Set a file system directory for templates -TemplateRenderUtil.setTemplateDirectory("/path/to/templates"); -``` - -### Using Multiple Template Sources - -Configure FreeMarker to load templates from multiple sources: - -```java -// Load templates from both classpath and file system -// Templates will be searched first in classpath, then in file system -TemplateRenderUtil.setClasspathAndFileTemplateLoaders("templates", "/path/to/external/templates"); -``` - -### Adding Shared Variables - -Make variables available to all templates: - -```java -// Add company information available in all templates -TemplateRenderUtil.addSharedVariable("companyName", "Acme Corporation"); -TemplateRenderUtil.addSharedVariable("companyLogo", "/images/logo.png"); -TemplateRenderUtil.addSharedVariable("currentYear", java.time.Year.now().getValue()); -``` - -### Setting Configuration Properties - -Customize FreeMarker's behavior with configuration properties: - -```java -// Create and set configuration properties -Properties props = new Properties(); -props.setProperty("number_format", "0.##"); -props.setProperty("date_format", "yyyy-MM-dd"); -props.setProperty("locale", "en_US"); - -TemplateRenderUtil.setConfigurationProperties(props); -``` - -## Rendering Templates to HTML - -### Rendering a Template File - -```java -// Create a data model -Map dataModel = new HashMap<>(); -dataModel.put("title", "Invoice #12345"); -dataModel.put("customer", customerObject); -dataModel.put("items", itemsList); - -// Render template to HTML -String html = TemplateRenderUtil.renderTemplateToHtml("invoice.ftl", dataModel); -``` - -### Rendering a Template String - -```java -// Create a template string -String templateContent = "

${title}

Hello, ${name}!

"; - -// Create a data model -Map dataModel = new HashMap<>(); -dataModel.put("title", "Welcome"); -dataModel.put("name", "John Doe"); - -// Render template string to HTML -String html = TemplateRenderUtil.renderTemplateStringToHtml(templateContent, "welcome-template", dataModel); -``` - -### Saving Template Strings for Reuse - -```java -// Create a template programmatically -String templateContent = "

${title}

${content}

"; - -// Save the template for future use -TemplateRenderUtil.saveTemplate(templateContent, "dynamic-template.ftl"); - -// Later, use the saved template -String html = TemplateRenderUtil.renderTemplateToHtml("dynamic-template.ftl", dataModel); -``` - -## Converting HTML to PDF - -### Basic Conversion - -```java -// Convert HTML to PDF with default options -TemplateRenderUtil.renderHtmlToPdf(html, outputStream, new TemplateRenderUtil.PdfOptions()); - -// Convert HTML to PDF file -TemplateRenderUtil.renderHtmlToPdfFile(html, "output.pdf"); - -// Convert HTML to PDF bytes -byte[] pdfBytes = TemplateRenderUtil.renderHtmlToPdfBytes(html); - -// Convert HTML to PDF asynchronously -CompletableFuture pdfFuture = TemplateRenderUtil.renderHtmlToPdfBytesAsync(html); -pdfFuture.thenAccept(bytes -> { - // Process the PDF bytes -}); -``` - -### Direct Template to PDF Conversion - -```java -// Render template directly to PDF file -TemplateRenderUtil.renderTemplateToPdfFile("invoice.ftl", dataModel, "invoice.pdf"); - -// Render template to PDF bytes -byte[] pdfBytes = TemplateRenderUtil.renderTemplateToPdfBytes("invoice.ftl", dataModel); -``` - -### Template String to PDF Conversion - -```java -// Create a template string -String templateContent = "

${title}

${content}

"; - -// Create a data model -Map dataModel = new HashMap<>(); -dataModel.put("title", "Generated PDF"); -dataModel.put("content", "This PDF was generated from a template string."); - -// Render template string directly to PDF file -TemplateRenderUtil.renderTemplateStringToPdfFile( - templateContent, - "inline-template", - dataModel, - "template-string-output.pdf" -); - -// Render template string to PDF bytes (useful for web downloads) -byte[] pdfBytes = TemplateRenderUtil.renderTemplateStringToPdfBytes( - templateContent, - "inline-template", - dataModel -); -``` - -## PDF Customization Options - -The `PdfOptions` class provides customization for PDF output: - -```java -// Create PDF options with custom settings -TemplateRenderUtil.PdfOptions options = new TemplateRenderUtil.PdfOptions() - // Set page size (A4, LETTER, LEGAL, A3) - .withPageSize(TemplateRenderUtil.PdfOptions.PageSize.LETTER) - - // Set margins in points (1/72 inch) - .withMargins(72, 72, 72, 72) // 1 inch margins on all sides - - // Set base URI for resolving relative links - .withBaseUri("classpath:static/") - - // Set font directory for custom fonts - .withFontDirectory("/path/to/fonts") - - // Set default font - .withDefaultFont("Arial") - - // Add PDF bookmarks (outline entries) - .withBookmark("Chapter 1", "1") - .withChildBookmark("Section 1.1", "1") - .withChildBookmark("Section 1.2", "1") - .withBookmark("Chapter 2", "2"); - -// Use the options when converting to PDF -TemplateRenderUtil.renderTemplateToPdfFile("invoice.ftl", dataModel, "custom-output.pdf", options); - -// Or use with template string -TemplateRenderUtil.renderTemplateStringToPdfFile( - templateContent, - "inline-template", - dataModel, - "custom-string-output.pdf", - options -); -``` - -## Template Caching - -Improve performance by caching templates: - -```java -// Enable template caching -TemplateRenderUtil.setTemplateCachingEnabled(true); - -// Set maximum cache size (number of templates) -TemplateRenderUtil.setTemplateCacheMaxSize(100); - -// Clear the template cache when needed -TemplateRenderUtil.clearTemplateCache(); -``` - -## Template Validation - -Validate templates before using them: - -```java -// Validate a template string -String templateContent = "

Hello ${name}!

"; -List errors = TemplateRenderUtil.validateTemplate(templateContent); -if (errors.isEmpty()) { - System.out.println("Template is valid!"); -} else { - System.out.println("Template has errors: " + errors); -} - -// Validate a template file -List fileErrors = TemplateRenderUtil.validateTemplateFile("invoice.ftl"); -if (fileErrors.isEmpty()) { - System.out.println("Template file is valid!"); -} else { - System.out.println("Template file has errors: " + fileErrors); -} -``` - -## HTML to Image Conversion - -Convert HTML content or templates to images: - -```java -// Convert HTML string to image -String html = "

Hello World

"; -byte[] pngBytes = TemplateRenderUtil.renderHtmlToImage(html, 800, 600, "png"); - -// Save the image to a file -TemplateRenderUtil.saveImageToFile(pngBytes, "output.png"); - -// Render a template directly to an image -byte[] templateImageBytes = TemplateRenderUtil.renderTemplateToImage( - "certificate.ftl", - dataModel, - 1024, 768, - "jpg" -); - -// Render a template string to an image -String templateContent = "

${title}

${content}

"; -byte[] templateStringImageBytes = TemplateRenderUtil.renderTemplateStringToImage( - templateContent, - "inline-template", - dataModel, - 800, 600, - "png" -); -``` - -## Template Processing Hooks - -Add pre-processing and post-processing hooks to modify templates and rendered HTML: - -```java -// Add a pre-processor to modify template content before rendering -TemplateRenderUtil.setTemplatePreProcessor((content, model) -> { - // Add a header to all templates - return "
Company Header
\n" + content; -}); - -// Add a post-processor to modify rendered HTML -TemplateRenderUtil.setTemplatePostProcessor((html, model) -> { - // Add analytics code to all rendered pages - return html + "\n"; -}); - -// Clear processors when no longer needed -TemplateRenderUtil.setTemplatePreProcessor(null); -TemplateRenderUtil.setTemplatePostProcessor(null); -``` - -## Asynchronous Rendering - -Render templates asynchronously for improved performance: - -```java -// Render template to HTML asynchronously -CompletableFuture htmlFuture = TemplateRenderUtil.renderTemplateToHtmlAsync( - "report.ftl", - dataModel -); - -// Process the result when it's ready -htmlFuture.thenAccept(html -> { - System.out.println("HTML rendering completed, length: " + html.length()); -}); - -// Render template to PDF asynchronously -CompletableFuture pdfFuture = TemplateRenderUtil.renderTemplateToPdfBytesAsync( - "invoice.ftl", - invoiceData, - new TemplateRenderUtil.PdfOptions() -); - -// Process the PDF when it's ready -pdfFuture.thenAccept(pdfBytes -> { - System.out.println("PDF rendering completed, size: " + pdfBytes.length + " bytes"); - // Save the PDF or send it to the client -}); - -// Configure the thread pool size for async operations -TemplateRenderUtil.setAsyncThreadPoolSize(10); - -// Shutdown the thread pool when no longer needed (e.g., on application shutdown) -TemplateRenderUtil.shutdownAsyncThreadPool(); -``` - -## Security Features - -Protect your PDF documents with passwords and permissions: +## Quick Start ```java -// Create PDF options with security settings -PdfRenderOptions options = new PdfRenderOptions() - // Set user password (required to open the document) - .setUserPassword("user123") - - // Set owner password (required to change the document) - .setOwnerPassword("owner456") - - // Set permissions - .setAllowPrinting(true) // Allow/disallow printing - .setAllowCopy(false); // Allow/disallow copying content +import org.fireflyframework.utils.template.TemplateRenderUtil; -// Use the options when converting to PDF -TemplateRenderUtil.renderTemplateToPdf("confidential-report.ftl", dataModel, "protected-report.pdf", options); +// Render a FreeMarker template +Map data = Map.of("name", "Firefly"); +String result = TemplateRenderUtil.render("hello.ftl", data); ``` -## Advanced Usage - -### Saving Templates - -```java -// Create a template programmatically -String templateContent = "\n" + - "\n" + - "${title}\n" + - "\n" + - "

${title}

\n" + - "

${content}

\n" + - "\n" + - ""; - -// Save the template for future use -TemplateRenderUtil.saveTemplate(templateContent, "dynamic-template.ftl"); -``` - -### Combining Multiple Features - -```java -// Set up template configuration -TemplateRenderUtil.setClasspathAndFileTemplateLoaders("templates", "./custom-templates"); -TemplateRenderUtil.addSharedVariable("company", companyInfo); +## Configuration -// Create custom PDF options -PdfRenderOptions options = new PdfRenderOptions(PdfRenderOptions.PageSize.A4) - .setMargins(50) - .setUserPassword("secret") - .setAllowPrinting(true) - .setAllowCopy(false); +No configuration is required. This library provides standalone utility classes. -// Render template directly to PDF with all options -TemplateRenderUtil.renderTemplateToPdf("reports/quarterly.ftl", reportData, "Q2-2023-Report.pdf", options); -``` - -## Error Handling - -The utility provides detailed error handling: - -```java -try { - // Attempt to render a template - String html = TemplateRenderUtil.renderTemplateToHtml("invoice.ftl", dataModel); - TemplateRenderUtil.renderTemplateToPdfFile("invoice.ftl", dataModel, "invoice.pdf"); -} catch (IOException e) { - // Handle file access errors - logger.error("Could not access template or output file", e); -} catch (TemplateException e) { - // Handle template processing errors - logger.error("Error in template syntax or processing", e); -} catch (DocumentException e) { - // Handle PDF creation errors - logger.error("Error creating PDF document", e); -} -``` - -## Complete Examples - -### Invoice Generation Example - -```java -// Create invoice data -Map invoice = new HashMap<>(); -invoice.put("invoiceNumber", "INV-2023-001"); -invoice.put("date", new Date()); -invoice.put("dueDate", new Date(System.currentTimeMillis() + 30L * 24 * 60 * 60 * 1000)); +## Documentation -Map customer = new HashMap<>(); -customer.put("name", "John Doe"); -customer.put("email", "john.doe@example.com"); -customer.put("address", "123 Main St, Anytown, USA"); -invoice.put("customer", customer); +No additional documentation available for this project. -List> items = new ArrayList<>(); -items.add(createItem("Website Design", 1, 1200.00)); -items.add(createItem("Hosting (1 year)", 1, 300.00)); -items.add(createItem("Domain Registration", 2, 15.00)); -invoice.put("items", items); +## Contributing -// Calculate totals -double subtotal = items.stream() - .mapToDouble(item -> (double)item.get("quantity") * (double)item.get("price")) - .sum(); -invoice.put("subtotal", subtotal); -invoice.put("tax", subtotal * 0.1); // 10% tax -invoice.put("total", subtotal * 1.1); - -// Set up PDF options -TemplateRenderUtil.PdfOptions options = new TemplateRenderUtil.PdfOptions() - .withPageSize(TemplateRenderUtil.PdfOptions.PageSize.A4) - .withMargins(36, 36, 36, 36); // 0.5 inch margins - -// Generate the invoice PDF -try { - TemplateRenderUtil.renderTemplateToPdfFile("invoice.ftl", invoice, - "Invoice-" + invoice.get("invoiceNumber") + ".pdf", options); - System.out.println("Invoice generated successfully!"); -} catch (Exception e) { - System.err.println("Failed to generate invoice: " + e.getMessage()); - e.printStackTrace(); -} - -// Helper method to create an item -private static Map createItem(String description, int quantity, double price) { - Map item = new HashMap<>(); - item.put("description", description); - item.put("quantity", quantity); - item.put("price", price); - item.put("amount", quantity * price); - return item; -} -``` - -### Dynamic Template Generation Example - -```java -// Create a template string dynamically -StringBuilder templateBuilder = new StringBuilder(); -templateBuilder.append("\n"); -templateBuilder.append("\n"); -templateBuilder.append("\n"); -templateBuilder.append(" ${title}\n"); -templateBuilder.append(" \n"); -templateBuilder.append("\n"); -templateBuilder.append("\n"); -templateBuilder.append("

${title}

\n"); -templateBuilder.append("
\n"); -templateBuilder.append("

${content}

\n"); -templateBuilder.append(" <#if items?has_content>\n"); -templateBuilder.append("
    \n"); -templateBuilder.append(" <#list items as item>\n"); -templateBuilder.append("
  • ${item}
  • \n"); -templateBuilder.append(" \n"); -templateBuilder.append("
\n"); -templateBuilder.append(" \n"); -templateBuilder.append("
\n"); -templateBuilder.append("
\n"); -templateBuilder.append(" Generated on: ${.now?string(\"yyyy-MM-dd HH:mm:ss\")}\n"); -templateBuilder.append("
\n"); -templateBuilder.append("\n"); -templateBuilder.append(""); - -String templateContent = templateBuilder.toString(); - -// Create a data model -Map dataModel = new HashMap<>(); -dataModel.put("title", "Dynamic Template Example"); -dataModel.put("content", "This document was generated from a dynamically created template string."); - -List items = new ArrayList<>(); -items.add("Item 1"); -items.add("Item 2"); -items.add("Item 3"); -dataModel.put("items", items); - -// Render the template string to PDF -try { - TemplateRenderUtil.renderTemplateStringToPdfFile( - templateContent, - "dynamic-template", - dataModel, - "dynamic-template-output.pdf" - ); - System.out.println("Dynamic template PDF generated successfully!"); -} catch (Exception e) { - System.err.println("Failed to generate PDF: " + e.getMessage()); - e.printStackTrace(); -} -``` - -### Annotations - -#### FilterableId - -The `@FilterableId` annotation is used to mark ID fields that should be included in filtering operations. By default, fields that end with "Id" are excluded from filter parameters, but when a field is annotated with `@FilterableId`, it will be included in the filters with specific behavior. - -```java -public class UserFilterDTO { - @FilterableId - private Long customerId; // Will be included in filters with exact matching - - private Long accountId; // Will be excluded from filters - - private String name; // Regular field with full filtering capabilities -} -``` +Contributions are welcome. Please read the [CONTRIBUTING.md](CONTRIBUTING.md) guide for details on our code of conduct, development process, and how to submit pull requests. -##### Behavior +## License -- In OpenAPI/Swagger documentation: - - The field will appear as a query parameter - - No range parameters will be generated for the field +Copyright 2024-2026 Firefly Software Solutions Inc. -- In runtime filtering: - - The field will be included in filtering operations - - Only exact matching will be used (no LIKE or range operations) - - Range filters will be ignored for this field +Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for details. diff --git a/pom.xml b/pom.xml index 667f4e7..3e7b952 100644 --- a/pom.xml +++ b/pom.xml @@ -20,14 +20,14 @@ org.freemarker freemarker - 2.3.32 + 2.3.34 org.xhtmlrenderer flying-saucer-pdf-openpdf - 9.3.1 + 9.3.2