Merge pull request #3 from kneitzel/add-existing-stuff

Add existing stuff
This commit is contained in:
Konrad Neitzel 2025-04-03 21:10:15 +02:00 committed by GitHub
commit f98e476458
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 2163 additions and 178 deletions

View File

@ -1,23 +1,16 @@
# NeitzelLib Maven Project
Small Library with classes that I found helpfully or interesting.
## A Java Utilities Library
The idea is not to diretly use anything from this library. It is only meant to provide some code which could be a quick start when required inside a project. So simply copy the classes that you need.
This repository is **not** a production-ready library, but rather a loose collection of small helpers, utilities, and ideas that might come in handy for Java developers.
## Components
The code in this project is intended as a **starting point** or **inspiration** for your own solutions. It is often easier to copy and adapt individual classes as needed instead of using the whole library as a dependency.
### core
Feel free to explore, copy, modify, and improve whatever you find useful.
This is the core library that does not have special dependencies like JavaFX.
> ⚠️ Use at your own discretion — no guarantees of stability, backwards compatibility, or completeness.
It contains:
- **inject** Some small, basic Injection Library (Just a quick start)
- **sql** Helper classes to work with SQL in Java
---
### fx
Library that extends JavaFX or helps with it.
It contains:
- **component** Just a quick start where I experiment with the idea to have JavaFX components which means that we have a View to display a specific Model.
- **injectfx** Injection inside JavaFX, main idea is to use constructor injection on FXML controller to include required Elements.
- **mvvm** The mvvmFX project seems to get no more updates / is no longer maintained. In this area I am simply playing around with some helper classes to make the use of the mvvm pattern easier through generation of ViewModels. **Currently not really useable**
## License
This is free and unencumbered software released into the public domain. Please see the [License](LICENSE.md) for details.

View File

@ -0,0 +1,95 @@
package de.neitzel.core.commandline;
import java.util.Iterator;
/**
* The ArgumentProvider class is a helper utility for iterating over an array
* of command-line arguments. It provides methods to check for available arguments
* and retrieve them in sequence.
*
* This class is designed to work seamlessly with a command-line parser
* and handle tokenized inputs efficiently. It implements the Iterator interface
* for ease of iteration.
*/
public class ArgumentProvider implements Iterator<String> {
/**
* A String array representing the command-line arguments provided to the application.
* This array holds each tokenized element of the command-line input for further parsing
* and processing by the application logic. It is used within the {@code ArgumentProvider}
* class to iterate through and retrieve arguments systematically.
*/
private String[] arguments;
/**
* Tracks the current position within an array of arguments.
*
* This variable is used to index into the arguments array, enabling
* sequential access to command-line tokens. It is incremented as arguments
* are processed or retrieved using methods such as {@code next()} or {@code peek()}
* in the {@link ArgumentProvider} class.
*
* Its value starts at 0 and increases until it reaches the length of
* the provided arguments array, at which point iteration ends.
*/
private int current = 0;
/**
* Creates an instance of the ArgumentProvider class to iterate over the given array of arguments.
* If the provided array is null, it initializes the arguments with an empty array.
*
* @param arguments The array of command-line arguments to be iterated over.
* If null, it defaults to an empty array.
*/
public ArgumentProvider(final String[] arguments) {
if (arguments == null) {
this.arguments = new String[] {};
} else {
this.arguments = arguments;
}
}
/**
* Checks if there are more arguments available to iterate over.
*
* @return true if there are additional arguments available; false otherwise.
*/
public boolean hasNext() {
return current < arguments.length;
}
/**
* Determines if the specified number of additional arguments are available in the collection.
*
* @param count the number of additional arguments to check for availability
* @return true if there are at least the specified number of arguments available, otherwise false
*/
public boolean hasNext(final int count) {
return current + count <= arguments.length;
}
/**
* Retrieves the next argument in the sequence.
* If no more arguments are available, returns {@code null}.
*
* @return the next argument as a {@code String}, or {@code null} if no further arguments are available
*/
public String next() {
if (!hasNext()) return null;
String result = arguments[current];
current++;
return result;
}
/**
* Returns the next argument in the sequence without advancing the iterator.
* If there are no more arguments available, this method returns null.
*
* @return the next argument in the sequence or null if no arguments are available
*/
public String peek() {
if (!hasNext()) return null;
return arguments[current];
}
}

View File

@ -0,0 +1,192 @@
package de.neitzel.core.commandline;
import lombok.*;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.function.Consumer;
/**
* The `Parameter` class defines a command-line parameter with associated metadata,
* such as constraints on the number of values it accepts, descriptions, and aliases.
* It also allows specifying callbacks to handle parameter processing.
*
* This class is intended to be used as part of a command-line parser, enabling
* structured handling of arguments provided via the command line.
*/
@Slf4j
@Builder
@Getter
@Setter
public class Parameter {
/**
* Represents a command-line parameter definition within the application.
*
* This class encapsulates the metadata and configuration of a command-line parameter,
* including its name, aliases, descriptions, value constraints, and behavior. Instances
* of this class are used to define and manage the parameters that the `Parser` class
* recognizes and processes.
*
* A parameter can be configured as a default parameter or as a help command. The default
* parameter serves as a catch-all for unmatched command-line inputs, while the help
* command provides usage information for users.
*/
public Parameter() {
}
/**
* Constructs a new Parameter with the given attributes.
*
* @param name The name of the parameter.
* @param minNumberValues The minimum number of values allowed for this parameter.
* @param maxNumberValues The maximum number of values allowed for this parameter.
* @param multipleEntries Indicates whether multiple entries are allowed for this parameter.
* @param shortDescription A brief description of the parameter.
* @param longDescription A detailed description of the parameter.
* @param callback A consumer function that processes a list of values associated with this parameter.
* @param isHelpCommand Indicates whether this parameter represents a help command.
* @param isDefaultParameter Indicates whether this parameter is the default parameter.
* @param aliasList A list of aliases for this parameter.
*/
public Parameter(String name, int minNumberValues, int maxNumberValues, boolean multipleEntries, String shortDescription, String longDescription, Consumer<List<String>> callback, boolean isHelpCommand, boolean isDefaultParameter, List<String> aliasList) {
this.name = name;
this.minNumberValues = minNumberValues;
this.maxNumberValues = maxNumberValues;
this.multipleEntries = multipleEntries;
this.shortDescription = shortDescription;
this.longDescription = longDescription;
this.callback = callback;
this.isHelpCommand = isHelpCommand;
this.isDefaultParameter = isDefaultParameter;
this.aliasList = aliasList;
}
/**
* The `name` variable represents the primary identifier for a parameter.
* This string is used to uniquely identify a command-line parameter when parsing
* arguments. It serves as the key for registering and retrieving parameters in a
* command-line parser.
*
* The value of `name` is case-insensitive and can be used alongside aliases to
* recognize and process parameters provided in the command-line input.
*/
private String name;
/**
* Specifies the minimum number of values required for this parameter.
*
* This variable enforces a constraint on the number of arguments that must
* be provided for the parameter during command-line parsing. If the number of
* provided arguments is less than this value, an exception will be thrown during parsing.
*
* It is primarily used in validation logic within the command-line parser
* to ensure the required input is received for proper processing of the parameter.
*/
private int minNumberValues;
/**
* Specifies the maximum number of values that the corresponding parameter can accept.
*
* This field is used to validate and enforce constraints during command-line parsing.
* If more values than specified are provided for a parameter, the parser throws an exception
* to indicate a violation of this constraint.
*
* A value of 0 implies that the parameter does not support any values, while a positive
* value indicates the exact maximum limit of acceptable values.
*/
private int maxNumberValues;
/**
* Indicates whether the parameter allows multiple entries.
*
* If set to {@code true}, the parameter can be specified multiple times
* on the command-line. This allows the association of multiple values
* or options with the same parameter name.
*
* If set to {@code false}, the parameter can be specified only once
* during command-line parsing.
*/
private boolean multipleEntries;
/**
* A concise, human-readable description of the parameter's purpose and functionality.
*
* This description provides a brief summary to help users understand the
* essential role of the parameter within the command-line parser. It is typically
* displayed in usage instructions, help messages, or command summaries.
*/
private String shortDescription;
/**
* A detailed, extended description of the parameter's purpose and usage.
*
* This description provides deeper context about what the parameter represents,
* how it fits into the overall command-line application, and any nuances
* associated with its use. It is displayed when help or additional documentation
* for a specific parameter is requested.
*/
private String longDescription;
/**
* A callback function that processes a list of string arguments for a specific parameter.
* The callback is invoked during command-line parsing when a parameter is recognized,
* passing the associated values of the parameter for further processing.
*
* The provided {@link Consumer} implementation defines the logic to
* handle or validate the values supplied for a command-line parameter. The values
* passed are determined based on the parameter's configuration (e.g., minimum and
* maximum number of associated values).
*
* This field is typically set for the `Parameter` class to enable custom handling
* of parameter-specific logic, such as invoking a help command or performing
* business logic with the values parsed from the command-line arguments.
*/
private Consumer<List<String>> callback;
/**
* Indicates whether the parameter is designated as the help command.
*
* When set to {@code true}, this parameter is treated as the special help command
* within the command-line parser. A parameter marked as the help command typically
* provides users with information about available options or detailed descriptions
* of specific commands when invoked. If this flag is enabled, a custom callback
* method for displaying help context is automatically associated with the parameter.
*/
private boolean isHelpCommand;
/**
* Indicates whether the parameter is designated as the default parameter.
*
* The default parameter is a special type of parameter that can accept arguments
* without an explicit prefix or identifier. It is used when a provided command-line
* argument does not match any defined parameter and does not start with a special
* character (e.g., '-') typically used to denote named parameters.
*
* If this field is set to {@code true}, the parameter is treated as the default
* parameter. Only one parameter can be assigned this role within the parser.
* Attempting to assign multiple default parameters or a default parameter without
* accepting values (both `minNumberValues` and `maxNumberValues` set to 0) will
* result in an exception during configuration.
*
* This property is utilized during the parsing process to determine whether an
* unmatched argument should be handled as a default parameter value, simplifying
* the handling of positional arguments or other unnamed input data.
*/
private boolean isDefaultParameter;
/**
* A list of alias names associated with a parameter.
*
* This variable holds alternative names that can be used
* to reference the parameter in command-line input. Each alias
* functions as an equivalent to the primary parameter name.
* Aliases are case-insensitive when used within the command-line parser.
*
* The aliases associated with a parameter allow greater flexibility
* and user convenience when specifying parameters during command-line execution.
*/
@Singular("alias")
private List<String> aliasList;
}

