/****************************************************************************
* Copyright (c) 2022-2025 Imixs Software Solutions GmbH and others.
* https://www.imixs.com
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0
*
* This Source Code may also be made available under the terms of the
* GNU General Public License, version 2 or later (GPL-2.0-or-later),
* which is available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
****************************************************************************/
package com.alexanderlogistics;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.imixs.workflow.engine.TextEvent;
import org.imixs.workflow.util.XMLParser;
import jakarta.ejb.Stateless;
import jakarta.enterprise.event.Observes;
/**
* The AGLTimestampAdapter replaces text fragments with a specific timestamp.
*
* The adapter parses a text for the tag `` and replaces the tag
* with the current system time.
* The output can be formatted with the attribute `format` adapting the Java
* Time Format.
* The timestamp can further be adjusted by days or minutes using the optional
* attributes `adjustDays` or `adjustMinutes`.
*
* NOTE: Can be removed with Imixs-Workflow versin 6.2.8
*
* @author rsoika
*
*/
@Stateless
public class AGLTimestampAdapter {
private static final Logger logger = Logger.getLogger(AGLTimestampAdapter.class.getName());
// Default format pattern used if no 'format' attribute is provided
private static final String DEFAULT_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
/**
* This method reacts on CDI events of the type TextEvent and parses a string
* for xml tag . Those tags will be replaced with the current
* system time.
*
*/
public void onEvent(@Observes TextEvent event) {
String text = event.getText();
boolean debug = logger.isLoggable(Level.FINE);
List timestampTags = XMLParser.findTags(text, "timestamp");
// Replace each tag with the computed timestamp
for (String tag : timestampTags) {
String timestamp = computeTimestamp(tag);
if (debug) {
logger.log(Level.FINE, "replacing tag ''{0}'' with ''{1}''", new Object[] { tag, timestamp });
}
text = text.replace(tag, timestamp);
}
event.setText(text);
}
/**
* Computes the timestamp string for a given tag.
*
* Supports the optional attributes:
* - format: a java.time.format.DateTimeFormatter pattern
* - adjustDays: number of days to add (negative values subtract)
* - adjustMinutes: number of minutes to add (negative values subtract)
*
* @param tag - the full xml tag string, e.g.
* @return the formatted timestamp
*/
/**
* Computes the timestamp string for a given tag.
*
* Supports the optional attributes:
* - format: a java.time.format.DateTimeFormatter pattern
* - adjustMonths: number of months to add (negative values subtract)
* - adjustDays: number of days to add (negative values subtract)
* - adjustMinutes: number of minutes to add (negative values subtract)
* - adjustSeconds: number of seconds to add (negative values subtract)
*
* @param tag - the full xml tag string, e.g.
* @return the formatted timestamp
*/
private String computeTimestamp(String tag) {
LocalDateTime now = LocalDateTime.now();
now = applyAdjustment(now, tag, "adjustMonths", ChronoUnit.MONTHS);
now = applyAdjustment(now, tag, "adjustDays", ChronoUnit.DAYS);
now = applyAdjustment(now, tag, "adjustMinutes", ChronoUnit.MINUTES);
now = applyAdjustment(now, tag, "adjustSeconds", ChronoUnit.SECONDS);
// Resolve the format pattern, fallback to default if not provided or invalid
String format = XMLParser.findAttribute(tag, "format");
String pattern = (format != null && !format.isEmpty()) ? format : DEFAULT_FORMAT;
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
return now.format(formatter);
} catch (IllegalArgumentException e) {
logger.log(Level.WARNING, "invalid format pattern ''{0}'' - using default format", pattern);
return now.format(DateTimeFormatter.ofPattern(DEFAULT_FORMAT));
}
}
/**
* Reads the given attribute from the tag and, if present, adjusts the
* given LocalDateTime by that amount using the specified ChronoUnit.
*
* @param dateTime - the date/time to adjust
* @param tag - the full xml tag string
* @param attributeName - the attribute name to look up (e.g. "adjustDays")
* @param unit - the ChronoUnit to apply the value with
* @return the adjusted LocalDateTime, or the unchanged input if the
* attribute is missing or invalid
*/
private LocalDateTime applyAdjustment(LocalDateTime dateTime, String tag, String attributeName, ChronoUnit unit) {
String value = XMLParser.findAttribute(tag, attributeName);
if (value != null && !value.isEmpty()) {
try {
long amount = Long.parseLong(value.trim());
return dateTime.plus(amount, unit);
} catch (NumberFormatException e) {
logger.log(Level.WARNING, "invalid {0} value ''{1}'' - ignoring",
new Object[] { attributeName, value });
}
}
return dateTime;
}
}