View File

@ -0,0 +1,216 @@
package de.neitzel.core.commandline;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
/**
* The Parser class is responsible for parsing and handling command-line arguments.
* It allows for the registration of known parameters and provides mechanisms
* to validate and process command-line input.
*/
@Slf4j
public class Parser {
/**
* A map to store parameters where the key is a string representing
* the parameter name and the value is the corresponding {@link Parameter} object.
*
* This map serves as a registry for defining, organizing, and accessing
* command-line parameters. Each entry holds a parameter's metadata and
* its associated configuration to facilitate effective command-line parsing.
*
* Key considerations:
* - The key represents the primary name of the parameter.
* - The value, encapsulated as a {@link Parameter} object, includes
* details such as descriptions, value constraints, aliases, and processing logic.
*/
private Map<String, Parameter> parameters = new HashMap<>();
/**
* The `defaultParameter` variable represents the default command-line parameter for a parser.
*
* This parameter is used to capture arguments that do not explicitly match any named parameter
* or alias. It acts as a catch-all for unnamed command-line input, often simplifying the handling
* of positional arguments or other free-form input provided by the user.
*
* It is essential to note:
* - Only one parameter can be designated as the default parameter in a command-line parser.
* - The parameter must allow values to be processed (e.g., its `minNumberValues` or `maxNumberValues`
* should not disallow input).
* - This parameter is automatically invoked if an input does not match any explicitly named
* parameter or alias in the parser configuration.
*
* When set to `null`, the parser does not handle unmatched arguments, and unrecognized inputs
* may result in an error or exception, depending on the parser's implementation.
*/
private Parameter defaultParameter = null;
/**
* Constructs a new instance of the `Parser` class.
*
* The `Parser` class is responsible for parsing and processing
* command-line arguments. It interprets input data based on defined
* parameters and provides structured access to arguments, enabling
* streamlined application configuration and execution.
*
* This constructor initializes the parser without any predefined
* configuration or parameters. Users can define parameters,
* add handlers, and parse command-line arguments using available
* methods in the class.
*/
public Parser() {
}
/**
* Adds a new parameter to the internal parameter map. The method registers the parameter
* using its primary name and all specified aliases (case-insensitive). It also sets up
* specific behaviors for help and default parameters based on the parameter's configuration.
*
* @param parameter the Parameter object to be added. It contains the primary name, aliases,
* and other metadata such as whether it is a help command or default parameter.
* The parameter must fulfill specific constraints if defined as the default
* parameter (e.g., accepting values).
*
* @throws IllegalArgumentException if the parameter is defined as a default parameter and
* does not accept values (both minNumberValues and maxNumberValues
* are set to 0).
*/
public void addParameter(final Parameter parameter) {
// Add by name
parameters.put(parameter.getName().toLowerCase(), parameter);
// Add for all aliases
for (String alias: parameter.getAliasList()) {
parameters.put(alias.toLowerCase(), parameter);
}
// Set help Callback for help command.
if (parameter.isHelpCommand())
parameter.setCallback(this::helpCommandCallback);
if (parameter.isDefaultParameter()) {
if (parameter.getMinNumberValues() == 0 && parameter.getMaxNumberValues() == 0)
throw new IllegalArgumentException("Default Parameter must accept values!");
defaultParameter = parameter;
}
}
/**
* Checks whether a given parameter string matches a valid parameter within the defined constraints.
*
* @param param the parameter string to be checked. This can either be a key defined in the `parameters` map
* or a potential default parameter if it does not start with a dash ("-").
* @return {@code true} if the parameter is a valid entry in the `parameters` map or matches the default parameter;
* {@code false} otherwise, including when the parameter starts with a dash ("-").
*/
protected boolean isParameter(final String param) {
if (parameters.containsKey(param)) return true;
if (param.startsWith("-")) return false;
return defaultParameter != null;
}
/**
* Parses an array of command-line arguments and processes them as defined by the application's parameters.
*
* The method iteratively checks each argument in the provided array, validates it against
* the registered parameters, and invokes the corresponding processing callback if applicable.
* Unrecognized parameters or missing required values will result in an {@code IllegalArgumentException}.
*
* @param args the array of command-line arguments to be parsed and processed. Each element in this
* array represents a single input argument provided to the application. The format and
* content of the arguments are expected to conform to the application's parameter definitions.
*/
public void parse(final String[] args) {
ArgumentProvider provider = new ArgumentProvider(args);
while (provider.hasNext()) {
log.debug("Parsing argument: " + provider.peek());
// Peek to see the next parameter.
String next = provider.peek().toLowerCase();
if (!isParameter(next)) {
log.error("Unknown Parameter: " + next);
throw new IllegalArgumentException("Unknown argument: " + next);
}
Parameter parameter = parameters.get(next);
if (parameter == null) {
parameter = defaultParameter;
} else {
provider.next();
}
if (!provider.hasNext(parameter.getMinNumberValues())) {
String message = "Parameter " + next + " requires " + parameter.getMinNumberValues() + " more elements!";
log.error(message);
throw new IllegalArgumentException(message);
}
parameter.getCallback().accept(getOptions(provider, parameter.getMinNumberValues(), parameter.getMaxNumberValues()));
}
}
/**
* Retrieves a list of options by consuming arguments from the provided {@link ArgumentProvider}
* within the range specified by the minimum and maximum values.
*
* @param provider The source providing the command-line arguments. This object allows
* retrieving and examining argument strings in sequence.
* @param min The minimum number of arguments to be retrieved. If fewer arguments
* are available, no arguments will be added to the result.
* @param max The maximum number of arguments to be retrieved. If `max` is smaller
* than `min`, it will be adjusted to match `min`. Only up to `max`
* arguments will be added to the result.
* @return A list of argument strings, containing up to `max` elements and at least `min`
* elements if sufficient arguments are available. The list will not include
* arguments already recognized in the `parameters` map.
*/
private List<String> getOptions(ArgumentProvider provider, int min, int max) {
if (max < min) max = min;
List<String> result = new ArrayList<>();
int current = 0;
while (current < max && provider.hasNext()) {
if (current < min || !parameters.containsKey(provider.peek())) {
result.add(provider.next());
current++;
} else {
break;
}
}
return result;
}
/**
* Handles the help command when invoked in the command-line interface, providing information about available parameters.
* If no arguments are provided, it lists all possible parameters and their short descriptions.
* If specific arguments are supplied, it provides the detailed description of the corresponding parameter.
* In case an unknown parameter is specified, it indicates so to the user.
*
* @param arguments a list of strings representing the user-provided arguments. If empty or {@code null},
* the method lists all available parameters with their short descriptions. If a parameter name
* is provided in the list, its detailed information is displayed. If an unrecognized parameter
* is provided, a corresponding message is shown.
*/
public void helpCommandCallback(final List<String> arguments) {
if (arguments == null || arguments.size() == 0) {
System.out.println("Moegliche Parameter der Applikation:");
parameters.values().stream()
.distinct()
.sorted(Comparator.comparing(Parameter::getName))
.forEach(p -> System.out.println(p.getShortDescription() ));
} else {
Parameter parameter = null;
if (parameters.containsKey(arguments.get(0))) parameter = parameters.get(arguments.get(0));
if (parameters.containsKey("-" + arguments.get(0))) parameter = parameters.get("-" + arguments.get(0));
if (parameter == null) {
System.out.println("Unbekannter Parameter: " + arguments.get(0));
} else {
System.out.println(parameter.getLongDescription());
}
}
}
}

View File

@ -0,0 +1,268 @@
package de.neitzel.core.config;
import de.neitzel.core.util.FileUtils;
import de.neitzel.core.util.Strings;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.Properties;
/**
* Provides a utility class for managing configuration properties in an
* application. This class allows loading properties from files, accessing
* values with various types including environment variable substitution,
* and updating properties.
*/
@Slf4j
public class Configuration {
/**
* A {@link Properties} object that stores a set of key-value pairs.
* This variable can be used to manage configuration settings or other
* collections of properties within the application.
*
* It provides methods to load, retrieve, and modify properties
* as necessary for the application's requirements.
*/
private final Properties properties;
/**
* Constructs a new Configuration instance with default properties.
* This constructor initializes the Configuration object using an
* empty set of {@code Properties}.
*/
public Configuration() {
this(new Properties());
}
/**
* Constructs a new Configuration instance using the provided properties.
*
* @param properties the Properties object containing configuration key-value pairs
*/
public Configuration(Properties properties) {
this.properties = properties;
}
/**
* Retrieves a boolean property value associated with the specified key. If the key does not exist in the properties,
* the provided default value is returned. The method also supports interpreting specific string values as true.
*
* @param key the key used to retrieve the boolean property
* @param defaultValue the default value returned if the key is not found in the properties
* @return the boolean value associated with the key, or the defaultValue if the key does not exist
*/
protected boolean getBooleanProperty(final String key, final boolean defaultValue) {
if (!properties.containsKey(key)) return defaultValue;
return getStringProperty(key, defaultValue ? "ja": "nein").equalsIgnoreCase("ja") || properties.getProperty(key).equalsIgnoreCase("true");
}
/**
* Retrieves the value of the specified property as a trimmed string.
* If the property is not found, the default value is returned.
*
* @param key the key of the property to retrieve
* @param defaultValue the default value to return if the property is not found
* @return the trimmed string value of the property, or the default value if the property is not found
*/
protected String getStringProperty(final String key, final String defaultValue) {
if (!properties.containsKey(key)) return defaultValue;
return properties.getProperty(key).trim();
}
/**
* Retrieves a string property value associated with the specified key, applies
* environment variable expansion on the value, and returns the processed result.
*
* @param key the key identifying the property to retrieve.
* @param defaultValue the default value to use if the property is not found.
* @return the processed property value with expanded environment variables, or
* the defaultValue if the property is not found.
*/
protected String getStringPropertyWithEnv(final String key, final String defaultValue) {
String result = getStringProperty(key, defaultValue);
return Strings.expandEnvironmentVariables(result);
}
/**
* Retrieves the value of a string property associated with the specified key,
* removes any surrounding quotes from the value, and returns the resultant string.
*
* @param key the key associated with the desired property
* @param defaultValue the default value to return if the property is not found or is null
* @return the string property without surrounding quotes, or the defaultValue if the property is not found
*/
protected String getStringPropertyWithoutQuotes(final String key, final String defaultValue) {
return Strings.removeQuotes(getStringProperty(key, defaultValue));
}
/**
* Retrieves the string value of a configuration property identified by the given key,
* removes surrounding quotes if present, and expands any environment variables found
* within the string. If the property is not found, a default value is used.
*
* @param key the key identifying the configuration property
* @param defaultValue the default value to use if the property is not found
* @return the processed string property with quotes removed and environment variables expanded
*/
protected String getStringPropertyWithoutQuotesWithEnv(final String key, final String defaultValue) {
String result = getStringPropertyWithoutQuotes(key, defaultValue);
return Strings.expandEnvironmentVariables(result);
}
/**
* Retrieves the integer value for the specified property key. If the key does
* not exist in the properties or the value is null/empty, the provided default
* value is returned.
*
* @param key the property key to retrieve the value for
* @param defaultValue the default value to return if the key is not present
* or the value is null/empty
* @return the integer value associated with the key, or the defaultValue if
* the key does not exist or its value is null/empty
*/
protected Integer getIntegerProperty(final String key, final Integer defaultValue) {
if (!properties.containsKey(key)) return defaultValue;
String value = properties.getProperty(key);
return Strings.isNullOrEmpty(value) ? null : Integer.parseInt(value);
}
/**
* Sets an integer property in the properties object. If the provided value is null,
* an empty string will be stored as the property's value.
*
* @param key the key under which the property will be stored
* @param value the integer value to be stored; if null, an empty string will be used
*/
protected void setIntegerProperty(final String key, final Integer value) {
if (value == null) {
properties.setProperty(key, "");
} else {
properties.setProperty(key, ""+value);
}
}
/**
* Retrieves a LocalDate value from the properties based on the provided key.
* If the key does not exist or the value is invalid, a default value is returned.
*
* @param key the key to look up the property in the properties map
* @param defaultValue the default LocalDate value to return if the key is not found
* @param formatString the format string to parse the LocalDate value
* @return the LocalDate value from the properties if available and valid,
* otherwise the defaultValue
*/
protected LocalDate getLocalDateProperty(final String key, final LocalDate defaultValue, final String formatString) {
if (!properties.containsKey(key)) return defaultValue;
String value = properties.getProperty(key);
if (value == null || value.isEmpty()) return null;
return LocalDate.parse(value, DateTimeFormatter.ofPattern(formatString));
}
/**
* Sets a property with the given key and a formatted LocalDate value.
* If the provided value is null, the property will be set to an empty string.
*
* @param key the key of the property to set
* @param value the LocalDate value to format and set as the property value
* @param formatString the pattern string used to format the LocalDate value
*/
protected void setLocalDateProperty(final String key, final LocalDate value, final String formatString) {
if (value == null) {
setProperty(key, "");
} else {
setProperty(key, value.format(DateTimeFormatter.ofPattern(formatString)));
}
}
/**
* Sets a property with the specified key to the given value. If the value is null,
* it defaults to an empty string. Logs the operation and updates the property.
*
* @param key the key of the property to be set
* @param value the value to be associated with the specified key; defaults to an empty string if null
*/
public void setProperty(final String key, final String value) {
String newValue = value == null ? "" : value;
log.info("Setting a new value for '" + key + "': '" + newValue + "'");
properties.setProperty(key, newValue);
}
/**
* Loads the content of the specified file using the provided file name.
*
* @param fileName the name of the file to be loaded
*/
public void load(final String fileName) {
load(fileName, Charset.defaultCharset().name(), true);
}
/**
* Loads the configuration from a specified file. If the file does not exist in the
* specified location, it attempts to find the file alongside the JAR file of the application.
* Reads the configuration with the provided encoding and an option to accept UTF-8 encoding.
*
* @param fileName the name of the configuration file to be loaded
* @param encoding the encoding format to be used while reading the configuration file
* @param acceptUTF8 a boolean flag indicating whether to accept UTF-8 encoding
*/
public void load(final String fileName, final String encoding, final boolean acceptUTF8) {
log.info("Reading Config: " + fileName + " with encoding: " + encoding + "accepting UTF-8: " + acceptUTF8);
File configFile = new File(fileName);
// Try to get the file next to the jar file if the configFile does not exist.
if (!configFile.exists()) {
try {
String fileAtJar = new File(Configuration.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParent() + "/" + fileName;
configFile = new File(fileAtJar);
} catch (URISyntaxException ex) {
log.error("Unable to get path of jar file / class.", ex);
}
}
// Read the configuration file if it exists.
if (configFile.exists()) {
log.info("Reading Configuration file. " + configFile.getAbsolutePath());
try (InputStreamReader reader = FileUtils.createUniversalFileReader(configFile, encoding, acceptUTF8)) {
log.info("Reading the configuration with encoding: " + reader.getEncoding());
properties.load(reader);
} catch (FileNotFoundException fnfe) {
log.error("Configuration file: " + fileName + " not found!", fnfe);
} catch (IOException ioe) {
log.error("Cannot read config file.", ioe);
}
} else {
log.error("Unable to load config file! Last try: " + configFile.getAbsolutePath());
}
}
/**
* Merges the properties from the provided configuration into the current configuration.
*
* @param config the Configuration object whose properties will be merged into this instance
*/
public void merge(final Configuration config) {
for(Map.Entry<Object, Object> entry: config.properties.entrySet()) {
properties.put(entry.getKey(), entry.getValue());
}
}
/**
* Removes the specified key-value pair from the properties map if the key exists.
*
* @param key the key to be removed from the properties map
*/
public void remove(final String key){
if (properties.containsKey(key)) properties.remove(key);
}
}

View File

@ -0,0 +1,103 @@
package de.neitzel.core.io;
import de.neitzel.core.util.FileUtils;
import lombok.extern.slf4j.Slf4j;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
/**
* The ConvertedEncodingFileReader class extends {@link InputStreamReader} to provide functionality
* for handling file encoding conversion transparently. If a file is detected to be in UTF-8 encoding,
* this class converts it to the specified target encoding using a temporary file, then opens the reader
* with the converted encoding. If the file is already in the target encoding, it opens the reader directly.
*
* This class is useful for applications needing to process text files in specific encodings and ensures
* encoding compatibility.
*/
@Slf4j
public class ConvertedEncodingFileReader extends InputStreamReader {
/**
* The `checkEncoding` variable specifies the default encoding to be used
* when verifying file encodings within the `ConvertedEncodingFileReader` class.
* This encoding is primarily used to determine whether a file needs conversion
* to the target format or can be read directly in its existing format.
* The default value is set to "ISO-8859-15".
*
* Modifying this variable requires careful consideration, as it affects
* the behavior of methods that rely on encoding validation, particularly
* in the process of detecting UTF-8 files or converting them during file reading.
*/
private static String checkEncoding = "ISO-8859-15";
/**
* Sets the encoding that will be used to check the file encoding for compatibility.
* Throws an exception if the specified encoding is not valid or supported.
*
* @param encoding the name of the character encoding to set as the check encoding;
* it must be a valid and supported Charset.
* @throws IllegalCharsetNameException if the specified encoding is not valid or supported.
*/
private static void setCheckEncoding(final String encoding) {
if (Charset.forName(encoding) != null) throw new IllegalCharsetNameException("Encoding " + encoding + " is not supported!");
checkEncoding = encoding;
}
/**
* Constructs a ConvertedEncodingFileReader for a specified file and target encoding format.
* The class reads the provided file and ensures that its content is handled in the target encoding.
* If the file is not already in the target encoding, it converts the file's encoding
* transparently using a temporary file before reading it.
*
* @param file The file to be read. Must exist and be accessible.
* @param targetFormat The target character encoding format to which the file content should be converted.
* @throws IOException If the file does not exist, is inaccessible, or an error occurs during the encoding conversion process.
*/
public ConvertedEncodingFileReader(final File file, final String targetFormat) throws IOException {
super(createTargetFormatInputFileStream(file, targetFormat), targetFormat);
}
/**
* Constructs a ConvertedEncodingFileReader for reading a file with encoding conversion support.
* This constructor takes the file path as a string and ensures the file's encoding is either
* converted to the specified target format or read directly if it matches the target format.
*
* @param filename the path to the file to be read
* @param targetFormat the target encoding format to use for reading the file
* @throws IOException if an I/O error occurs while accessing or reading the specified file
*/
public ConvertedEncodingFileReader(final String filename, final String targetFormat) throws IOException {
this(new File(filename), targetFormat);
}
/**
* Creates an input file stream for a given file, converting its encoding if necessary.
* If the file is not in UTF-8 encoding, a direct {@link FileInputStream} is returned for the file.
* If the file is in UTF-8 encoding, it is converted to the specified target format using a temporary file,
* and then an input stream for the temporary file is returned.
*
* @param file the file for which the input stream is to be created
* @param targetFormat the desired target encoding format
* @return a {@link FileInputStream} for the file or a temporary file with converted encoding
* @throws IOException if the file does not exist or an error occurs during file operations
*/
private static FileInputStream createTargetFormatInputFileStream(final File file, final String targetFormat) throws IOException {
if (!file.exists()) {
String errorMessage = "File " + file.toString() + " does not exist!";
log.error(errorMessage);
throw new FileNotFoundException(errorMessage);
}
if (!FileUtils.isUTF8(file, checkEncoding)) {
return new FileInputStream(file);
} else {
File tempFile = File.createTempFile(file.getName(), "tmp");
FileUtils.convertTextFile(file, "UTF-8", tempFile, targetFormat);
tempFile.deleteOnExit();
return new FileInputStream(tempFile);
}
}
}

View File

@ -0,0 +1,46 @@
package de.neitzel.core.io;
import java.io.File;
import java.io.IOException;
/**
* The ISO8859EncodingFileReader class extends the ConvertedEncodingFileReader to provide
* file reading functionality with specific encoding support for ISO-8859-15.
* This class ensures that the file content is either read directly in the ISO-8859-15 encoding
* or converted transparently to this encoding if needed.
*/
public class ISO8859EncodingFileReader extends ConvertedEncodingFileReader {
/**
* Represents the target encoding format used by the ISO8859EncodingFileReader class.
* The TARGET_FORMAT is set to "ISO-8859-15", which specifies an encoding standard
* that is a variant of ISO-8859-1, adding the Euro symbol and other additional characters.
* This constant is used to indicate the desired character encoding for reading file content.
*/
private static final String TARGET_FORMAT = "ISO-8859-15";
/**
* Constructs an instance of ISO8859EncodingFileReader to read the provided file
* while ensuring the encoding is set to ISO-8859-15. If the file is not in the
* target encoding, this method transparently converts the file content to match
* the encoding before reading.
*
* @param file The file to be read. Must exist and be accessible.
* @throws IOException If the file does not exist, is inaccessible, or an error
* occurs during the encoding conversion process.
*/
public ISO8859EncodingFileReader(File file) throws IOException {
super(file, TARGET_FORMAT);
}
/**
* Constructs an ISO8859EncodingFileReader for reading a file with encoding conversion
* to the ISO-8859-15 format. This constructor accepts the file path as a string.
*
* @param filename the path to the file to be read
* @throws IOException if an I/O error occurs while accessing or reading the specified file
*/
public ISO8859EncodingFileReader(String filename) throws IOException {
super(filename, TARGET_FORMAT);
}
}

View File

@ -0,0 +1,96 @@
package de.neitzel.core.io;
/**
* Utility class for encoding and decoding strings.
* This class provides methods for transforming strings into encoded representations
* and decoding them back to the original representation.
*/
public class StringEncoder {
/**
* Private constructor to prevent instantiation of the utility class.
* This utility class is not meant to be instantiated, as it only provides
* static utility methods for array-related operations.
*
* @throws UnsupportedOperationException always, to indicate that this class
* should not be instantiated.
*/
private StringEncoder() {
throw new UnsupportedOperationException("Utility class");
}
/**
* Decodes a string containing encoded characters back to its original representation.
* Encoded characters are expected to be in the format {@code "&amp;#<code>;<code>"}, where
* {@code <code>} is a numeric representation of the character to decode.
*
* @param data the string to decode; may contain encoded characters or regular text. If null, an empty string is returned.
* @return the decoded string with all encoded characters replaced by their original representations.
* @throws IllegalArgumentException if the input string has encoding markup
* that is improperly formatted or incomplete.
*/
public static String decodeData(final String data) {
if (data == null) return "";
String remaining = data;
StringBuilder result = new StringBuilder();
while (!remaining.isEmpty()) {
int indexAmp = remaining.indexOf("&");
if (indexAmp == -1) {
result.append(remaining);
remaining="";
} else {
// First get the elements till the &
if (indexAmp > 0) {
result.append(remaining.substring(0, indexAmp));
remaining = remaining.substring(indexAmp);
}
int endSpecial=remaining.indexOf(";");
if (endSpecial == -1) throw new IllegalArgumentException("String couldn't be decoded! (" + data + ")");
String special = remaining.substring(0, endSpecial+1);
remaining = remaining.substring(endSpecial+1);
result.append(decodeCharacter(special));
}
}
return result.toString();
}
/**
* Decodes a character from its numeric character reference representation.
* The input string must represent an encoded character in the format {@code "&#<code_point>;"}.
*
* @param data the string containing the numeric character reference to decode.
* It must start with {@code "&#"} and end with {@code ";"}.
* @return the decoded character represented by the numeric character reference.
* @throws IllegalArgumentException if the input string does not follow the expected format.
*/
public static char decodeCharacter(final String data) {
if (!data.startsWith("&#")) throw new IllegalArgumentException("Data does not start with &# (" + data + ")");
if (!data.endsWith(";")) throw new IllegalArgumentException("Data does not end with ; (" + data + ")");
return (char)Integer.parseInt(data.substring(2, data.length()-1));
}
/**
* Encodes the provided string by converting characters outside the ASCII range (32-127)
* and the ampersand {@code "&"} character into their corresponding numeric character reference
* representation (e.g., {@code "&#38;"}).
*
* @param data the input string to encode; if null, an empty string is returned
* @return an encoded string where non-ASCII and ampersand characters
* are replaced with numeric character references
*/
public static String encodeData(final String data) {
if (data == null) return "";
StringBuilder result = new StringBuilder();
for (int index=0; index < data.length(); index++) {
char character = data.charAt(index);
if (character < 32 || character > 127 || character == 38) {
result.append("&#" + (int)character + ";");
} else {
result.append(character);
}
}
return result.toString();
}
}

View File

@ -10,6 +10,18 @@ import javax.sound.sampled.SourceDataLine;
* It allows playing tones based on frequency or predefined tone names.
*/
public class ToneGenerator {
/**
* Private constructor to prevent instantiation of the utility class.
* This utility class is not meant to be instantiated, as it only provides
* static utility methods for array-related operations.
*
* @throws UnsupportedOperationException always, to indicate that this class
* should not be instantiated.
*/
private ToneGenerator() {
throw new UnsupportedOperationException("Utility class");
}
/**
* Plays a tone based on a predefined tone name for a specified duration.
*

View File

@ -13,6 +13,18 @@ import java.util.HashMap;
* frequency information for specific tones.
*/
public class ToneTable {
/**
* Private constructor to prevent instantiation of the utility class.
* This utility class is not meant to be instantiated, as it only provides
* static utility methods for array-related operations.
*
* @throws UnsupportedOperationException always, to indicate that this class
* should not be instantiated.
*/
private ToneTable() {
throw new UnsupportedOperationException("Utility class");
}
/**
* A static map that associates written tone names with their corresponding frequencies in hertz (Hz).
* The keys represent tone names (e.g., "C4", "D#5"), and the values are their respective frequencies.

View File

@ -22,7 +22,6 @@ import java.util.stream.StreamSupport;
* @param <T> The type of the objects returned by the query.
*/
@Slf4j
@RequiredArgsConstructor
public class Query<T> {
/**
@ -69,6 +68,15 @@ public class Query<T> {
*/
private String queryText;
/**
* Constructs a new Query object with the given database connection.
*
* @param connection The Connection object used to interact with the database.
*/
public Query(Connection connection) {
this.connection = connection;
}
/**
* Executes the given SQL query using the provided database connection.
*

View File

@ -18,7 +18,6 @@ import java.util.Map;
* If any additional behaviors or transformations are applied, they are documented
* in the respective overridden method descriptions.
*/
@RequiredArgsConstructor
public class TrimmingResultSet implements ResultSet {
/**
@ -31,7 +30,16 @@ public class TrimmingResultSet implements ResultSet {
* SQL query execution lifecycle.
*/
private final ResultSet resultSet;
/**
* Initializes a new instance of the TrimmingResultSet class, wrapping the provided ResultSet.
*
* @param resultSet the ResultSet to be wrapped and processed by this TrimmingResultSet instance
*/
public TrimmingResultSet(ResultSet resultSet) {
this.resultSet = resultSet;
}
/**
* Retrieves the string value from the specified column index of the current row in the ResultSet.
* The value is trimmed to remove leading and trailing whitespace. If the value is null, it returns null.

View File

@ -0,0 +1,78 @@
package de.neitzel.core.util;
import java.util.Objects;
/**
* Utility class providing helper methods for working with arrays.
*/
public class ArrayUtils {
/**
* Private constructor to prevent instantiation of the utility class.
* This utility class is not meant to be instantiated, as it only provides
* static utility methods for array-related operations.
*
* @throws UnsupportedOperationException always, to indicate that this class
* should not be instantiated.
*/
private ArrayUtils() {
throw new UnsupportedOperationException("Utility class");
}
/**
* Checks if the given character array contains the specified character.
*
* @param array the character array to be searched
* @param ch the character to search for in the array
* @return true if the character is found in the array, false otherwise
*/
public static boolean contains(char[] array, char ch) {
for(int index=0; index < array.length; index++) {
if (array[index] == ch) return true;
}
return false;
}
/**
* Checks if the specified integer array contains the given integer value.
*
* @param array the array of integers to search
* @param ch the integer value to search for in the array
* @return true if the array contains the specified integer value, false otherwise
*/
public static boolean contains(int[] array, int ch) {
for(int index=0; index < array.length; index++) {
if (array[index] == ch) return true;
}
return false;
}
/**
* Checks if the specified long array contains the given long value.
*
* @param array the array of long values to search
* @param ch the long value to search for in the array
* @return true if the array contains the specified long value, false otherwise
*/
public static boolean contains(long[] array, long ch) {
for(int index=0; index < array.length; index++) {
if (array[index] == ch) return true;
}
return false;
}
/**
* Checks if the specified array contains the given element.
*
* @param array the array to be searched
* @param ch the element to search for in the array
* @param <T> the type of the elements in the array
* @return true if the element is found in the array, false otherwise
*/
public static <T> boolean contains(T[] array, T ch) {
for(int index=0; index < array.length; index++) {
if (Objects.equals(array[index], ch)) return true;
}
return false;
}
}

View File

@ -0,0 +1,79 @@
package de.neitzel.core.util;
import java.util.ArrayList;
import java.util.List;
/**
* Utility class for working with Enum types, providing methods to parse and generate
* patterns for Enum flags.
*/
public class EnumUtil {
/**
* Private constructor to prevent instantiation of the utility class.
* This utility class is not meant to be instantiated, as it only provides
* static utility methods for array-related operations.
*
* @throws UnsupportedOperationException always, to indicate that this class
* should not be instantiated.
*/
private EnumUtil() {
throw new UnsupportedOperationException("Utility class");
}
/**
* Generates a regular expression pattern that matches all possible case-insensitive representations
* of the enum constants within the specified Enum class. The pattern also includes optional delimiters
* such as commas, spaces, and empty values, enabling the matching of lists or sequences of flag values.
*
* @param <T> The type of the Enum.
* @param clazz The Enum class for which the regular expression is to be generated.
* @return A String containing the regular expression pattern for matching the Enum's flag values.
*/
public static <T extends Enum<T>> String getFlagRegEx(Class<T> clazz) {
StringBuilder result = new StringBuilder();
result.append("(|,|\\s");
for (T flag: clazz.getEnumConstants()) {
result.append("|");
for(char ch: flag.toString().toUpperCase().toCharArray()) {
if (Character.isAlphabetic(ch)) {
result.append("[");
result.append(ch);
result.append(Character.toLowerCase(ch));
result.append("]");
} else {
result.append(ch);
}
}
}
result.append(")*");
return result.toString();
}
/**
* Parses a delimited string containing Enum constant names into a list of Enum constants.
*
* This method takes an Enum class and a string of flags, splits the string by commas
* or whitespace, and converts each substring into an Enum constant of the given class.
* The flag names are case-insensitive and will be converted to uppercase before matching
* to the Enum constants.
*
* @param <T> The type of the Enum.
* @param clazz The Enum class to which the flags should be parsed.
* @param flags A string containing the delimited list of flag names to parse.
* Individual names can be separated by commas or whitespace.
* @return A list of Enum constants parsed from the input string. If the input string
* is null or empty, an empty list is returned.
* @throws IllegalArgumentException if any of the flag names do not match the constants in the given Enum class.
* @throws NullPointerException if the clazz parameter is null.
*/
public static <T extends Enum<T>> List<T> parseFlags(final Class<T> clazz, final String flags) {
List<T> result = new ArrayList<>();
if (flags != null) {
for (String flag: flags.split("[,\\s]")) {
if (!flag.isEmpty()) result.add(T.valueOf(clazz, flag.toUpperCase()));
}
}
return result;
}
}

View File

@ -0,0 +1,298 @@
package de.neitzel.core.util;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.stream.Collectors;
/**
* Utility class for handling file operations, such as encoding checks, content reading/writing,
* path manipulations, and file conversions.
*/
@Slf4j
public class FileUtils {
/**
* Private constructor to prevent instantiation of the utility class.
* This utility class is not meant to be instantiated, as it only provides
* static utility methods for array-related operations.
*
* @throws UnsupportedOperationException always, to indicate that this class
* should not be instantiated.
*/
private FileUtils() {
throw new UnsupportedOperationException("Utility class");
}
/**
* Defines a standardized timestamp format for debugging purposes, specifically used for naming
* or identifying files with precise timestamps. The format is "yyyy-MM-dd_HH_mm_ss_SSS", which
* includes:
* - Year in four digits (yyyy)
* - Month in two digits (MM)
* - Day of the month in two digits (dd)
* - Hour in 24-hour format with two digits (HH)
* - Minutes in two digits (mm)
* - Seconds in two digits (ss)
* - Milliseconds in three digits (SSS)
*
* This ensures timestamps are sortable and easily identifiable.
*/
public static final SimpleDateFormat DEBUG_FILE_TIMESTAMP_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH_mm_ss_SSS");
/**
* Default encoding used for string checks and validations in the application.
*
* This constant represents the `ISO-8859-15` encoding, which is a standardized
* character set encoding, commonly used in contexts where backward compatibility
* with `ISO-8859-1` is required, but with support for certain additional characters,
* such as the euro currency symbol ().
*/
public static final String DEFAULT_CHECK_ENCODING = "ISO-8859-15";
/**
* Specifies the default buffer size used for data processing operations.
*
* This constant represents the size of the buffer in bytes, set to 1024,
* and is typically utilized in input/output operations to optimize performance
* by reducing the number of read/write calls.
*/
public static final int BUFFER_SIZE = 1024;
/**
* Determines whether the given file is encoded in UTF-8.
*
* @param file The file to be checked for UTF-8 encoding.
* @param checkEncoding The character encoding to use while checking the file content.
* @return true if the file is determined to be encoded in UTF-8; false otherwise.
* @throws IOException If an I/O error occurs while reading the file.
*/
public static boolean isUTF8(final File file, final String checkEncoding) throws IOException {
if (hasUTF8BOM(file)) return true;
int BUFFER_SIZE = 1024;
char[] buffer = new char[BUFFER_SIZE];
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(file), checkEncoding)) {
while (reader.read(buffer, 0, BUFFER_SIZE) > 0) {
if (
(ArrayUtils.contains(buffer, (char) 0x00C2)) // Part of UTF-8 Characters 0xC2 0xZZ
|| (ArrayUtils.contains(buffer, (char) 0x00C3))) { // Part of UTF-8 Characters 0xC3 0xZZ
return true;
}
}
return false;
} catch (IOException ex) {
log.error("Exception while reading file.", ex);
throw ex;
}
}
/**
* Checks if the provided file starts with a UTF-8 Byte Order Mark (BOM).
*
* This method reads the first character of the file using a reader that assumes
* UTF-8 encoding and checks if it matches the Unicode Byte Order Mark (U+FEFF).
*
* @param file The file to check for a UTF-8 BOM. Must not be null.
* @return true if the file starts with a UTF-8 BOM, false otherwise.
* @throws IOException If an input or output exception occurs while reading the file.
*/
public static boolean hasUTF8BOM(final File file) throws IOException {
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)) {
return reader.read() == 0xFEFF;
} catch (IOException ex) {
log.error("Exception while reading file.", ex);
throw ex;
}
}
/**
* Determines if the content of the given file is encoded in UTF-8.
*
* @param file The file to check for UTF-8 encoding. Must not be null.
* @return true if the file content is in UTF-8 encoding; false otherwise.
* @throws IOException If an I/O error occurs while reading the file.
*/
public static boolean isUTF8(final File file) throws IOException {
return isUTF8(file, DEFAULT_CHECK_ENCODING);
}
/**
* Converts the content of a text file from one character encoding format to another.
*
* This method reads the input text file using the specified source encoding and writes
* the content to the output text file in the specified target encoding.
*
* @param inFile The input text file to be converted. Must not be null.
* @param sourceFormat The character encoding of the input file. Must not be null or empty.
* @param outFile The output text file to write the converted content to. Must not be null.
* @param targetFormat The character encoding to be used for the output file. Must not be null or empty.
* @throws IOException If an I/O error occurs during reading or writing.
*/
public static void convertTextFile(final File inFile, final String sourceFormat, final File outFile, final String targetFormat) throws IOException {
char[] buffer = new char[BUFFER_SIZE];
int charsRead, startIndex;
boolean first = true;
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(inFile), sourceFormat);
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(outFile), targetFormat)) {
while ((charsRead = reader.read(buffer, 0, BUFFER_SIZE)) > 0) {
startIndex = 0;
if (first) {
// Check UTF-8 BOM
if (buffer[0] == 0xFEFF) {
log.info("BOM found!");
startIndex = 1;
}
first = false;
}
writer.write(buffer, startIndex, charsRead - startIndex);
}
} catch (IOException ex) {
log.error("Exception when converting Textfile.", ex);
throw ex;
}
}
/**
* Creates a universal file reader for the specified file name.
* This method initializes and returns an InputStreamReader to read
* the content of the given file.
*
* @param filename The name or path of the file to be read.
* @return An InputStreamReader for reading the specified file.
* @throws IOException If an I/O error occurs while creating the file reader.
*/
public static InputStreamReader createUniversalFileReader(final String filename) throws IOException {
return createUniversalFileReader(new File(filename));
}
/**
* Creates a universal file reader for the specified file and format.
* The method resolves the file using its name and the expected format,
* returning an InputStreamReader for reading the file contents.
*
* @param filename the name of the file to be read.
* @param expectedFormat the format expected for the file content.
* @return an InputStreamReader for the specified file and format.
* @throws IOException if an I/O error occurs while opening or reading the file.
*/
public static InputStreamReader createUniversalFileReader(final String filename, final String expectedFormat) throws IOException {
return createUniversalFileReader(new File(filename), expectedFormat);
}
/**
* Creates a universal file reader for the specified file using the default encoding and configuration.
*
* @param file The file to be read. Must not be null.
* @return An InputStreamReader configured to read the specified file.
* @throws IOException If an I/O error occurs while creating the reader.
*/
public static InputStreamReader createUniversalFileReader(final File file) throws IOException {
return createUniversalFileReader(file, DEFAULT_CHECK_ENCODING, true);
}
/**
* Creates a universal file reader for the specified file with an expected format.
* This method wraps the given file in an InputStreamReader for consistent character stream manipulation.
*
* @param file The file to be read. Must not be null.
* @param expectedFormat The expected format of the file (e.g., encoding). Must not be null.
* @return An InputStreamReader for the specified file, allowing the caller to read the file
* with the desired format applied.
* @throws IOException If an I/O error occurs during the creation of the reader.
*/
public static InputStreamReader createUniversalFileReader(final File file, final String expectedFormat) throws IOException {
return createUniversalFileReader(file, expectedFormat, true);
}
/**
* Creates an InputStreamReader for reading a file, considering the specified encoding format
* and whether UTF-8 should be accepted. Handles potential BOM for UTF-8 encoded files.
*
* @param file The file to be read.
* @param expectedFormat The expected encoding format of the file.
* @param acceptUTF8 Indicates whether UTF-8 encoding should be accepted if detected.
* @return An InputStreamReader for the specified file and encoding.
* @throws IOException If there is an error accessing the file or reading its content.
*/
public static InputStreamReader createUniversalFileReader(final File file, final String expectedFormat, final boolean acceptUTF8) throws IOException {
String encoding = acceptUTF8 && isUTF8(file, expectedFormat)
? "UTF-8"
: expectedFormat;
boolean skipBOM = encoding.equals("UTF-8") && hasUTF8BOM(file);
InputStreamReader result = new InputStreamReader(new FileInputStream(file), encoding);
if (skipBOM) {
int BOM = result.read();
if (BOM != 0xFEFF) log.error ("Skipping BOM but value not 0xFEFF!");
}
return result;
}
/**
* Retrieves the parent directory of the given file or directory path.
*
* If the given path does not have a parent directory, it defaults to returning the
* current directory represented by ".".
*
* @param filename The file or directory path for which the parent directory is to be retrieved.
* @return The parent directory of the given path, or "." if no parent directory exists.
*/
public static String getParentDirectory(final String filename) {
File file = new File(filename);
return file.getParent() != null ? file.getParent() : ".";
}
/**
* Extracts the name of a file from the given file path.
*
* @param filename The full path or name of the file. Must not be null.
* @return The name of the file without any directory path.
*/
public static String getFilename(final String filename) {
File file = new File(filename);
return file.getName();
}
/**
* Reads the content of a file and returns it as a string, joining all lines with the system line separator.
*
* @param filename The name of the file to be read.
* @return A string containing the content of the file with all lines joined by the system line separator.
* @throws IOException If an I/O error occurs while reading the file.
*/
public static String readFileContent(final String filename) throws IOException {
try (BufferedReader reader = new BufferedReader(createUniversalFileReader(filename))) {
return reader.lines().collect(Collectors.joining(System.lineSeparator()));
}
}
/**
* Writes the given content to the specified file path. If the file already exists, it will be overwritten.
*
* @param path The path of the file to write to. Must not be null and must be writable.
* @param content The content to be written to the file. Must not be null.
* @throws IOException If an I/O error occurs during writing to the file.
*/
public static void writeFile(final Path path, final String content) throws IOException {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(path.toFile()))) {
writer.write(content);
}
}
}

View File

@ -0,0 +1,90 @@
package de.neitzel.core.util;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;
/**
* The RegionalizationMessage class provides functionality to retrieve
* localized messages from a resource bundle and format messages with parameters.
* It supports multiple constructors for initializing with specific locales if needed.
*/
public class RegionalizationMessage {
/**
* The `res` variable holds a `ResourceBundle` instance,
* which is used to retrieve locale-specific objects and messages.
* It facilitates the process of internationalization by loading resources
* such as text and messages from specified bundles based on the provided locale.
*
* This variable is initialized in constructors of the `RegionalizationMessage` class
* and is used internally by various methods to fetch localized messages.
*/
private ResourceBundle res;
/**
* Constructs a new RegionalizationMessage instance using the specified resource bundle source.
* This constructor initializes the resource bundle with the given source name.
*
* @param source The base name of the resource bundle to load.
* This is typically a fully qualified class name or package name for the resource.
*/
public RegionalizationMessage(final String source) {
res = ResourceBundle.getBundle(source);
}
/**
* Constructs a RegionalizationMessage object to retrieve localized messages
* from a specified resource bundle using the given source and locale.
*
* @param source The base name of the resource bundle, a fully qualified class name.
* @param locale The Locale object specifying the desired language and region for localization.
*/
public RegionalizationMessage(final String source, final Locale locale) {
res = ResourceBundle.getBundle(source, locale);
}
/**
* Retrieves the localized message corresponding to the specified key from the resource bundle.
* If the key does not exist in the resource bundle, this method returns null.
*
* @param key The key for which the localized message needs to be retrieved.
* @return The localized message as a String if the key exists in the resource bundle;
* otherwise, null.
*/
public String getMessage(final String key) {
if (!res.containsKey(key)) return null;
return res.getString(key);
}
/**
* Retrieves a localized message for the given key from the resource bundle.
* If the key is not found, the specified default message is returned.
*
* @param key The key to look up in the resource bundle.
* @param defaultMessage The default message to return if the key is not found.
* @return The localized message corresponding to the key, or the default message
* if the key does not exist in the resource bundle.
*/
public String getMessage(final String key, final String defaultMessage) {
if (res.containsKey(key))
return res.getString(key);
return defaultMessage;
}
/**
* Retrieves a localized and formatted message from a resource bundle based on a key.
* If the key is not found in the resource bundle, a default message is used.
* The message supports parameter substitution using the supplied arguments.
*
* @param key The key used to retrieve the localized message from the resource bundle.
* @param defaultMessage The default message to be used if the key is not found in the resource bundle.
* @param params The parameters to substitute into the message placeholders.
* @return A formatted string containing the localized message with substituted parameters.
*/
public String getFormattedMessage(final String key, final String defaultMessage, final Object... params) {
MessageFormat format = new MessageFormat(getMessage(key, defaultMessage));
return format.format(params);
}
}

View File

@ -0,0 +1,157 @@
package de.neitzel.core.util;
import lombok.NonNull;
import java.util.Map;
/**
* Utility class providing common string manipulation methods.
*/
public class Strings {
/**
* Private constructor to prevent instantiation of the utility class.
* This utility class is not meant to be instantiated, as it only provides
* static utility methods for array-related operations.
*
* @throws UnsupportedOperationException always, to indicate that this class
* should not be instantiated.
*/
private Strings() {
throw new UnsupportedOperationException("Utility class");
}
/**
* A map that holds the system's environment variables. The keys represent
* environment variable names, and the values represent their corresponding
* values. It is initialized with the current system environment variables using
* {@link System#getenv()}.
*
* This variable provides access to the underlying system environment, which can
* be used for various purposes such as configuration, path resolution, or
* dynamic value substitution.
*
* Note: Modifications to this map will not affect the system environment, as it
* is a copy of the environment at the time of initialization.
*/
private static Map<String, String> environmentVariables = System.getenv();
/**
* Expands environment variable placeholders within the provided text.
* Placeholders in the format ${VARIABLE_NAME} are replaced with their
* corresponding values from the environment variables.
*
* @param text The input string containing environment variable placeholders.
* If null, the method returns null.
* @return A string with the placeholders replaced by their corresponding
* environment variable values. If no placeholders are found,
* the original string is returned.
*/
public static String expandEnvironmentVariables(String text) {
if (text == null) return null;
for (Map.Entry<String, String> entry : environmentVariables.entrySet()) {
String key = entry.getKey();
String value = entry.getValue().replace('\\', '/');
text = text.replaceAll("\\$\\{" + key + "\\}", value);
}
return text;
}
/**
* Checks whether a given string is either null or empty.
*
* @param string the string to be checked for nullity or emptiness.
* @return true if the string is null or has a length of 0; false otherwise.
*/
public static boolean isNullOrEmpty(final String string) {
return (string == null || string.length()==0);
}
/**
* Removes surrounding double quotes from the input string if they are present.
* Trims leading and trailing whitespaces from the input before processing.
*
* @param value The input string that might contain surrounding double quotes.
* The input cannot be null, and leading/trailing whitespaces will be ignored.
* @return A string with leading and trailing double quotes removed if present.
* Returns the original string if no surrounding double quotes are detected.
*/
public static String removeQuotes(final String value) {
String trimmedValue = value.trim();
if (trimmedValue.length() > 1 && trimmedValue.startsWith("\"") && trimmedValue.endsWith("\""))
return trimmedValue.substring(1, trimmedValue.length()-1);
return value;
}
/**
* Replaces illegal characters in a given string with a specified replacement string.
* Optionally, consecutive illegal characters can be combined into a single replacement.
*
* @param value The input string in which illegal characters are to be replaced.
* @param illegalCharacters A string specifying the set of illegal characters to be matched.
* @param replacement The string to replace each illegal character or group of characters.
* @param combine A boolean flag indicating whether consecutive illegal characters should be replaced
* with a single replacement string. If true, groups of illegal characters are combined.
* @return A new string with the illegal characters replaced by the provided replacement string.
*/
public static String replaceIllegalCharacters(final String value, final String illegalCharacters, final String replacement, final boolean combine) {
String replacementRegex = "[" + illegalCharacters + "]" + (combine ? "+" : "");
return value.replaceAll(replacementRegex, replacement);
}
/**
* Replaces characters in the input string that are not in the allowed characters set
* with a specified replacement string. Optionally combines consecutive non-allowed
* characters into a single replacement.
*
* @param value The input string to be processed.
* @param allowedCharacters A string containing the set of characters that are allowed.
* Any character not in this set will be replaced.
* @param replacement The string to replace non-allowed characters with.
* @param combine If true, consecutive non-allowed characters will be replaced with
* a single instance of the replacement string.
* @return A new string with non-allowed characters replaced according to the specified rules.
*/
public static String replaceNonAllowedCharacters(final String value, final String allowedCharacters, final String replacement, final boolean combine) {
String replacementRegex = "[^" + allowedCharacters + "]" + (combine ? "+" : "");
return value.replaceAll(replacementRegex, replacement);
}
/**
* Increments a string value by modifying its last character, or leading characters if necessary.
* The increment follows these rules:
* - If the last character is a digit '9', it wraps to 'A'.
* - If the last character is 'Z', the preceding part of the string is recursively incremented, and '0' is appended.
* - If the string is empty, it returns "1".
* - For all other characters, increments the last character by one.
*
* @param element The string whose value is to be incremented. Must not be null.
* @return The incremented string value. If the input string is empty, returns "1".
*/
public static String increment(@NonNull final String element) {
if (element.isEmpty()) return "1";
String firstPart = element.substring(0, element.length()-1);
char lastChar = element.charAt(element.length()-1);
if (lastChar == '9') return firstPart + 'A';
if (lastChar == 'Z') return increment(firstPart) + '0';
return firstPart + (char)(lastChar+1);
}
/**
* Trims the input string to a specified maximum length, if necessary.
* If the input string's length is less than or equal to the specified max length,
* the string is returned unchanged. If the input string's length exceeds the max
* length, it is truncated to that length.
*
* @param original The original input string to be processed. If null, the method returns null.
* @param maxLength The maximum number of characters allowed in the resulting string.
* @return The original string if its length is less than or equal to maxLength,
* otherwise a truncated version of the string up to maxLength characters.
*/
public static String limitCharNumber(final String original, final int maxLength) {
if (original == null || original.length() <= maxLength) return original;
return original.substring(0, maxLength);
}
}

View File

@ -0,0 +1,239 @@
package de.neitzel.core.util;
import lombok.NonNull;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.time.format.DateTimeFormatter;
import java.util.Date;
/**
* Utility class for handling common XML operations such as creating XML elements,
* formatting XML strings, and validating XML content.
*/
@Slf4j
public class XmlUtils {
/**
* Private constructor to prevent instantiation of the utility class.
* This utility class is not meant to be instantiated, as it only provides
* static utility methods for array-related operations.
*
* @throws UnsupportedOperationException always, to indicate that this class
* should not be instantiated.
*/
private XmlUtils() {
throw new UnsupportedOperationException("Utility class");
}
/**
* A {@link DateTimeFormatter} instance used for formatting or parsing dates in the "yyyy-MM-dd" pattern.
*
* This formatter adheres to the XML date format standard (ISO-8601). It can be used
* to ensure consistent date representations in XML or other similar text-based formats.
*
* Thread-safe and immutable, this formatter can be shared across multiple threads.
*/
public static final DateTimeFormatter XML_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
/**
* Creates a new element in the provided XML document with the specified name.
*
* @param doc The XML document in which the new element is to be created. Must not be null.
* @param name The name of the element to be created. Must not be null or empty.
* @return The newly created element with the given name. Never returns null.
*/
public static Element createElement(final Document doc, final String name) {
log.debug("Creating a new element " + name);
return doc.createElement(name);
}
/**
* Creates a new XML element with the specified name and value, appends the value
* as a text node to the element, and returns the resulting element.
*
* @param doc the XML document to which the element belongs. Must not be null.
* @param name the name of the element to create. Must not be null.
* @param value the text value to be set as the content of the created element.
* If null, an empty string will be used as the content.
* @return the newly created XML element containing the specified value as a text node.
*/
public static Element createElement(final Document doc, final String name, final String value) {
log.debug("Creating a new element " + name + " with value: " + value);
Element element = doc.createElement(name);
Node content = doc.createTextNode(value != null ? value : "");
element.appendChild(content);
return element;
}
/**
* Creates an XML element with the specified name and value, formatted as a date string.
* The date value is converted to an XML-compatible string format using a predefined formatter.
*
* @param doc the XML document to which the element belongs; must not be null
* @param name the name of the element to be created; must not be null or empty
* @param value the date value to be assigned to the created element; must not be null
* @return the created XML element containing the specified name and formatted date value
*/
public static Element createElement(final Document doc, final String name, final Date value) {
return createElement(doc, name, XML_DATE_FORMATTER.format(value.toInstant()));
}
/**
* Creates an XML element with the specified name and optional value.
*
* @param doc The Document object to which the element will belong. Must not be null.
* @param name The name of the element to be created. Must not be null or empty.
* @param value The optional value to be set as the text content of the element. If null,
* the element will have an empty text content.
* @return The newly created Element object with the specified name and value.
*/
public static Element createElement(final Document doc, final String name, final Integer value) {
log.debug("Creating a new element " + name + " with value: " + value);
Element element = doc.createElement(name);
Node content = doc.createTextNode(value != null ? ""+value : "");
element.appendChild(content);
return element;
}
/**
* Creates a new element with the specified name, appends it to the provided parent element,
* and returns the newly created element.
*
* @param doc The Document to which the new element belongs. Must not be null.
* @param name The name of the new element to be created. Must not be null or empty.
* @param parent The parent element to which the new element will be appended. Must not be null.
* @return The newly created and appended Element object.
*/
public static Element createAndInsertElement(final Document doc, final String name, @NonNull final Element parent) {
log.debug("Creating a new element " + name + " and adding it to a parent.");
Element element = createElement(doc, name);
parent.appendChild(element);
return element;
}
/**
* Creates a new XML element with a specified name and value, adds it to the specified parent element,
* and returns the created element.
*
* @param doc The XML document to which the new element belongs. Must not be null.
* @param name The name of the element to create. Must not be null.
* @param value The value to be set for the created element. Can be null if no value is required.
* @param parent The parent element to which the new element will be appended. Must not be null.
* @return The newly created and inserted element.
*/
public static Element createAndInsertElement(final Document doc, final String name, final String value, @NonNull final Element parent) {
log.debug("Creating a new element " + name + " with value: " + value + " and adding it to a parent.");
Element element = createElement(doc, name, value);
parent.appendChild(element);
return element;
}
/**
* Formats a given XML string by applying proper indentation to enhance readability.
* The method uses a transformer to process the XML input, applying indentation
* with a four-space configuration. In case of an error, the original XML string
* is returned without any modifications.
*
* @param xmlStream The raw XML string to be formatted. Cannot be null.
* @return The formatted XML string with proper indentation. If an exception occurs
* during formatting, the original XML string is returned.
*/
public static String format(final String xmlStream) {
log.debug("formatXML");
try {
Source xmlInput = new StreamSource(new StringReader(xmlStream));
StringWriter stringWriter = new StringWriter();
StreamResult xmlOutput = new StreamResult(stringWriter);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
transformerFactory.setAttribute("indent-number", "4");
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(xmlInput, xmlOutput);
return xmlOutput.getWriter().toString();
}
catch(TransformerException e) {
log.error("Error in XML: " + e.getMessage() + "\n"+xmlStream, e);
}
return xmlStream;
}
/**
* Formats a given XML Document into a human-readable string representation.
* The method applies indentation and specific output properties to the XML content.
* If an exception occurs during the transformation process, it logs the error
* and returns null.
*
* @param doc The XML Document to be formatted. Must not be null.
* @return A formatted string representation of the XML document, or null if an error occurs during processing.
*/
public static String format(final Document doc) {
try {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
transformerFactory.setAttribute("indent-number", "4");
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
StringWriter stringWriter = new StringWriter();
Source source = new DOMSource(doc);
Result result = new StreamResult(stringWriter);
transformer.transform(source, result);
String xmlString = stringWriter.toString();
log.info("MO Request: " + xmlString);
return xmlString;
}
catch(TransformerException e) {
log.error("Error in XML Transformation: " + e.getMessage(), e);
}
return null;
}
/**
* Validates whether a given XML string is well-formed.
* This method attempts to parse the input XML string and checks
* if it can successfully create a valid DOM object from it.
*
* @param xml The XML string to be validated. Must not be null.
* If null or invalid, the method will return false.
* @return true if the XML string is well-formed and can be successfully parsed;
* false otherwise, such as in the case of invalid content or parsing errors.
*/
public static boolean checkXml(final String xml) {
try {
InputStream stream = new ByteArrayInputStream(xml.getBytes());
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dbf.newDocumentBuilder();
Document document = docBuilder.parse(stream);
return document != null;
} catch (Exception ex) {
log.warn("Exception when validating xml.", ex);
return false;
}
}
}

View File

@ -43,160 +43,4 @@
</plugin>
</plugins>
</build>
<profiles>
<!-- Profile that adds JLink and JPackage runs.
Add -Pimage or -Dimage to use this profile.
-->
<profile>
<id>image</id>
<activation>
<property>
<name>image</name>
</property>
</activation>
<build>
<plugins>
<!-- Copy dependencies -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>${maven.dependency.plugin}</version>
<executions>
<!-- erstmal Abhängigkeiten für den Class-Path kopieren -->
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/modules</outputDirectory>
<includeScope>runtime</includeScope>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
<!-- dazu noch das Projekt-JAR -->
<execution>
<id>copy</id>
<phase>install</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/modules</outputDirectory>
<artifactItems>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<type>${project.packaging}</type>
<destFileName>${project.build.finalName}.jar</destFileName>
</artifactItem>
</artifactItems>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.github.akman</groupId>
<artifactId>jpackage-maven-plugin</artifactId>
<version>${jpackage.maven.plugin}</version>
<configuration>
<name>${appName}</name>
<type>IMAGE</type>
<modulepath>
<dependencysets>
<dependencyset>
<includenames>
<includename>javafx\..*</includename>
</includenames>
</dependencyset>
</dependencysets>
</modulepath>
<addmodules>
<addmodule>javafx.controls</addmodule>
<addmodule>javafx.graphics</addmodule>
<addmodule>javafx.fxml</addmodule>
<addmodule>javafx.web</addmodule>
</addmodules>
<mainclass>${main.class}</mainclass>
<input>${project.build.directory}/modules</input>
<mainjar>${jar.filename}.jar</mainjar>
</configuration>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>jpackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<!-- Profile to build a fat jar
Add -Pfatjar or -Dfatjar to use this profile.
-->
<profile>
<id>fatjar</id>
<activation>
<property>
<name>fatjar</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>${maven.shade.plugin}</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>full</shadedClassifierName>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>${main.class}</Main-Class>
<Build-Version>1.0</Build-Version>
</manifestEntries>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/MANIFEST.MF</exclude>
<exclude>**/module-info.class</exclude>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

54
log4j/pom.xml Normal file
View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.neitzel.lib</groupId>
<artifactId>neitzellib</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>log4j</artifactId>
<properties>
<!-- Application Properties -->
<link.name>${project.artifactId}</link.name>
<launcher>${project.artifactId}</launcher>
<appName>${project.artifactId}</appName>
<jar.filename>${project.artifactId}-${project.version}</jar.filename>
<!-- Dependency Versions -->
<log4j.version>1.2.17</log4j.version>
</properties>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>apache-log4j-extras</artifactId>
<version>${log4j.version}</version>
</dependency>
</dependencies>
<build>
<finalName>${jar.filename}</finalName>
<plugins>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,88 @@
package de.neitzel.log4j;
import org.apache.log4j.PropertyConfigurator;
import java.io.File;
import java.net.URISyntaxException;
/**
* Utility class for managing Log4j configurations. Provides methods to set up
* Log4j configurations from default files, resources, or command line arguments.
*/
public class Log4jUtils {
/**
* The default path to the Log4j configuration file.
* This variable is used to specify the local file path for the Log4j configuration
* when no custom configuration is provided.
*/
public static final String DEFAULT_LOG4J_LOGFILE = "./log4j.properties";
/**
* The default resource path to the Log4j configuration file included in the classpath.
* This path is used as a fallback when no other Log4j configuration is explicitly set.
*/
public static final String DEFAULT_LOG4J_RESOURCE = "/log4j.default.properties";
/**
* Checks if the system property "log4j.configuration" is set.
*
* @return true if the "log4j.configuration" property is defined, false otherwise.
*/
public static boolean isLog4jConfigFileSet() {
return System.getProperty("log4j.configuration") != null;
}
/**
* Configures Log4j using default configuration settings.
* This method leverages a default configuration file path and a default resource path
* to set up Log4j logging if a configuration file is not already specified via
* a system property. If a valid configuration file or resource is found, it will be applied.
*
* Delegates to the overloaded {@code setLog4jConfiguration(String log4jConfigFile, String defaultResource)}
* method using predefined defaults.
*/
public static void setLog4jConfiguration() {
setLog4jConfiguration(DEFAULT_LOG4J_LOGFILE, DEFAULT_LOG4J_RESOURCE);
}
/**
* Constructs the absolute path to the specified Log4j configuration file located
* in the same directory as the JAR file of the application.
*
* @param log4jConfigFile The name of the Log4j configuration file.
* @return The absolute path to the specified Log4j configuration file if the
* path is successfully constructed; otherwise, returns null in case of an error.
*/
public static String getLog4jLogfileAtJar(final String log4jConfigFile) {
try {
return new File(Log4jUtils.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParent() + "/" + log4jConfigFile;
} catch (URISyntaxException ex) {
return null;
}
}
/**
* Sets the Log4j configuration using the specified configuration file or a default resource
* if the configuration file is not found. If a Log4j configuration is already set, the method
* does nothing.
*
* @param log4jConfigFile the path to the Log4j configuration file to be used.
* @param defaultResource the fallback resource to be used as the configuration if the file
* is not found or accessible.
*/
public static void setLog4jConfiguration(final String log4jConfigFile, final String defaultResource) {
if (isLog4jConfigFileSet()) return;
String fileAtJar = getLog4jLogfileAtJar(log4jConfigFile);
if (new File(log4jConfigFile).exists()) {
PropertyConfigurator.configure(log4jConfigFile);
} else if (fileAtJar != null && new File(fileAtJar).exists()) {
System.out.println("Nutze Log4J Konfiguration bei jar File: " + fileAtJar);
PropertyConfigurator.configure(fileAtJar);
}else {
PropertyConfigurator.configure(Log4jUtils.class.getResource(defaultResource));
}
}
}

17
pom.xml
View File

@ -15,6 +15,7 @@
<module>encryption</module>
<module>fx</module>
<module>net</module>
<module>log4j</module>
<module>fx-example</module>
</modules>
@ -24,10 +25,10 @@
<!-- Dependency versions -->
<javafx.version>21.0.3</javafx.version>
<jetbrains.annotations.version>24.1.0</jetbrains.annotations.version>
<junit.version>5.10.2</junit.version>
<lombok.version>1.18.32</lombok.version>
<mockito.version>5.12.0</mockito.version>
<jetbrains.annotations.version>26.0.2</jetbrains.annotations.version>
<junit.version>5.12.1</junit.version>
<lombok.version>1.18.38</lombok.version>
<mockito.version>5.16.1</mockito.version>
<reflections.version>0.10.2</reflections.version>
<slf4j.version>2.0.17</slf4j.version>
@ -99,6 +100,7 @@
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Lombok -->
<dependency>
@ -143,6 +145,13 @@
<scope>test</scope>
</dependency>
<!-- Logging implementation -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<scope>test</scope>
</dependency>
<!-- Dependency used for @NotNull / @Nullable -->
<dependency>
<groupId>org.jetbrains</groupId>