Compare commits

...

51 commits

Author SHA1 Message Date
8126b3ab83
Fix MiscellaneousTest failing tests
Some checks failed
build-and-test / build (push) Failing after 1m37s
build-and-test / generate-javadoc (push) Failing after 1m39s
build-and-test / test (push) Failing after 1m46s
2024-12-02 21:41:38 +01:00
a7dabfb923
Add FileAccess#move and FileAccess#copy methods
Some checks failed
build-and-test / build (push) Failing after 1m27s
build-and-test / test (push) Failing after 1m35s
build-and-test / generate-javadoc (push) Failing after 1m40s
2024-12-02 21:39:28 +01:00
de6b5f76f2
Add getPathRaw() and toString() methods 2024-12-02 21:34:59 +01:00
19f6838300
Fix engine initialization exception handling 2024-12-02 21:34:35 +01:00
8d5cb0ce23
Add more default directories 2024-12-02 21:34:24 +01:00
ed1c1d3b1a
Add 'level' and 'origin' log features
Some checks failed
build-and-test / generate-javadoc (push) Failing after 1m36s
build-and-test / test (push) Failing after 1m34s
build-and-test / build (push) Failing after 1m38s
2024-12-02 20:59:47 +01:00
571d600b09
Fix NPE in stacktraceAsStringRecursive method
Some checks failed
build-and-test / build (push) Failing after 1m23s
build-and-test / generate-javadoc (push) Failing after 1m26s
build-and-test / test (push) Failing after 1m29s
2024-12-02 02:31:04 +01:00
92aa012738
Attempt at fixing window and bgfx reinit
Some checks failed
build-and-test / build (push) Failing after 1m32s
build-and-test / test (push) Failing after 1m48s
build-and-test / generate-javadoc (push) Failing after 4m47s
2024-12-01 21:11:46 +01:00
ec1dcb734a
Remove subpackages from rendering.type package
Some checks failed
build-and-test / test (push) Failing after 2m9s
build-and-test / build (push) Failing after 15m9s
build-and-test / generate-javadoc (push) Failing after 15m51s
2024-12-01 20:10:37 +01:00
3450ba3fb0
Add renderer and render info settings
Some checks failed
build-and-test / build (push) Has been cancelled
build-and-test / test (push) Has been cancelled
build-and-test / generate-javadoc (push) Has been cancelled
2024-12-01 20:09:36 +01:00
91b2ab7a22
Add check if logging adapter has changed
Some checks failed
build-and-test / build (push) Failing after 4m30s
build-and-test / test (push) Failing after 5m16s
build-and-test / generate-javadoc (push) Failing after 43m0s
2024-12-01 16:40:06 +01:00
a2a19c03aa
Fix Javadoc issues 2024-12-01 16:39:52 +01:00
2e69d37ec7
[noci] Update actions-docker pull url 2024-11-30 12:56:17 +01:00
d71ff5db0d
Relocate + split rendering code -> separate class
Some checks failed
build-and-test / build (push) Failing after 1m57s
build-and-test / generate-javadoc (push) Failing after 2m2s
build-and-test / test (push) Failing after 2m2s
This should allow for more JIT optimizations
2024-11-25 02:52:55 +01:00
485b813853
Fix FPS calculation
Some checks failed
build-and-test / build (push) Failing after 1m51s
build-and-test / test (push) Failing after 1m57s
build-and-test / generate-javadoc (push) Failing after 2m5s
2024-11-25 02:29:00 +01:00
d6d890b259
Fix delta time and FPS count calculation
Some checks failed
build-and-test / build (push) Failing after 2m0s
build-and-test / generate-javadoc (push) Failing after 2m3s
build-and-test / test (push) Failing after 2m5s
2024-11-25 02:26:32 +01:00
2db14012f8
Remove all remaining traces of ImmutableHashMap
Some checks failed
build-and-test / build (push) Failing after 1m58s
build-and-test / test (push) Failing after 2m4s
build-and-test / generate-javadoc (push) Failing after 2m7s
2024-11-25 01:59:16 +01:00
7d15c5c73d
Cleanup rendering subsystem
Some checks failed
build-and-test / build (push) Failing after 2m4s
build-and-test / generate-javadoc (push) Failing after 2m5s
build-and-test / test (push) Failing after 2m6s
2024-11-25 01:47:00 +01:00
c89e65882c
Very experimental rendering subsystem changes
Some checks failed
build-and-test / build (push) Failing after 2m4s
build-and-test / test (push) Failing after 2m4s
build-and-test / generate-javadoc (push) Failing after 2m8s
2024-11-24 16:39:11 +01:00
45ec057457
Rename some Miscellaneous methods, add stacktraceAsStringRecursive
Some checks failed
build-and-test / build (push) Failing after 1m57s
build-and-test / generate-javadoc (push) Failing after 2m1s
build-and-test / test (push) Failing after 2m1s
2024-11-24 15:39:48 +01:00
c975c5adff
Update icon
Some checks failed
build-and-test / test (push) Failing after 1m56s
build-and-test / generate-javadoc (push) Failing after 2m11s
build-and-test / build (push) Failing after 2m13s
2024-11-24 13:28:28 +01:00
64f48a472f
Perform code maintenance
Please note that this commit may not fully compile as I'm currently working on a rendering subsystem rewrite.
2024-11-24 13:28:15 +01:00
8bd0896415
Ignore JVM segfault log files
Some checks failed
build-and-test / build (push) Failing after 59s
build-and-test / generate-javadoc (push) Failing after 1m31s
build-and-test / test (push) Successful in 1m37s
2024-11-10 20:56:52 +01:00
20580fb80b
Update documentation to reflect last commit 2024-11-10 20:56:35 +01:00
a45f010196
Merge and rename windowing subsystem 2024-11-10 20:55:01 +01:00
69cf668c4d
Heavily improve API doc of EngineConfiguration class
All checks were successful
build-and-test / test (push) Successful in 1m40s
build-and-test / generate-javadoc (push) Successful in 1m46s
build-and-test / build (push) Successful in 1m49s
2024-11-10 17:59:21 +01:00
7560e150af
Bump version
All checks were successful
build-and-test / test (push) Successful in 1m50s
build-and-test / build (push) Successful in 1m55s
build-and-test / generate-javadoc (push) Successful in 1m55s
2024-11-10 17:17:10 +01:00
b643735d0b
Update Docusaurus once again
All checks were successful
build-and-test / test (push) Successful in 1m18s
build-and-test / generate-javadoc (push) Successful in 1m22s
build-and-test / build (push) Successful in 1m24s
2024-11-09 16:16:34 +01:00
d12206b925
Update dependencies, set source version to Java 21
All checks were successful
build-and-test / test (push) Successful in 1m26s
build-and-test / generate-javadoc (push) Successful in 1m32s
build-and-test / build (push) Successful in 1m34s
2024-11-09 15:51:39 +01:00
dde8972feb
Remove unused logTemplate config setting
All checks were successful
build-and-test / test (push) Successful in 1m4s
build-and-test / build (push) Successful in 1m15s
build-and-test / generate-javadoc (push) Successful in 1m21s
2024-11-09 14:37:32 +01:00
6425442c25
Update documentation
All checks were successful
build-and-test / test (push) Successful in 1m2s
build-and-test / build (push) Successful in 1m21s
build-and-test / generate-javadoc (push) Successful in 1m20s
2024-11-08 22:15:25 +01:00
d1d8e305ed
Fix build.gradle log call
All checks were successful
build-and-test / build (push) Successful in 1m17s
build-and-test / test (push) Successful in 1m27s
build-and-test / generate-javadoc (push) Successful in 1m34s
2024-11-06 14:29:31 +01:00
a6a41f5cec
Update docusaurus
Some checks failed
build-and-test / generate-javadoc (push) Failing after 59s
build-and-test / test (push) Successful in 1m48s
build-and-test / build (push) Successful in 1m52s
2024-11-06 02:31:45 +01:00
7cf9a4f418
Remove all old shortcode converter references
Some checks failed
build-and-test / test (push) Successful in 1m17s
build-and-test / build (push) Successful in 1m47s
build-and-test / generate-javadoc (push) Failing after 1m45s
2024-11-05 21:16:42 +01:00
ea93d12151
Move the very internal shutdown event to the non-internal events package
Some checks failed
build-and-test / build (push) Has been cancelled
build-and-test / generate-javadoc (push) Has been cancelled
build-and-test / test (push) Has been cancelled
2024-11-05 21:15:30 +01:00
c533a06148
Overhaul engine init procedure + add new placeholder
Some checks failed
build-and-test / build (push) Successful in 1m17s
build-and-test / generate-javadoc (push) Failing after 1m21s
build-and-test / test (push) Successful in 1m30s
2024-11-05 21:13:30 +01:00
4281f946be
Fix Javadoc generation issues
Some checks failed
build-and-test / generate-javadoc (push) Failing after 1m4s
build-and-test / build (push) Successful in 1m16s
build-and-test / test (push) Successful in 1m15s
2024-11-05 03:07:34 +01:00
5021f2cc35
Remove testing Logger#crash call
Some checks failed
build-and-test / build (push) Failing after 46s
build-and-test / test (push) Failing after 53s
build-and-test / generate-javadoc (push) Failing after 1m4s
2024-11-05 02:57:52 +01:00
edd28bef2f
Make getArguments return an immutable list
Some checks failed
build-and-test / test (push) Failing after 58s
build-and-test / generate-javadoc (push) Failing after 1m0s
build-and-test / build (push) Failing after 1m3s
2024-11-05 02:55:28 +01:00
7c0b7e1e90
Rewrite logging infrastructure
This commit changes the following things inside the logging infrastructure:
- passing issuerClass, issuerOrigin and issuerMetadata is no longer required, relevant information is now being pulled from the stack
- split huge classes into multiple smaller ones
- separated "normal" and asynchronous logging classes
- simplified logging
- improved performance
- more detailed crash reporting
- regex-based filtering
- internal placeholders have been replaced with more lightweight method calls
- much more changes
2024-11-05 02:54:50 +01:00
0966a43d5e
Fix Javadoc generation issues
All checks were successful
build-and-test / build (push) Successful in 1m4s
build-and-test / test (push) Successful in 1m16s
build-and-test / generate-javadoc (push) Successful in 1m22s
2024-11-03 18:54:27 +01:00
2730aa0f61
Add forced early engine init stage check
Some checks failed
build-and-test / build (push) Failing after 1m22s
build-and-test / test (push) Successful in 1m18s
build-and-test / generate-javadoc (push) Failing after 1m21s
2024-11-03 18:42:42 +01:00
ed1c8b9d3e
Add FileAccess class for filesystem access
Some checks failed
build-and-test / generate-javadoc (push) Failing after 1m18s
build-and-test / build (push) Failing after 1m22s
build-and-test / test (push) Successful in 1m30s
2024-11-03 18:40:48 +01:00
d3a01c2c66
Allow throwing all exceptions during engine init
Due to some Java limitation we are required to throw a RuntimeException with our original exception contained within and afterwards unwrap it so we can throw any exception we like. That is dumb.
2024-11-03 18:40:19 +01:00
a21ef1bc5f
Fix variable name convention 2024-11-03 18:32:40 +01:00
a619746e8d
Update abstract class constructor API doc 2024-10-30 22:32:03 +01:00
e42ac8a08e
Remove unecessary Window#render() call
All checks were successful
build-and-test / build (push) Successful in 1m7s
build-and-test / test (push) Successful in 1m27s
build-and-test / generate-javadoc (push) Successful in 1m30s
2024-10-18 17:58:03 +02:00
ffcf4604a4
Add setter docs for GlfwWindow#renderCode
All checks were successful
build-and-test / test (push) Successful in 1m8s
build-and-test / generate-javadoc (push) Successful in 1m40s
build-and-test / build (push) Successful in 1m43s
2024-10-18 17:51:00 +02:00
6f8d190d6f
Add ability to inject custom rendering code, open GLFW subsystem
Some checks failed
build-and-test / build (push) Failing after 1m18s
build-and-test / generate-javadoc (push) Failing after 1m18s
build-and-test / test (push) Successful in 1m24s
2024-10-18 16:24:10 +02:00
c2028cfa33
Add window hint to instruct GLFW to use no API
All checks were successful
build-and-test / build (push) Successful in 1m16s
build-and-test / test (push) Successful in 1m30s
build-and-test / generate-javadoc (push) Successful in 1m34s
2024-10-18 15:08:06 +02:00
40894bedba
Bump version 2024-10-16 13:43:46 +02:00
194 changed files with 7360 additions and 8653 deletions

View file

@ -8,7 +8,7 @@ jobs:
build:
runs-on: docker
container:
image: git.staropensource.de/staropensource/actions-docker:java
image: git.staropensource.de/infrastructure/actions-docker:java
steps:
- name: Checkout
uses: https://code.forgejo.org/actions/checkout@v4
@ -58,7 +58,7 @@ jobs:
generate-javadoc:
runs-on: docker
container:
image: git.staropensource.de/staropensource/actions-docker:java
image: git.staropensource.de/infrastructure/actions-docker:java
steps:
- name: Checkout
uses: https://code.forgejo.org/actions/checkout@v4
@ -99,7 +99,7 @@ jobs:
test:
runs-on: docker
container:
image: git.staropensource.de/staropensource/actions-docker:java
image: git.staropensource.de/infrastructure/actions-docker:java
steps:
- name: Checkout
uses: https://code.forgejo.org/actions/checkout@v4

View file

@ -7,7 +7,7 @@ jobs:
generate-javadoc:
runs-on: docker
container:
image: git.staropensource.de/staropensource/actions-docker:java
image: git.staropensource.de/infrastructure/actions-docker:java
steps:
- name: Checkout
uses: https://code.forgejo.org/actions/checkout@v4
@ -34,7 +34,7 @@ jobs:
test:
runs-on: docker
container:
image: git.staropensource.de/staropensource/actions-docker:java
image: git.staropensource.de/infrastructure/actions-docker:java
steps:
- name: Checkout
uses: https://code.forgejo.org/actions/checkout@v4

3
.gitignore vendored
View file

@ -42,3 +42,6 @@ bin/
### Mac OS ###
.DS_Store
### Java ###
hs_err_pid*.log

View file

@ -72,6 +72,8 @@ To change them, simply append `-P<property>` or `-P<property>=<value>`, like thi
#### Parallelism
Use the `jobs` property to control how many jobs will get executed simultaneously.
On Linux, specify `-Pjobs=$(nproc)`. Defaults to `8`.
#### Rendering
You can use the `renderingPlatform` property to control which rendering platform to initialize for.
#### JVM Home
You can use the `graalHome` property to specify the `$JAVA_HOME` of your local GraalVM installation.
Only used in the `nativeImage` task. Useful if you aren't using GraalVM as your primary JDK.

View file

@ -26,7 +26,6 @@ import de.staropensource.engine.base.type.logging.LogLevel;
import org.fusesource.jansi.Ansi;
import org.fusesource.jansi.AnsiConsole;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Prints colored log output using the Jansi library.
@ -43,28 +42,16 @@ public class AnsiLoggingAdapter implements LoggingAdapter {
*/
public AnsiLoggingAdapter() {}
/** {@inheritDoc} */
@Override
public @NotNull String prePlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {
return format; // No modifications necessary
}
/** {@inheritDoc} */
@Override
public @NotNull String postPlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {
return format; // No modifications necessary
}
/** {@inheritDoc} */
@Override
@SuppressWarnings({ "resource" }) // Using try-with-resources will cause issues here
public void print(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {
public void print(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message, @NotNull String format) {
// Convert to Ansi
Ansi output = new AnsiShortcodeConverter(format, true).getAnsi();
Ansi output = new AnsiShortcodeParser(format, true).getAnsi();
// Print message
if (level == LogLevel.ERROR || level == LogLevel.CRASH)
if (EngineConfiguration.getInstance().isLoggerForceStandardOutput())
if (EngineConfiguration.getInstance().isLogForceStandardOutput())
AnsiConsole.out().println(output);
else
AnsiConsole.err().println(output);

View file

@ -28,12 +28,13 @@ import java.util.HashSet;
import java.util.Set;
/**
* Converts shortcodes such as {@code <bold>} or {@code <blink>} into a usable {@link Ansi} escape sequence.
* Implementation of the {@link ShortcodeParser} class
* with ANSI support using the Jansi library.
*
* @see ShortcodeParser
* @since v1-alpha2
* @since v1-alpha8
*/
public final class AnsiShortcodeConverter extends ShortcodeParser {
public final class AnsiShortcodeParser extends ShortcodeParser {
/**
* Creates and initializes an instance of this class.
*
@ -42,7 +43,7 @@ public final class AnsiShortcodeConverter extends ShortcodeParser {
* @throws ParserException when parsing failed
* @since v1-alpha2
*/
public AnsiShortcodeConverter(@NotNull String string, boolean ignoreInvalidEscapes) throws ParserException {
public AnsiShortcodeParser(@NotNull String string, boolean ignoreInvalidEscapes) throws ParserException {
super(string, ignoreInvalidEscapes);
}

View file

@ -21,6 +21,7 @@ package de.staropensource.engine.ansi;
import de.staropensource.engine.base.annotation.EngineSubsystem;
import de.staropensource.engine.base.implementable.SubsystemClass;
import de.staropensource.engine.base.implementation.logging.PlainLoggingAdapter;
import de.staropensource.engine.base.utility.information.EngineInformation;
import de.staropensource.engine.base.implementation.versioning.StarOpenSourceVersioningSystem;
import de.staropensource.engine.base.logging.Logger;
@ -59,7 +60,7 @@ public final class AnsiSubsystem extends SubsystemClass {
if (instance == null)
instance = this;
else
logger.crash("Only one instance of this class is allowed, use getInstance() instead of creating a new instance");
Logger.crash("Only one instance of this class is allowed, use getInstance() instead of creating a new instance");
}
/** {@inheritDoc} */
@ -71,7 +72,8 @@ public final class AnsiSubsystem extends SubsystemClass {
/** {@inheritDoc} */
@Override
public void initializeSubsystem() {
Logger.setLoggingAdapter(new AnsiLoggingAdapter());
if (Logger.getLoggingAdapter().getClass().getName().equals(PlainLoggingAdapter.class.getName()))
Logger.setLoggingAdapter(new AnsiLoggingAdapter());
}
/** {@inheritDoc} */

View file

@ -27,14 +27,17 @@ import de.staropensource.engine.base.implementable.ShutdownHandler;
import de.staropensource.engine.base.implementable.SubsystemClass;
import de.staropensource.engine.base.implementable.helper.EventHelper;
import de.staropensource.engine.base.implementation.versioning.StarOpenSourceVersioningSystem;
import de.staropensource.engine.base.internal.event.InternalEngineShutdownEvent;
import de.staropensource.engine.base.event.InternalEngineShutdownEvent;
import de.staropensource.engine.base.internal.type.DependencySubsystemVector;
import de.staropensource.engine.base.logging.PrintStreamService;
import de.staropensource.engine.base.logging.*;
import de.staropensource.engine.base.logging.backend.async.LoggingQueue;
import de.staropensource.engine.base.logging.backend.async.LoggingThread;
import de.staropensource.engine.base.type.DependencyVector;
import de.staropensource.engine.base.type.EngineState;
import de.staropensource.engine.base.type.immutable.ImmutableLinkedList;
import de.staropensource.engine.base.utility.DependencyResolver;
import de.staropensource.engine.base.utility.Miscellaneous;
import de.staropensource.engine.base.utility.FileAccess;
import de.staropensource.engine.base.utility.misc.Miscellaneous;
import de.staropensource.engine.base.utility.PlaceholderEngine;
import de.staropensource.engine.base.utility.information.EngineInformation;
import de.staropensource.engine.base.utility.information.JvmInformation;
@ -84,14 +87,6 @@ public final class Engine extends SubsystemClass {
@Getter
private static final ThreadGroup threadGroup = new ThreadGroup("sos!engine");
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha0
*/
private static final LoggerInstance logger = new LoggerInstance.Builder().setClazz(Engine.class).setOrigin("ENGINE").setMetadata(EngineInformation.getVersioningCodename()).build();
/**
* Contains the engine state.
*
@ -103,7 +98,7 @@ public final class Engine extends SubsystemClass {
* @since v1-alpha2
*/
@Getter
private @NotNull EngineState state = EngineState.UNKNOWN;
private @NotNull EngineState state;
/**
* Contains a list of all registered subsystems.
@ -118,7 +113,7 @@ public final class Engine extends SubsystemClass {
* @since v1-alpha1
*/
@Getter
private @NotNull ImmutableLinkedList<@NotNull DependencySubsystemVector> subsystems = new ImmutableLinkedList<>();
private @NotNull List<@NotNull DependencySubsystemVector> subsystems = Collections.emptyList();
/**
* Contains the engine's shutdown handler.
@ -169,57 +164,116 @@ public final class Engine extends SubsystemClass {
}
// Print warning about shutdown
logger.warn("Trying to shut down engine using shutdown hook.\nThis approach to shutting down the engine and JVM is NOT RECOMMENDED, please use Engine#shutdown() instead.");
Logger.warn("Trying to shut down engine using shutdown hook.\nThis approach to shutting down the engine and JVM is NOT RECOMMENDED, please use Engine#shutdown() instead.");
// Shutdown
Engine.getInstance().shutdown();
// Print last message
InitLogger.warn(getClass(), "ENGINE", EngineInformation.getVersioningCodename(), "Engine successfully shut down using shutdown hook. PLEASE USE Engine#shutdown() INSTEAD OF System#exit() or Runtime#exit()!");
Logger.warn("Engine successfully shut down using shutdown hook. PLEASE USE Engine#shutdown() INSTEAD OF System#exit() or Runtime#exit()!");
});
/**
* Initializes the StarOpenSource Engine.
*
* @throws IllegalStateException when running in an incompatible environment
* @since v1-alpha6
* @throws RuntimeException for all exceptions thrown by this constructor
* @since v1-alpha8
*/
private Engine() throws IllegalStateException {
long initTime = Miscellaneous.measureExecutionTime(() -> {
private Engine() throws RuntimeException {
try {
instance = this;
state = EngineState.EARLY_STARTUP;
// For measuring the initialization time
long initTimeEarly = System.currentTimeMillis();
long initTimeLate = initTimeEarly;
// Check for incompatible JVM implementations
checkJvmIncompatibilities();
// Display that the engine is initializing
Logger.verb("Initializing engine");
// Start the logging thread
Logger.diag("Starting logging infrastructure");
LoggingThread.startThread(false);
PrintStreamService.initializeStreams();
// Initialize EngineInternals
Logger.diag("Initializing EngineInternals class");
new EngineInternals();
// Load engine configuration
Logger.diag("Loading engine configuration");
new EngineConfiguration();
EngineConfiguration.getInstance().loadConfiguration();
logger.info("Initializing engine");
initializeClasses(); // Initialize classes
if (checkEnvironment()) // Check environment
throw new IllegalStateException("Running in an incompatible environment");
ensureEnvironment(); // Prepare the environment and ensure safety
populateCrashContent(); // Populate crash content
cacheEvents(); // Cache event listeners
startThreads(); // Start threads
// Load engine build information
Logger.diag("Loading engine build information");
EngineInformation.update();
logger.verb("Completing early initialization stage");
// Check for reflective classpath scanning compatibility
checkReflectiveClasspathScanningCompatibility();
// Check for Java version incompatibilities
checkJavaVersion();
// Initialize PlaceholderEngine
Logger.diag("Initializing PlaceholderEngine");
PlaceholderEngine.initialize();
// Initialize static FileAccess instances
Logger.diag("Initializing static FileAccess instances");
FileAccess.initializeInstances();
// Install the safety shutdown hook
Logger.diag("Installing safety shutdown hook");
EngineInternals.getInstance().installSafetyShutdownHook(true);
// Cache events
Logger.diag("Caching event listeners");
cacheEvents();
// Complete early initialization stage
Logger.verb("Completing early initialization stage");
state = EngineState.STARTUP;
initTimeEarly = System.currentTimeMillis() - initTimeEarly;
// Perform automatic subsystem initialization
if (EngineConfiguration.getInstance().isInitialPerformSubsystemInitialization()) {
collectSubsystems(); // Collect subsystems
// Collect all subsystems
Logger.diag("Collecting subsystems");
collectSubsystems();
// Initialize subsystems
try {
initializeSubsystems();
} catch (Exception exception) {
logger.error("Subsystem dependency resolution failed");
Logger.error("Subsystem dependency resolution failed");
}
}
});
logger.verb("Completing late initialization stage");
state = EngineState.RUNNING;
logger.info("Initialized sos!engine %engine_version% (commit %engine_git_commit_id_long%-%engine_git_branch%, dirty %engine_git_dirty%) in " + initTime + "ms\nThe StarOpenSource Engine is licensed under the GNU AGPL v3. Copyright (c) 2024 The StarOpenSource Engine Authors.");
// Complete late initialization stage
Logger.verb("Completing late initialization stage");
state = EngineState.RUNNING;
initTimeLate = System.currentTimeMillis() - initTimeLate;
// Print welcome message
Logger.info(
"""
Welcome to the StarOpenSource Engine "%engine_version_codename%" %engine_version%!
Running commit %engine_git_commit_id_long% (dirty %engine_git_dirty%).
Initialization took %init_time_total%ms (early %init_time_early%ms, late %init_time_late%ms).
Copyright (c) 2024 The StarOpenSource Engine Authors
Licensed under the GNU Affero General Public License v3"""
.replace("%init_time_total%", String.valueOf(initTimeEarly + initTimeLate))
.replace("%init_time_early%", String.valueOf(initTimeEarly))
.replace("%init_time_late%", String.valueOf(initTimeLate))
);
} catch (Exception exception) {
throw new RuntimeException(exception);
}
}
/**
@ -230,147 +284,72 @@ public final class Engine extends SubsystemClass {
* @throws RuntimeException on engine initialization failure
* @since v1-alpha6
*/
public static void initialize() throws IllegalStateException, RuntimeException {
public static void initialize() throws RuntimeException {
try {
if (instance == null)
new Engine();
} catch (IllegalStateException exception) {
throw exception;
} catch (Exception exception) {
logger.error("Engine initialization failed");
logger.error(Miscellaneous.getStackTraceHeader(exception));
for (String line : Miscellaneous.getStackTraceAsString(exception, true).split("\n"))
logger.error(line);
throw new RuntimeException("Engine initialization failed", exception);
} catch (RuntimeException exception) {
Logger.error("Engine initialization failed\n" + Miscellaneous.stacktraceAsStringRecursive(exception.getCause(), true, true));
Logger.flush();
throw new RuntimeException("Engine initialization failed", exception.getCause());
}
}
/**
* Initializes all classes.
* Checks if the running JVM implementation is not supported by the engine.
*
* @since v1-alpha0
* @since v1-alpha8
*/
private void initializeClasses() {
logger.verb("Initializing engine classes");
new EngineInternals();
PlaceholderEngine.initialize();
private void checkJvmIncompatibilities() {
if (System.getProperties().getProperty("sosengine.base.allowUnsupportedJVMInitialization", "false").equals("true")) {
Logger.warn("Skipping JVM implementation incompatibilities check");
return;
}
EngineInformation.update();
PrintStreamService.initializeStreams();
}
/**
* Checks if the environment is compatible with the engine build.
*
* @since v1-alpha4
*/
private boolean checkEnvironment() {
logger.diag("Checking environment");
// Warn about potential Java incompatibilities
if (JvmInformation.getJavaVersion() > EngineInformation.getJavaSource())
logger.warn("The StarOpenSource Engine is running on an untested Java version.\nThings may not work as expected or features which can improve performance, stability, compatibility or ease of use may be missing.\nIf you encounter issues, try running a JVM implementing Java " + EngineInformation.getJavaSource());
// Shutdown if running in an unsupported JVM
// Substrate VM (GraalVM Community)
if (JvmInformation.getImplementationName().equals("Substrate VM") && JvmInformation.getImplementationVendor().equals("GraalVM Community")) {
logger.error("##############################################################################################");
logger.error("## Running in Substrate VM, which is the name of the JVM used by GraalVM native-image. ##");
logger.error("## The StarOpenSource Engine does not support native-image as using reflection in a certain ##");
logger.error("## way seems to cause the Substrate JVM to crash. Workarounds have failed. ##");
logger.error("## This has already been noted in issue #3, which you can view here: ##");
logger.error("## https://git.staropensource.de/StarOpenSource/Engine/issues/3 ##");
logger.error("## ##");
logger.error("## While this is sad, we unfortunately can't do anything against it unless we introduce ##");
logger.error("## annoying and stupid changes into the engine, which we don't want to do. ##");
logger.error("## ##");
logger.error("## We're truly sorry for this inconvenience. The sos!engine will now terminate. ##");
logger.error("##############################################################################################");
Logger.error("##############################################################################################");
Logger.error("## Running in Substrate VM, which is the name of the JVM used by GraalVM native-image. ##");
Logger.error("## The StarOpenSource Engine does not support native-image as using reflection in a certain ##");
Logger.error("## way seems to cause the Substrate JVM to crash. Workarounds have failed. ##");
Logger.error("## This has already been noted in issue #3, which you can view here: ##");
Logger.error("## https://git.staropensource.de/StarOpenSource/Engine/issues/3 ##");
Logger.error("## ##");
Logger.error("## While this is sad, we unfortunately can't do anything against it unless we introduce ##");
Logger.error("## annoying and stupid changes into the engine, which we don't want to do. ##");
Logger.error("## ##");
Logger.error("## We're truly sorry for this inconvenience. The sos!engine will now terminate. ##");
Logger.error("##############################################################################################");
Runtime.getRuntime().exit(255);
}
}
/**
* Checks if reflective classpath scanning is supported.
*
* @since v1-alpha8
*/
private void checkReflectiveClasspathScanningCompatibility() {
// Check if reflective classpath scanning is supported
if (checkClasspathScanningSupport()) {
logger.warn("Running in an classpath scanning-unfriendly environment, disabling.");
logger.warn("If shit doesn't work and is expected to be discovered by annotations, you'll need to");
logger.warn("either register it first or have to place classes in some package.");
logger.warn("Please consult sos!engine's documentation for more information about this issue.");
if (System.getProperties().getProperty("sosengine.base.considerEnvironmentUnfriendlyToClasspathScanning", "false").equals("true")) {
Logger.warn("Running in an classpath scanning-unfriendly environment, disabling classpath scanning support.");
Logger.warn("If shit doesn't work and is expected to be discovered by annotations, you'll need to");
Logger.warn("either register it first or have to update some engine configuration setting.");
Logger.warn("Please consult sos!engine's documentation for more information about this issue.");
EngineInternals.getInstance().overrideReflectiveClasspathScanning(false);
}
return false;
}
/**
* Returns whether scanning the classpath is supported.
* Checks and warns if the Java version of the
* running JVM is higher than the engine supports.
*
* @return test results
* @since v1-alpha5
* @since v1-alpha8
*/
private boolean checkClasspathScanningSupport() {
// This may be expanded in the future
return EngineConfiguration.getInstance().isInitialForceDisableClasspathScanning();
}
/**
* Ensures the execution safety of the environment.
*
* @since v1-alpha4
*/
private void ensureEnvironment() {
EngineInternals.getInstance().installSafetyShutdownHook(true);
}
/**
* This method populates {@link CrashHandler#crashContent} with content.
*
* @see CrashHandler#getCrashContent()
* @since v1-alpha0
*/
@SuppressWarnings({ "ExtractMethodRecommender" })
private void populateCrashContent() {
logger.diag("Populating crash content");
// Issuer
Map<@NotNull String, @NotNull String> crashContentIssuer = new LinkedHashMap<>();
crashContentIssuer.put("Code part", "%issuer_origin%");
crashContentIssuer.put("Classpath", "%issuer_path%");
crashContentIssuer.put("Additional information", "%issuer_metadata%");
crashContentIssuer.put("Message", "%crash_message%");
// Engine -> Dependencies
LinkedList<@NotNull String> crashContentEngineDependencies = new LinkedList<>();
crashContentEngineDependencies.add("Subsystem 'base': Reflections: %engine_dependency_reflections%");
crashContentEngineDependencies.add("Subsystem 'ansi': Jansi: %engine_dependency_jansi%");
crashContentEngineDependencies.add("Subsystem 'slf4j-compat': SLF4J: %engine_dependency_slf4j%");
crashContentEngineDependencies.add("Subsystems 'glfw', 'opengl' & 'vulkan': LWJGL: %engine_dependency_lwjgl%");
// Engine -> *
Map<@NotNull String, @NotNull Object> crashContentEngine = new LinkedHashMap<>();
crashContentEngine.put("Version", "%engine_version%");
crashContentEngine.put("Dependencies", crashContentEngineDependencies);
// JVM -> Implementation
Map<@NotNull String, @NotNull String> crashContentJvmImplementation = new LinkedHashMap<>();
crashContentJvmImplementation.put("Name", "%jvm_implementation_name%");
crashContentJvmImplementation.put("Version", "%jvm_implementation_version%");
crashContentJvmImplementation.put("Vendor", "%jvm_implementation_vendor%");
// JVM -> *
Map<@NotNull String, @NotNull Object> crashContentJvm = new LinkedHashMap<>();
crashContentJvm.put("Java Version", "%jvm_java%");
crashContentJvm.put("Implementation", crashContentJvmImplementation);
crashContentJvm.put("Arguments", JvmInformation.getArguments());
// Operating system
Map<@NotNull String, @NotNull String> crashContentOS = new LinkedHashMap<>();
crashContentOS.put("Time", "%time_hour%:%time_minute%:%time_second% (%time_zone%, UNIX Epoch: %time_epoch%)");
crashContentOS.put("Date", "%date_day%.%date_month%.%date_year%");
// Add to crash handler
CrashHandler.getCrashContent().put("Issuer", crashContentIssuer);
CrashHandler.getCrashContent().put("Engine", crashContentEngine);
CrashHandler.getCrashContent().put("Java Virtual Machine", crashContentJvm);
CrashHandler.getCrashContent().put("Operating system", crashContentOS);
CrashHandler.getCrashContent().put("Stacktrace", "\n%stacktrace%");
CrashHandler.getCrashContent().put("Stacktrace for all threads", "\n%stacktrace_all%");
private void checkJavaVersion() {
if (JvmInformation.getJavaVersion() > EngineInformation.getJavaSource())
Logger.warn("The StarOpenSource Engine is running on an untested Java version.\nThings may not work as expected or features which can improve performance, stability, compatibility or ease of use may be missing.\nIf you encounter issues, try running a JVM implementing Java " + EngineInformation.getJavaSource());
}
/**
@ -379,28 +358,11 @@ public final class Engine extends SubsystemClass {
* @since v1-alpha0
*/
private void cacheEvents() {
logger.diag("Caching events");
// Internal events
EventHelper.cacheEvent(InternalEngineShutdownEvent.class);
// General events
EventHelper.cacheEvent(EngineCrashEvent.class);
EventHelper.cacheEvent(EngineShutdownEvent.class);
EventHelper.cacheEvent(EngineSoftCrashEvent.class);
EventHelper.cacheEvent(InternalEngineShutdownEvent.class);
EventHelper.cacheEvent(LogEvent.class);
EventHelper.cacheEvent(ThrowableCatchEvent.class);
}
/**
* Starts engine threads.
*
* @since v1-alpha1
*/
public void startThreads() {
logger.diag("Starting threads");
LoggingThread.startThread();
}
/**
@ -424,18 +386,18 @@ public final class Engine extends SubsystemClass {
if (initializedClassRaw instanceof SubsystemClass)
initializedClass = (SubsystemClass) initializedClassRaw;
else
logger.crash("Failed to initialize subsystem " + clazz.getName() + ": Does not implement " + SubsystemClass.class.getName());
Logger.crash("Failed to initialize subsystem " + clazz.getName() + ": Does not implement " + SubsystemClass.class.getName());
//noinspection DataFlowIssue // the crash call will prevent a NullPointerException
subsystemsMutable.add(new DependencySubsystemVector(initializedClass.getDependencyVector(), initializedClass));
} catch (Exception exception) {
if (exception.getClass() == IllegalStateException.class && exception.getMessage().startsWith("The version string is invalid: "))
logger.crash("Failed to initialize subsystem " + clazz.getName() + ": Invalid version string: " + exception.getMessage().replace("The version string is invalid: ", ""));
logger.crash("Failed to initialize subsystem " + clazz.getName() + ": Method invocation error", exception);
Logger.crash("Failed to initialize subsystem " + clazz.getName() + ": Invalid version string: " + exception.getMessage().replace("The version string is invalid: ", ""));
Logger.crash("Failed to initialize subsystem " + clazz.getName() + ": Method invocation error", exception);
}
// Update 'subsystems'
subsystems = new ImmutableLinkedList<>(subsystemsMutable);
subsystems = Collections.unmodifiableList(subsystemsMutable);
}
/**
@ -461,10 +423,10 @@ public final class Engine extends SubsystemClass {
} else
for (String path : EngineConfiguration.getInstance().getInitialIncludeSubsystemClasses())
try {
logger.diag("Resolving class " + path);
Logger.diag("Resolving class " + path);
classes.add(Class.forName(path));
} catch (ClassNotFoundException exception) {
logger.error("Failed loading subsystem class " + path + ": Class not found");
Logger.error("Failed loading subsystem class " + path + ": Class not found");
}
return classes;
@ -485,7 +447,7 @@ public final class Engine extends SubsystemClass {
resolver.addVectors(subsystems);
// Resolve dependencies and get order
logger.verb("Resolving subsystem dependencies");
Logger.diag("Resolving subsystem dependencies");
try {
for (DependencyVector vector : resolver.resolve().getOrder()) // smol workaround
order.add((DependencySubsystemVector) vector);
@ -500,29 +462,29 @@ public final class Engine extends SubsystemClass {
.append("- ")
.append(error);
logger.crash("Found unresolved dependencies:" + list, throwable);
Logger.crash("Found unresolved dependencies:" + list, throwable);
return;
}
logger.crash("An error occurred trying to resolve subsystem dependencies: " + throwable.getClass().getName() + (throwable.getMessage() == null ? "" : ": " + throwable.getMessage()));
Logger.crash("An error occurred trying to resolve subsystem dependencies: " + throwable.getClass().getName() + (throwable.getMessage() == null ? "" : ": " + throwable.getMessage()));
throw throwable;
}
// Initialize subsystems
logger.verb("Initializing engine subsystems");
Logger.diag("Initializing engine subsystems");
long initTime;
for (DependencySubsystemVector vector : subsystems) {
logger.diag("Initializing subsystem " + vector.getSubsystemClass().getName() + " (" + vector.getSubsystemClass().getClass().getName() + ")");
Logger.diag("Initializing subsystem '" + vector.getSubsystemClass().getName() + "' (" + vector.getSubsystemClass().getClass().getName() + ")");
try {
initTime = Miscellaneous.measureExecutionTime(() -> vector.getSubsystemClass().initializeSubsystem());
} catch (Throwable throwable) {
logger.crash("An error occurred trying to initialize subsystem " + vector.getSubsystemClass().getName() + " (" + vector.getSubsystemClass().getClass().getName() + "): " + throwable.getClass().getName() + (throwable.getMessage() == null ? "" : ": " + throwable.getMessage()));
Logger.crash("An error occurred trying to initialize subsystem " + vector.getSubsystemClass().getName() + " (" + vector.getSubsystemClass().getClass().getName() + "): " + throwable.getClass().getName() + (throwable.getMessage() == null ? "" : ": " + throwable.getMessage()));
throw throwable;
}
logger.diag("Initialized subsystem " + vector.getSubsystemClass().getName() + " (" + vector.getSubsystemClass().getClass().getName() + ") in " + initTime + "ms");
Logger.diag("Initialized subsystem '" + vector.getSubsystemClass().getName() + "' (" + vector.getSubsystemClass().getClass().getName() + ") in " + initTime + "ms");
}
// Update 'subsystems'
subsystems = new ImmutableLinkedList<>(order);
subsystems = Collections.unmodifiableList(order);
}
/**
@ -535,7 +497,7 @@ public final class Engine extends SubsystemClass {
if (state == EngineState.UNKNOWN || state == EngineState.SHUTDOWN)
return;
logger.info("Shutting engine down");
Logger.info("Shutting engine down");
if (state != EngineState.CRASHED)
state = EngineState.SHUTDOWN;
@ -546,7 +508,7 @@ public final class Engine extends SubsystemClass {
EngineConfiguration.getInstance().loadConfiguration(properties);
// Flush log messages
Logger.flushLogMessages();
LoggingQueue.flush();
// Disable safety shutdown hook
try {
@ -554,14 +516,17 @@ public final class Engine extends SubsystemClass {
} catch (Exception ignored) {}
// Send events
logger.verb("Notifying classes about shutdown");
Logger.verb("Notifying classes about shutdown");
new EngineShutdownEvent().callEvent();
logger.verb("Notifying subsystems about shutdown");
Logger.verb("Notifying subsystems about shutdown");
new InternalEngineShutdownEvent().callEvent();
// Delete scheduled files
FileAccess.deleteScheduled();
// Invoke shutdown handler
logger.verb("Invoking shutdown handler (code " + exitCode + ")");
Logger.verb("Invoking shutdown handler (code " + exitCode + ")");
shutdownHandler.shutdown((short) exitCode);
}
@ -581,7 +546,11 @@ public final class Engine extends SubsystemClass {
return "base";
}
/** {@inheritDoc} */
/**
* This method does nothing.
*
* @since v1-alpha1
*/
@Override
public void initializeSubsystem() {}
@ -634,12 +603,12 @@ public final class Engine extends SubsystemClass {
Runtime.getRuntime().addShutdownHook(thread);
Runtime.getRuntime().removeShutdownHook(thread);
} catch (IllegalStateException exception) {
logger.warn("Terminating JVM: Already shutting down, skipping");
Logger.warn("Terminating JVM: Already shutting down, skipping");
return;
}
logger.warn("Terminating JVM");
System.exit(exitCode);
Logger.warn("Terminating JVM");
Runtime.getRuntime().exit(exitCode);
}
}
}

View file

@ -19,11 +19,13 @@
package de.staropensource.engine.base;
import de.staropensource.engine.base.annotation.EngineSubsystem;
import de.staropensource.engine.base.event.LogEvent;
import de.staropensource.engine.base.implementable.Configuration;
import de.staropensource.engine.base.implementable.ShortcodeParser;
import de.staropensource.engine.base.logging.CrashHandler;
import de.staropensource.engine.base.implementable.SubsystemClass;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.logging.LoggingThread;
import de.staropensource.engine.base.logging.backend.async.LoggingThread;
import de.staropensource.engine.base.type.EngineState;
import de.staropensource.engine.base.type.logging.LogLevel;
import de.staropensource.engine.base.type.vector.Vec2f;
@ -33,10 +35,7 @@ import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.*;
/**
* Provides the base engine configuration.
@ -70,11 +69,11 @@ public final class EngineConfiguration extends Configuration {
private static EngineConfiguration instance;
/**
* Contains prefix properties must begin with.
* Contains the configuration prefix.
*
* @since v1-alpha0
* -- GETTER --
* Returns prefix properties must begin with.
* Returns the configuration prefix.
*
* @return property group
* @since v1-alpha0
@ -83,261 +82,331 @@ public final class EngineConfiguration extends Configuration {
/**
* If enabled, allows for unintentional behaviour
* and excess logging. Unless you want to debug or work
* on a sensitive part of the engine, don't enable this!
* Contains if debugging options should be allowed.
* All debugging options will be forcefully set to
* {@code false} if this option is set to {@code false}.
*
* @since v1-alpha0
* -- GETTER --
* Gets the value for {@link #debug}.
* Returns if debugging options should be allowed.
* All debugging options will be forcefully set to
* {@code false} if this option is set to {@code false}.
*
* @return variable value
* @see #debug
* @return debugging enabled?
* @since v1-alpha0
*/
private boolean debug;
/**
* If enabled, all called events will be logged.
* Contains whether or not to log
* events being emitted.
* <p>
* This will cause all events to
* be logged, with the exception
* of the {@link LogEvent}.
*
* @since v1-alpha0
* -- GETTER --
* Gets the value for {@link #debugEvents}.
* Returns whether or not to log
* events being emitted.
* <p>
* This will cause all events to
* be logged, with the exception
* of the {@link LogEvent}.
*
* @return variable value
* @see #debugEvents
* @return detailed event logging enabled?
* @since v1-alpha0
*/
private boolean debugEvents;
/**
* If enabled, will try to automatically initialize every
* subsystem found though reflection.
* Contains whether or not to automatically discover
* and initialize any class extending {@link SubsystemClass}
* whilst being annotated with {@link EngineSubsystem}.
* <p>
* This however may fail in certain situation, where manual
* subsystem initialization may be required. For this reason,
* this can be turned off before the engine initializes. Please
* note though that dependency resolution between subsystems
* won't be performed, be careful when initializing subsystems manually.
* This mechanism may fail in certain situations, where
* manual subsystem initialization may be desired. Make
* sure to disable this setting before engine startup
* and then initialize all subsystems manually.
*
* @see Engine
* @since v1-alpha2
* @since v1-alpha5
* -- GETTER --
* Gets the value for {@link #initialPerformSubsystemInitialization}.
* Returns whether or not to automatically discover
* and initialize any class extending {@link SubsystemClass}
* whilst being annotated with {@link EngineSubsystem}.
* <p>
* This mechanism may fail in certain situations, where
* manual subsystem initialization may be desired. Make
* sure to disable this setting before engine startup
* and then initialize all subsystems manually.
*
* @return variable value
* @see #initialPerformSubsystemInitialization
* @return automatically discover and initialize subsystems?
* @since v1-alpha5
*/
private boolean initialPerformSubsystemInitialization;
/**
* If enabled, will force-disable reflective classpath scanning.
*
* @see EngineInternals#getReflectiveClasspathScanning()
* @see EngineInternals#overrideReflectiveClasspathScanning(boolean)
* @since v1-alpha5
* -- GETTER --
* Gets the value for {@link #initialForceDisableClasspathScanning}.
*
* @return variable value
* @see #initialForceDisableClasspathScanning
* @since v1-alpha5
*/
private boolean initialForceDisableClasspathScanning;
/**
* Will try to load the specified classes as subsystems,
* if reflective classpath scanning is disabled.
* Contains a set of class names to try to load
* and initialize as subsystems. Will only take effect
* if {@link #initialPerformSubsystemInitialization} is
* turned off.
*
* @since v1-alpha5
* -- GETTER --
* Gets the value for {@link #initialIncludeSubsystemClasses}.
* Returns a set of class names to try to load
* and initialize as subsystems. Will only take effect
* if {@link #getInitialIncludeSubsystemClasses()} is
* turned off.
*
* @return variable value
* @see #initialIncludeSubsystemClasses
* @return set of class names to try and initialize as subsystems
* @since v1-alpha5
*/
private Set<@NotNull String> initialIncludeSubsystemClasses;
/**
* If enabled, will cause {@link ShortcodeParser} to print
* invalid shortcodes as {@link LogLevel#SILENT_WARNING}s.
* Contains whether or not to complain about invalid
* shortcodes.
* <p>
* Requires the active log level to be set at least
* to {@link LogLevel#SILENT_WARNING} to have effect.
*
* @see ShortcodeParser
* @see #loggerLevel
* @see #logLevel
* @since v1-alpha0
* -- GETTER --
* Gets the value for {@link #errorShortcodeParser}.
* Returns whether or not to complain about invalid
* shortcodes.
* <p>
* Requires the active log level to be set at least
* to {@link LogLevel#SILENT_WARNING} to have effect.
*
* @return variable value
* @see #errorShortcodeParser
* @return complain about invalid shortcodes?
* @see #getLogLevel()
* @since v1-alpha0
*/
private boolean errorShortcodeParser;
/**
* If enabled, will makes the {@link Logger} work asynchronous,
* in a separate platform thread. Don't disable unless you want
* your application to run <b>extremely</b> slowly.
* Contains if to log asynchronously.
* <p>
* If enabled, will cause a logging thread
* to spawn. All log messages will be queued
* and printed after a set delay
* ({@link #logPollingSpeed}).
* Highly recommended to keep enabled, or
* the performance of your application will
* very likely suffer.
*
* @see #loggerPollingSpeed
* @see Thread
* @see #logPollingSpeed
* @since v1-alpha0
* -- GETTER --
* Gets the value for {@link #optimizeLogging}.
* Returns if to log asynchronously.
* <p>
* If enabled, will cause a logging thread
* to spawn. All log messages will be queued
* and printed after a set delay
* ({@link #getLogPollingSpeed()}).
* Highly recommended to keep enabled, or
* the performance of your application will
* very likely suffer.
*
* @return variable value
* @see #optimizeLogging
* @return log asynchronously?
* @see #getLogPollingSpeed()
* @since v1-alpha0
*/
private boolean optimizeLogging;
/**
* If enabled, will make all events asynchronous,
* in separate virtual threads. Don't disable unless you
* want your application to run slower.
* Contains whether or not to emit events
* asynchronously.
* <p>
* This will cause a
* <a href="https://openjdk.org/jeps/444">VirtualThread</a>
* to spawn every time an event is emitted.
*
* @see VirtualThread
* @since v1-alpha0
* -- GETTER --
* Gets the value for {@link #optimizeEvents}.
* Contains whether or not to emit events
* asynchronously.
* <p>
* This will cause a
* <a href="https://openjdk.org/jeps/444">VirtualThread</a>
* to spawn every time an event is emitted.
*
* @return variable value
* @see #optimizeEvents
* @return emit events asynchronously?
* @since v1-alpha0
*/
private boolean optimizeEvents;
/**
* Contains which logger levels are allowed
* by setting the minimum logger level.
* Contains the minimum allowed log level.
* <p>
* The priority list is as follows (from high to low priority):
* <ul>
* <li>{@link LogLevel#CRASH}</li>
* <li>{@link LogLevel#ERROR}</li>
* <li>{@link LogLevel#WARNING}</li>
* <li>{@link LogLevel#INFORMATIONAL}</li>
* <li>{@link LogLevel#SILENT_WARNING}</li>
* <li>{@link LogLevel#VERBOSE}</li>
* <li>{@link LogLevel#DIAGNOSTIC}</li>
* </ul>
*
* @see Logger
* @since v1-alpha0
* -- GETTER --
* Gets the value for {@link #loggerLevel}.
* Returns the minimum allowed log level.
* <p>
* The priority list is as follows (from high to low priority):
* <ul>
* <li>{@link LogLevel#CRASH}</li>
* <li>{@link LogLevel#ERROR}</li>
* <li>{@link LogLevel#WARNING}</li>
* <li>{@link LogLevel#INFORMATIONAL}</li>
* <li>{@link LogLevel#SILENT_WARNING}</li>
* <li>{@link LogLevel#VERBOSE}</li>
* <li>{@link LogLevel#DIAGNOSTIC}</li>
* </ul>
*
* @return variable value
* @see #loggerLevel
* @return minimum allowed log level
* @since v1-alpha0
*/
private LogLevel loggerLevel;
private LogLevel logLevel;
/**
* Contains the logging template used for creating log messages.
* Contains a comma-separated list of optional
* features to add to the final log output.
* <p>
* Available features (in order of appearance):
* <ul>
* <li><code>formatting</code></li>
* <li><code>runtime</code></li>
* <li><code>date</code></li>
* <li><code>time</code></li>
* <li><code>shortIssuerClass</code></li>
* <li><code>moduleName</code></li>
* <li><code>moduleVersion</code> (requires <code>moduleName</code>)</li>
* <li><code>methodName</code></li>
* <li><code>lineNumber</code></li>
* </ul>
*
* @see Logger
* @since v1-alpha0
* @since v1-alpha8
* -- GETTER --
* Gets the value for {@link #loggerTemplate}
* Returns a comma-separated list of optional
* features to add to the final log output.
* <p>
* Available features (in order of appearance):
* <ul>
* <li><code>formatting</code></li>
* <li><code>runtime</code></li>
* <li><code>date</code></li>
* <li><code>time</code></li>
* <li><code>shortIssuerClass</code></li>
* <li><code>moduleName</code></li>
* <li><code>moduleVersion</code> (requires <code>moduleName</code>)</li>
* <li><code>methodName</code></li>
* <li><code>lineNumber</code></li>
* <li><code>level</code></li>
* <li><code>origin</code></li>
* </ul>
*
* @return variable value
* @see #loggerTemplate
* @since v1-alpha0
* @return optional features to enable
* @since v1-alpha8
*/
private String loggerTemplate;
private Set<@NotNull String> logFeatures;
/**
* Contains how fast the logging thread will
* poll for queued messages. This also causes
* messages to be buffered.
* poll for queued messages in milliseconds.
* This also causes messages to be buffered.
* <p>
* Only applies if {@code optimizeLogging} is turned on.
* Values below {@code 1} will poll for queued
* messages as fast as it can. This however has pretty much
* no benefit. Leave it at {@code 5}, it works quite well.
* Values below {@code 1} will poll for queued messages
* as fast as it can. This however has pretty much no
* benefit. Leave it at {@code 5}, it works quite well.
*
* @see #optimizeLogging
* @since v1-alpha4
* -- GETTER --
* Gets the value for {@link #loggerPollingSpeed}.
*
* @return variable value
* @see #loggerPollingSpeed
* @since v1-alpha4
*/
private int loggerPollingSpeed;
/**
* If enabled, will force the {@link Logger} and {@link CrashHandler} to use
* <a href="https://www.man7.org/linux/man-pages/man3/stderr.3.html">the standard output</a>
* instead of <a href="https://www.man7.org/linux/man-pages/man3/stderr.3.html">the standard error</a>
* for logging {@code ERROR} and {@code CRASH}.
*
* @since v1-alpha0
* -- GETTER --
* Gets the value for {@link #loggerForceStandardOutput}.
*
* @return variable value
* @see #loggerForceStandardOutput
* @since v1-alpha0
*/
private boolean loggerForceStandardOutput;
/**
* If enabled, will enable support for printing
* log messages on multiple lines. By enabling this
* configuration setting, logger throughput will be
* decreased slightly when encountering a log message
* with newlines found in it. This performance hit is
* negligible though and should not affect application
* performance, especially with logger multi-threading
* turned on (see {@link #optimizeLogging}).
*
* @since v1-alpha4
* -- GETTER --
* Gets the value for {@link #loggerEnableNewlineSupport}.
*
* @return variable value
* @see #loggerEnableNewlineSupport
* @since v1-alpha4
*/
private boolean loggerEnableNewlineSupport;
/**
* If enabled, the JVM will be shutdown immediately
* after printing a fatal crash report. This will
* prevent shutdown hooks from executing.
* Note: This will also prevent Jansi and potentially other libraries
* from removing temporary native libraries at shutdown.
*
* @see CrashHandler
* @since v1-alpha0
* -- GETTER --
* Gets the value for {@link #loggerImmediateShutdown}.
*
* @return variable value
* @see #loggerImmediateShutdown
* @since v1-alpha0
*/
private boolean loggerImmediateShutdown;
/**
* Will truncate the path of types when using
* their {@code toString} method.
* Contains how fast the logging thread will
* poll for queued messages, in milliseconds.
* This also causes messages to be buffered.
* <p>
* Here's an example: Lets say that you
* have a {@link Vec2f} and to convert it
* to a String, which you can do with
* {@link Vec2f#toString()}. With this flag
* disabled it would return
* {@code de.staropensource.engine.base.types.vectors.}{@link Vec2i}{@code (x=64 y=64)},
* with it however it would just return
* Only applies if {@code optimizeLogging} is turned on.
* Values below {@code 1} will poll for queued messages
* as fast as it can. This however has pretty much no
* benefit. Leave it at {@code 5}, it works quite well.
*
* @return logging thread polling speed in milliseconds
* @see #isOptimizeLogging()
* @since v1-alpha4
*/
private int logPollingSpeed;
/**
* Contains whether or not to forcefully write
* to the standard output instead of the
* standard error stream.
* <p>
* This only applies to the {@link LogLevel#ERROR} and
* {@link LogLevel#CRASH} log levels, as these use
* the standard error stream by default.
*
* @see <a href="https://man7.org/linux/man-pages/man3/stderr.3.html">man page about standard streams</a>
* @since v1-alpha0
* -- GETTER --
* Contains whether or not to forcefully write
* to the standard output instead of the
* standard error stream.
* <p>
* This only applies to the {@link LogLevel#ERROR} and
* {@link LogLevel#CRASH} log levels, as these use
* the standard error stream by default.
*
* @return force use stdout?
* @see <a href="https://man7.org/linux/man-pages/man3/stderr.3.html">man page about standard streams</a>
* @since v1-alpha0
*/
private boolean logForceStandardOutput;
/**
* Contains if to truncate the full path
* of a class when invoking using their
* {@link #toString()} method.
* <p>
* Here's an example: Lets say that you have a
* {@link Vec2f} instance and want to convert
* it to a String. You can do that by using
* {@link Vec2f}'s {@link Vec2f#toString()}
* method. With this flag disabled it will
* return
* {@code de.staropensource.engine.base.types.vectors.}{@link Vec2i}{@code (x=64 y=64)}.
* With this flag enabled however the method will return
* {@link Vec2i}{@code (x=64 y=64)},
* which is much smaller.
*
* @since v1-alpha2
* -- GETTER --
* Gets the value for {@link #hideFullTypePath}.
* Returns if to truncate the full path
* of a class when invoking using their
* {@link #toString()} method.
* <p>
* Here's an example: Lets say that you have a
* {@link Vec2f} instance and want to convert
* it to a String. You can do that by using
* {@link Vec2f}'s {@link Vec2f#toString()}
* method. With this flag disabled it will
* return
* {@code de.staropensource.engine.base.types.vectors.}{@link Vec2i}{@code (x=64 y=64)}.
* With this flag enabled however the method will return
* {@link Vec2i}{@code (x=64 y=64)},
* which is much smaller.
*
* @return variable value
* @see #hideFullTypePath
* @return truncate class paths?
* @since v1-alpha2
*/
private boolean hideFullTypePath;
@ -349,7 +418,7 @@ public final class EngineConfiguration extends Configuration {
* @since v1-alpha6
*/
EngineConfiguration() {
super("ENGINE");
super();
instance = this;
@ -366,7 +435,6 @@ public final class EngineConfiguration extends Configuration {
case "debugEvents" -> debugEvents = parser.getBoolean(group + property);
case "initialPerformSubsystemInitialization" -> initialPerformSubsystemInitialization = parser.getBoolean(group + property);
case "initialForceDisableClasspathScanning" -> initialForceDisableClasspathScanning = parser.getBoolean(group + property);
case "initialIncludeSubsystemClasses" -> {
initialIncludeSubsystemClasses = new HashSet<>();
initialIncludeSubsystemClasses.addAll(Arrays.stream(parser.getString(group + property).split(",")).toList());
@ -378,23 +446,22 @@ public final class EngineConfiguration extends Configuration {
optimizeLogging = parser.getBoolean(group + property);
// Start logging thread automatically
if (optimizeLogging && Engine.getInstance().getState() == EngineState.RUNNING)
LoggingThread.startThread();
if (optimizeLogging && Engine.getInstance().getState() == EngineState.RUNNING) {
LoggingThread.startThread(false);
}
}
case "optimizeEvents" -> optimizeEvents = parser.getBoolean(group + property);
case "loggerLevel" -> {
case "logLevel" -> {
try {
loggerLevel = LogLevel.valueOf(parser.getString(group + property).toUpperCase());
logLevel = LogLevel.valueOf(parser.getString(group + property).toUpperCase());
} catch (IllegalArgumentException ignored) {
System.out.println("Logger level " + parser.getString(group + property) + " is not valid");
Logger.error("The log level '" + parser.getString(group + property) + "' is not valid");
}
}
case "loggerTemplate" -> loggerTemplate = parser.getString(group + property);
case "loggerPollingSpeed" -> loggerPollingSpeed = parser.getInteger(group + property, true);
case "loggerForceStandardOutput" -> loggerForceStandardOutput = parser.getBoolean(group + property);
case "loggerEnableNewlineSupport" -> loggerEnableNewlineSupport = parser.getBoolean(group + property);
case "loggerImmediateShutdown" -> loggerImmediateShutdown = parser.getBoolean(group + property);
case "logFeatures" -> logFeatures = Set.copyOf(Arrays.stream(parser.getString(group + property).split(",")).toList());
case "logPollingSpeed" -> logPollingSpeed = parser.getInteger(group + property, true);
case "logForceStandardOutput" -> logForceStandardOutput = parser.getBoolean(group + property);
case "hideFullTypePath" -> hideFullTypePath = parser.getBoolean(group + property);
}
@ -417,7 +484,6 @@ public final class EngineConfiguration extends Configuration {
debugEvents = false;
initialPerformSubsystemInitialization = true;
initialForceDisableClasspathScanning = false;
initialIncludeSubsystemClasses = new HashSet<>();
errorShortcodeParser = true;
@ -425,12 +491,10 @@ public final class EngineConfiguration extends Configuration {
optimizeLogging = true;
optimizeEvents = true;
loggerLevel = LogLevel.INFORMATIONAL;
loggerTemplate = "%log_color_primary%[%time_hour%:%time_minute%:%time_second%] [%log_level% %log_path%%log_metadata%] %log_message_prefix%%log_color_primary%%log_color_secondary%%log_message%<reset>";
loggerPollingSpeed = 5;
loggerForceStandardOutput = false;
loggerEnableNewlineSupport = true;
loggerImmediateShutdown = false;
logLevel = LogLevel.INFORMATIONAL;
logFeatures = Set.of("formatting", "time", "methodName", "lineNumber", "level", "origin");
logPollingSpeed = 5;
logForceStandardOutput = false;
hideFullTypePath = false;
}
@ -443,7 +507,6 @@ public final class EngineConfiguration extends Configuration {
case "debugEvents" -> debugEvents;
case "initialPerformSubsystemInitialization" -> initialPerformSubsystemInitialization;
case "initialForceDisableClasspathScanning" -> initialForceDisableClasspathScanning;
case "initialIncludeSubsystemClasses" -> initialIncludeSubsystemClasses;
case "errorShortcodeParser" -> errorShortcodeParser;
@ -451,12 +514,10 @@ public final class EngineConfiguration extends Configuration {
case "optimizeLogging" -> optimizeLogging;
case "optimizeEvents" -> optimizeEvents;
case "loggerLevel" -> loggerLevel;
case "loggerTemplate" -> loggerTemplate;
case "loggerPollingSpeed" -> loggerPollingSpeed;
case "loggerForceStandardOutput" -> loggerForceStandardOutput;
case "loggerEnableNewlineSupport" -> loggerEnableNewlineSupport;
case "loggerImmediateShutdown" -> loggerImmediateShutdown;
case "logLevel" -> logLevel;
case "logFeatures" -> logFeatures;
case "logPollingSpeed" -> logPollingSpeed;
case "logForceStandardOutput" -> logForceStandardOutput;
case "hideFullTypePath" -> hideFullTypePath;
default -> null;

View file

@ -20,11 +20,11 @@
package de.staropensource.engine.base;
import de.staropensource.engine.base.exception.IllegalAccessException;
import de.staropensource.engine.base.implementable.Event;
import de.staropensource.engine.base.implementable.EventListenerCode;
import de.staropensource.engine.base.implementable.ShutdownHandler;
import de.staropensource.engine.base.implementable.helper.EventHelper;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.base.type.EventPriority;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.InternalAccessArea;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
@ -54,14 +54,6 @@ public final class EngineInternals {
@Getter
private static EngineInternals instance;
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha4
*/
private static final LoggerInstance logger = new LoggerInstance.Builder().setClazz(EngineInternals.class).setOrigin("ENGINE").build();
/**
* Contains all disabled internal access areas.
*
@ -85,7 +77,7 @@ public final class EngineInternals {
* use case and application.
*
* @see EventHelper#registerEvent(Class, EventListenerCode)
* @see EventHelper#registerEvent(Class, EventListenerCode, EventPriority)
* @see EventHelper#registerEvent(Class, EventListenerCode, Event.Priority)
* @since v1-alpha5
*/
private boolean reflectiveClasspathScanning = true;
@ -100,7 +92,7 @@ public final class EngineInternals {
if (instance == null && Engine.getInstance() != null)
instance = this;
else
logger.crash("Only one instance of this class is allowed, use getInstance() instead of creating a new instance");
Logger.crash("Only one instance of this class is allowed, use getInstance() instead of creating a new instance");
}
/**
@ -199,7 +191,7 @@ public final class EngineInternals {
* @return reflective classpath scanning flag state
* @throws IllegalAccessException when restricted ({@link InternalAccessArea#REFLECTIVE_CLASSPATH_SCANNING_GET})
* @see EventHelper#registerEvent(Class, EventListenerCode)
* @see EventHelper#registerEvent(Class, EventListenerCode, EventPriority)
* @see EventHelper#registerEvent(Class, EventListenerCode, Event.Priority)
* @since v1-alpha5
*/
public boolean getReflectiveClasspathScanning() throws IllegalAccessException {
@ -224,7 +216,7 @@ public final class EngineInternals {
* @param reflectiveClasspathScanning new reflective classpath scanning
* @throws IllegalAccessException when restricted ({@link InternalAccessArea#REFLECTIVE_CLASSPATH_SCANNING_OVERRIDE})
* @see EventHelper#registerEvent(Class, EventListenerCode)
* @see EventHelper#registerEvent(Class, EventListenerCode, EventPriority)
* @see EventHelper#registerEvent(Class, EventListenerCode, Event.Priority)
* @since v1-alpha5
*/
public void overrideReflectiveClasspathScanning(boolean reflectiveClasspathScanning) throws IllegalAccessException {

View file

@ -20,7 +20,6 @@
package de.staropensource.engine.base.annotation;
import de.staropensource.engine.base.implementable.Event;
import de.staropensource.engine.base.type.EventPriority;
import org.jetbrains.annotations.NotNull;
import java.lang.annotation.*;
@ -48,8 +47,8 @@ public @interface EventListener {
* Specifies the priority of the event.
*
* @return event priority
* @see EventPriority
* @see Event.Priority
* @since v1-alpha0
*/
@NotNull EventPriority priority() default EventPriority.DEFAULT;
@NotNull Event.Priority priority() default Event.Priority.DEFAULT;
}

View file

@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.event;
package de.staropensource.engine.base.event;
import de.staropensource.engine.base.implementable.Event;
import de.staropensource.engine.base.implementable.helper.EventHelper;

View file

@ -1,61 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.event;
import de.staropensource.engine.base.implementable.Event;
import de.staropensource.engine.base.implementable.helper.EventHelper;
import de.staropensource.engine.base.utility.Miscellaneous;
import org.jetbrains.annotations.NotNull;
/**
* Called when an exception is caught by {@link Miscellaneous#executeSafely(Runnable, String)}.
*
* @see Miscellaneous#executeSafely(Runnable, String)
* @since v1-alpha0
*/
public final class ThrowableCatchEvent implements Event {
/**
* Creates and initializes an instance of this event.
*
* @since v1-alpha0
*/
public ThrowableCatchEvent() {}
/**
* {@inheritDoc}
*
* @deprecated use the {@code callEvent} method with arguments
* @see ThrowableCatchEvent#callEvent(Throwable, String)
*/
@Deprecated
@Override
public void callEvent() {}
/**
* Emits the event and calls all event listeners.
*
* @param throwable caught throwable
* @param identifier an identifier given to the runnable
* @since v1-alpha0
*/
public void callEvent(@NotNull Throwable throwable, @NotNull String identifier) {
EventHelper.invokeAnnotatedMethods(getClass(), throwable, identifier);
}
}

View file

@ -20,7 +20,7 @@
package de.staropensource.engine.base.exception.reflection;
import de.staropensource.engine.base.type.reflection.ClassType;
import de.staropensource.engine.base.utility.ListFormatter;
import de.staropensource.engine.base.utility.misc.ListFormatter;
import org.jetbrains.annotations.NotNull;
/**

View file

@ -19,7 +19,6 @@
package de.staropensource.engine.base.implementable;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.base.utility.PropertiesReader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -37,23 +36,11 @@ import java.util.Properties;
*/
public abstract class Configuration {
/**
* Contains the {@link LoggerInstance} for this instance.
* Creates and initializes an instance of this abstract class.
*
* @see LoggerInstance
* @since v1-alpha1
*/
protected final @NotNull LoggerInstance logger;
/**
* Initializes this abstract class.
*
* @param origin see {@link LoggerInstance.Builder#setOrigin(String)}
* @since v1-alpha2
*/
protected Configuration(@NotNull String origin) {
// Set logger instance
logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin(origin).build();
protected Configuration() {
// Load default configuration
loadDefaultConfiguration();
}

View file

@ -19,6 +19,7 @@
package de.staropensource.engine.base.implementable;
import de.staropensource.engine.base.annotation.EventListener;
import de.staropensource.engine.base.implementable.helper.EventHelper;
/**
@ -34,4 +35,76 @@ public interface Event {
* @since v1-alpha0
*/
void callEvent();
/**
* Specifies in which order {@link EventListener}s shall be called.
*
* @since v1-alpha9
*/
@SuppressWarnings({ "unused" })
enum Priority {
/**
* {@link EventListener}s with this
* priority are called before all others.
* <p>
* This priority is exclusive to the
* engine and subsystems and should
* not be used by applications.
*
* @since v1-alpha9
*/
EXCLUSIVELY_IMPORTANT,
/**
* {@link EventListener}s with
* this priority are called 2nd.
*
* @since v1-alpha9
*/
VERY_IMPORTANT,
/**
* {@link EventListener}s with
* this priority are called 3rd.
*
* @since v1-alpha9
*/
IMPORTANT,
/**
* {@link EventListener}s with
* this priority are called 4th.
*
* @since v1-alpha9
*/
DEFAULT,
/**
* {@link EventListener}s with
* this priority are called 5th.
*
* @since v1-alpha9
*/
UNIMPORTANT,
/**
* {@link EventListener}s with
* this priority are called 6th.
*
* @since v1-alpha9
*/
VERY_UNIMPORTANT,
/**
* {@link EventListener}s with this
* priority are called after all others.
* <p>
* This priority is exclusive to the
* engine and subsystems and should
* not be used by applications.
*
* @since v1-alpha9
*/
EXCLUSIVELY_UNIMPORTANT
}
}

View file

@ -20,7 +20,6 @@
package de.staropensource.engine.base.implementable;
import de.staropensource.engine.base.implementable.helper.EventHelper;
import de.staropensource.engine.base.type.EventPriority;
import org.jetbrains.annotations.NotNull;
/**
@ -39,10 +38,10 @@ public abstract class EventListenerCode {
*
* @since v1-alpha5
*/
public @NotNull EventPriority priority = EventPriority.DEFAULT;
public @NotNull Event.Priority priority = Event.Priority.DEFAULT;
/**
* Initializes this abstract class.
* Creates and initializes an instance of this abstract class.
*
* @since v1-alpha5
*/

View file

@ -22,7 +22,6 @@ package de.staropensource.engine.base.implementable;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.logging.LogLevel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Interface for implementing custom logger implementations.
@ -32,43 +31,13 @@ import org.jetbrains.annotations.Nullable;
*/
public interface LoggingAdapter {
/**
* Invoked before anything is done with the log message.
* Prints a log message.
*
* @param level level
* @param issuerClass issuer class
* @param issuerOrigin issuer origin
* @param issuerMetadata issuer metadata
* @param message raw message
* @param format unmodified log format
* @return new log message, return {@code null} for no change
* @param level level of the log call
* @param issuer {@link StackTraceElement} of the issuer
* @param message raw message
* @param format processed log call output (print this!)
* @since v1-alpha2
*/
@Nullable String prePlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format);
/**
* Invoked after placeholders have been processed and replaced.
*
* @param level level
* @param issuerClass issuer class
* @param issuerOrigin issuer origin
* @param issuerMetadata issuer metadata
* @param message raw message
* @param format unmodified log format
* @return new log format
* @since v1-alpha2
*/
@NotNull String postPlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format);
/**
* Prints the log message.
*
* @param level level
* @param issuerClass issuer class
* @param issuerOrigin issuer origin
* @param issuerMetadata issuer metadata
* @param message raw message
* @param format unmodified log format
* @since v1-alpha2
*/
void print(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format);
void print(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message, @NotNull String format);
}

View file

@ -21,7 +21,7 @@ package de.staropensource.engine.base.implementable;
import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.exception.ParserException;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.base.logging.Logger;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
@ -29,7 +29,7 @@ import java.util.LinkedList;
import java.util.Locale;
/**
* Base class for implementing a shortcode converter.
* Base class for implementing a shortcode parser.
* <p>
* This class parses a string and converts it into a list of
* components, which can then be in turn be converted to something
@ -48,16 +48,9 @@ import java.util.Locale;
*
* @since v1-alpha1
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public abstract class ShortcodeParser {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha1
*/
protected final @NotNull LoggerInstance logger;
/**
* Contains a list of components the parsed text is made out of.
*
@ -68,11 +61,10 @@ public abstract class ShortcodeParser {
* @return component list
* @since v1-alpha1
*/
@Getter
protected final @NotNull LinkedList<String> components;
/**
* Initializes this abstract class.
* Creates and initializes an instance of this abstract class.
*
* @param string string to parse
* @param ignoreInvalidEscapes if {@code true}, will ignore and treat invalid escapes as text
@ -80,7 +72,6 @@ public abstract class ShortcodeParser {
* @since v1-alpha2
*/
protected ShortcodeParser(@NotNull String string, boolean ignoreInvalidEscapes) throws ParserException {
logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").build();
components = parse(string, ignoreInvalidEscapes);
}
@ -134,7 +125,7 @@ public abstract class ShortcodeParser {
else {
// Complain about invalid shortcode
if (EngineConfiguration.getInstance() != null && EngineConfiguration.getInstance().isErrorShortcodeParser())
logger.sarn("Invalid shortcode: " + part);
Logger.sarn("Invalid shortcode: " + part);
// Convert tag regular text
components.add("TEXT:" + "<" + part + ">");
@ -146,7 +137,7 @@ public abstract class ShortcodeParser {
else {
// Complain about invalid shortcode
if (EngineConfiguration.getInstance() != null && EngineConfiguration.getInstance().isErrorShortcodeParser())
logger.sarn("Invalid shortcode: " + part);
Logger.sarn("Invalid shortcode: " + part);
// Convert tag regular text
components.add("TEXT:" + "<" + part + ">");
@ -174,7 +165,7 @@ public abstract class ShortcodeParser {
else {
// Complain about invalid shortcode
if (EngineConfiguration.getInstance() != null && EngineConfiguration.getInstance().isErrorShortcodeParser())
logger.sarn("Invalid shortcode: " + part);
Logger.sarn("Invalid shortcode: " + part);
// Convert tag regular text
components.add("TEXT:" + "<" + part + ">");

View file

@ -22,8 +22,7 @@ package de.staropensource.engine.base.implementable;
import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.annotation.EngineSubsystem;
import de.staropensource.engine.base.annotation.EventListener;
import de.staropensource.engine.base.internal.event.InternalEngineShutdownEvent;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.base.event.InternalEngineShutdownEvent;
import de.staropensource.engine.base.type.DependencyVector;
import org.jetbrains.annotations.NotNull;
@ -35,15 +34,7 @@ import org.jetbrains.annotations.NotNull;
*/
public abstract class SubsystemClass {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha0
*/
public final LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").build();
/**
* Initializes this abstract class.
* Creates and initializes an instance of this abstract class.
*
* @since v1-alpha2
*/

View file

@ -30,9 +30,9 @@ import de.staropensource.engine.base.exception.reflection.StaticInitializerExcep
import de.staropensource.engine.base.implementable.Event;
import de.staropensource.engine.base.implementable.EventListenerCode;
import de.staropensource.engine.base.internal.implementation.EventListenerMethod;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.base.type.EventPriority;
import de.staropensource.engine.base.utility.ListFormatter;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.utility.misc.ListFormatter;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -52,14 +52,6 @@ import java.util.*;
*/
@Getter
public final class EventHelper {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha1
*/
private static final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(EventHelper.class).setOrigin("ENGINE").build();
/**
* Holds all cached events.
*
@ -85,7 +77,7 @@ public final class EventHelper {
* @see EngineInternals#getReflectiveClasspathScanning()
* @since v1-alpha5
*/
public static synchronized void registerEvent(@NotNull Class<? extends Event> event, @NotNull EventListenerCode eventListener, @NotNull EventPriority priority) {
public static synchronized void registerEvent(@NotNull Class<? extends Event> event, @NotNull EventListenerCode eventListener, @NotNull Event.Priority priority) {
if (EngineInternals.getInstance().getReflectiveClasspathScanning())
return;
@ -105,7 +97,7 @@ public final class EventHelper {
cachedEventListeners.put(event, list);
}
logger.diag("Registered event listener " + eventListener + " for event " + event + " with priority " + priority.name());
Logger.diag("Registered event listener " + eventListener + " for event " + event + " with priority " + priority.name());
}
/**
@ -119,7 +111,7 @@ public final class EventHelper {
* @since v1-alpha5
*/
public static void registerEvent(@NotNull Class<? extends Event> event, @NotNull EventListenerCode eventListener) {
registerEvent(event, eventListener, EventPriority.DEFAULT);
registerEvent(event, eventListener, Event.Priority.DEFAULT);
}
/**
@ -177,26 +169,26 @@ public final class EventHelper {
public static void invokeAnnotatedMethods(@NotNull Class<? extends Event> event, Object... arguments) {
if (event != LogEvent.class && EngineConfiguration.getInstance().isDebugEvents())
if (arguments.length == 0)
logger.diag("Event " + event.getName() + " was emitted");
Logger.diag("Event " + event.getName() + " was emitted");
else
logger.diag("Event " + event.getName() + " was emitted, passing arguments " + ListFormatter.formatArray(arguments));
Logger.diag("Event " + event.getName() + " was emitted, passing arguments " + ListFormatter.formatArray(arguments));
Runnable eventCode = () -> {
for (EventListenerCode eventListener : getAnnotatedMethods(event)) {
try {
eventListener.run(arguments);
} catch (NoAccessException exception) {
logger.warn("Event listener " + eventListener + " could not be called as the method could not be accessed");
Logger.warn("Event listener " + eventListener + " could not be called as the method could not be accessed");
} catch (InvalidMethodSignatureException exception) {
logger.warn("Event listener " + eventListener + " has an invalid method signature");
Logger.warn("Event listener " + eventListener + " has an invalid method signature");
} catch (InvocationTargetException exception) {
logger.crash("Event listener " + eventListener + " threw a throwable", exception.getTargetException(), true);
Logger.crash("Event listener " + eventListener + " threw a throwable", exception.getTargetException(), true);
} catch (InstanceMethodFromStaticContextException exception) {
logger.warn("Event listener " + eventListener + " is not static. Event listener methods must be static for them to be called.");
Logger.warn("Event listener " + eventListener + " is not static. Event listener methods must be static for them to be called.");
} catch (StaticInitializerException exception) {
logger.crash("Event listener " + eventListener + " could not be called as the static initializer failed", exception.getThrowable(), true);
Logger.crash("Event listener " + eventListener + " could not be called as the static initializer failed", exception.getThrowable(), true);
} catch (Exception exception) {
logger.crash("Event listener " + eventListener + " could not be called as an error occurred during reflection", exception, true);
Logger.crash("Event listener " + eventListener + " could not be called as an error occurred during reflection", exception, true);
}
}
};

View file

@ -23,9 +23,8 @@ import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.implementable.LoggingAdapter;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.logging.LogLevel;
import de.staropensource.engine.base.implementation.shortcode.EmptyShortcodeConverter;
import de.staropensource.engine.base.implementation.shortcode.EmptyShortcodeParser;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Prints log messages to the console, without any fancy colors or formatting.
@ -44,22 +43,10 @@ public class PlainLoggingAdapter implements LoggingAdapter {
/** {@inheritDoc} */
@Override
public @Nullable String prePlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {
return null; // No modifications necessary
}
/** {@inheritDoc} */
@Override
public @NotNull String postPlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {
return format; // No modifications necessary
}
/** {@inheritDoc} */
@Override
public void print(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {
format = new EmptyShortcodeConverter(format, true).getClean();
public void print(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message, @NotNull String format) {
format = new EmptyShortcodeParser(format, true).getClean();
if (level == LogLevel.ERROR || level == LogLevel.CRASH)
if (EngineConfiguration.getInstance() != null && EngineConfiguration.getInstance().isLoggerForceStandardOutput())
if (EngineConfiguration.getInstance() != null && EngineConfiguration.getInstance().isLogForceStandardOutput())
System.out.println(format);
else
System.err.println(format);

View file

@ -40,17 +40,5 @@ public class QuietLoggingAdapter implements LoggingAdapter {
/** {@inheritDoc} */
@Override
public @Nullable String prePlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {
return null;
}
/** {@inheritDoc} */
@Override
public @NotNull String postPlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {
return format;
}
/** {@inheritDoc} */
@Override
public void print(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {}
public void print(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message, @NotNull String format) {}
}

View file

@ -44,21 +44,9 @@ public class RawLoggingAdapter implements LoggingAdapter {
/** {@inheritDoc} */
@Override
public @Nullable String prePlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {
return null; // No modifications necessary
}
/** {@inheritDoc} */
@Override
public @NotNull String postPlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {
return format; // No modifications necessary
}
/** {@inheritDoc} */
@Override
public void print(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {
public void print(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message, @NotNull String format) {
if (level == LogLevel.ERROR || level == LogLevel.CRASH)
if (EngineConfiguration.getInstance().isLoggerForceStandardOutput())
if (EngineConfiguration.getInstance().isLogForceStandardOutput())
System.out.println(format);
else
System.err.println(format);

View file

@ -27,18 +27,18 @@ import org.jetbrains.annotations.NotNull;
* Cleans the string of any tags.
*
* @see ShortcodeParser
* @since v1-alpha1
* @since v1-alpha8
*/
public final class EmptyShortcodeConverter extends ShortcodeParser {
public final class EmptyShortcodeParser extends ShortcodeParser {
/**
* Creates and initializes an instance of this class.
*
* @param string string to parse
* @param ignoreInvalidEscapes if {@code true}, will ignore and treat invalid escapes as text
* @throws ParserException on error
* @since v1-alpha1
* @since v1-alpha8
*/
public EmptyShortcodeConverter(@NotNull String string, boolean ignoreInvalidEscapes) throws ParserException {
public EmptyShortcodeParser(@NotNull String string, boolean ignoreInvalidEscapes) throws ParserException {
super(string, ignoreInvalidEscapes);
}
@ -46,7 +46,7 @@ public final class EmptyShortcodeConverter extends ShortcodeParser {
* Returns the parsed string without any tags.
*
* @return cleaned input string
* @since v1-alpha1
* @since v1-alpha8
*/
public @NotNull String getClean() {
StringBuilder output = new StringBuilder();

View file

@ -22,7 +22,7 @@ package de.staropensource.engine.base.implementation.versioning;
import de.staropensource.engine.base.implementable.VersioningSystem;
import de.staropensource.engine.base.exception.versioning.IncompatibleVersioningSystemException;
import de.staropensource.engine.base.exception.versioning.InvalidVersionStringException;
import de.staropensource.engine.base.utility.Miscellaneous;
import de.staropensource.engine.base.utility.misc.StringUtil;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Range;
@ -98,7 +98,7 @@ public final class FourNumberVersioningSystem implements VersioningSystem {
*/
public FourNumberVersioningSystem(@NotNull String versionString) throws InvalidVersionStringException {
String[] separatorList = new String[]{ ".", "-" };
String separator = Miscellaneous.getSeparator(versionString, separatorList, 3);
String separator = StringUtil.getSeparatorRequired(versionString, separatorList, 3);
// Escape separator or throw error if invalid
switch (separator) {

View file

@ -22,7 +22,7 @@ package de.staropensource.engine.base.implementation.versioning;
import de.staropensource.engine.base.implementable.VersioningSystem;
import de.staropensource.engine.base.exception.versioning.IncompatibleVersioningSystemException;
import de.staropensource.engine.base.exception.versioning.InvalidVersionStringException;
import de.staropensource.engine.base.utility.Miscellaneous;
import de.staropensource.engine.base.utility.misc.StringUtil;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -117,7 +117,7 @@ public final class SemanticVersioningSystem implements VersioningSystem {
*/
public SemanticVersioningSystem(@NotNull String versionString) throws InvalidVersionStringException {
String[] separatorList = new String[]{ "." };
String separator = Miscellaneous.getSeparator(versionString, separatorList, 2);
String separator = StringUtil.getSeparatorRequired(versionString, separatorList, 2);
// Escape separator or throw error if invalid
switch (separator) {

View file

@ -22,7 +22,7 @@ package de.staropensource.engine.base.implementation.versioning;
import de.staropensource.engine.base.implementable.VersioningSystem;
import de.staropensource.engine.base.exception.versioning.IncompatibleVersioningSystemException;
import de.staropensource.engine.base.exception.versioning.InvalidVersionStringException;
import de.staropensource.engine.base.utility.Miscellaneous;
import de.staropensource.engine.base.utility.misc.StringUtil;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Range;
@ -86,7 +86,7 @@ public final class ThreeNumberVersioningSystem implements VersioningSystem {
*/
public ThreeNumberVersioningSystem(@NotNull String versionString) throws InvalidVersionStringException {
String[] separatorList = new String[]{ ".", "-" };
String separator = Miscellaneous.getSeparator(versionString, separatorList, 2);
String separator = StringUtil.getSeparatorRequired(versionString, separatorList, 2);
// Escape separator or throw error if invalid
switch (separator) {

View file

@ -22,7 +22,7 @@ package de.staropensource.engine.base.implementation.versioning;
import de.staropensource.engine.base.implementable.VersioningSystem;
import de.staropensource.engine.base.exception.versioning.IncompatibleVersioningSystemException;
import de.staropensource.engine.base.exception.versioning.InvalidVersionStringException;
import de.staropensource.engine.base.utility.Miscellaneous;
import de.staropensource.engine.base.utility.misc.StringUtil;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Range;
@ -74,7 +74,7 @@ public final class TwoNumberVersioningSystem implements VersioningSystem {
*/
public TwoNumberVersioningSystem(@NotNull String versionString) throws InvalidVersionStringException {
String[] separatorList = new String[]{ ".", "-" };
String separator = Miscellaneous.getSeparator(versionString, separatorList, 1);
String separator = StringUtil.getSeparatorRequired(versionString, separatorList, 1);
// Escape separator or throw error if invalid
switch (separator) {

View file

@ -1,24 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* Events used for engine-internal communication.
* These events are meant to be listened on by the base engine and it's subsystems.
*/
package de.staropensource.engine.base.internal.event;

View file

@ -20,7 +20,7 @@
package de.staropensource.engine.base.internal.implementation.placeholder;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.utility.Math;
import de.staropensource.engine.base.utility.misc.NumberUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Calendar;
@ -43,6 +43,6 @@ public final class DateDay implements Placeholder {
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%date_day%", Math.padNumbers(Calendar.getInstance().get(Calendar.DAY_OF_MONTH), 2));
return text.replace("%date_day%", NumberUtil.padNumbers(Calendar.getInstance().get(Calendar.DAY_OF_MONTH), 2));
}
}

View file

@ -20,7 +20,7 @@
package de.staropensource.engine.base.internal.implementation.placeholder;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.utility.Math;
import de.staropensource.engine.base.utility.misc.NumberUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Calendar;
@ -43,6 +43,6 @@ public final class DateMonth implements Placeholder {
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%date_month%", Math.padNumbers(Calendar.getInstance().get(Calendar.MONTH), 2));
return text.replace("%date_month%", NumberUtil.padNumbers(Calendar.getInstance().get(Calendar.MONTH), 2));
}
}

View file

@ -20,7 +20,7 @@
package de.staropensource.engine.base.internal.implementation.placeholder;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.utility.Math;
import de.staropensource.engine.base.utility.misc.NumberUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Calendar;
@ -43,6 +43,6 @@ public final class DateYear implements Placeholder {
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%date_year%", Math.padNumbers(Calendar.getInstance().get(Calendar.YEAR), 4));
return text.replace("%date_year%", NumberUtil.padNumbers(Calendar.getInstance().get(Calendar.YEAR), 4));
}
}

View file

@ -17,40 +17,30 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.crashhandler;
package de.staropensource.engine.base.internal.implementation.placeholder;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.utility.information.EngineInformation;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code crash_message} placeholder.
* Implements the {@code engine_version_codename} placeholder.
*
* @see Placeholder
* @since v1-alpha0
* @since v1-alpha8
*/
@SuppressWarnings({ "unused" })
public final class CrashMessage implements Placeholder {
/**
* Contains the message to use.
*
* @since v1-alpha0
*/
@NotNull
private final String message;
public final class EngineVersionCodename implements Placeholder {
/**
* Creates and initializes an instance of this event.
*
* @param message message to use
* @since v1-alpha0
* @since v1-alpha8
*/
public CrashMessage(@NotNull String message) {
this.message = message;
}
public EngineVersionCodename() {}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%crash_message%", message);
return text.replace("%engine_version_codename%", EngineInformation.getVersioningCodename());
}
}

View file

@ -20,7 +20,7 @@
package de.staropensource.engine.base.internal.implementation.placeholder;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.utility.Math;
import de.staropensource.engine.base.utility.misc.NumberUtil;
import org.jetbrains.annotations.NotNull;
/**
@ -42,6 +42,6 @@ public final class TimeEpoch implements Placeholder {
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%time_epoch%", Math.padNumbers(System.currentTimeMillis(), String.valueOf(Long.MAX_VALUE).length()));
return text.replace("%time_epoch%", NumberUtil.padNumbers(System.currentTimeMillis(), String.valueOf(Long.MAX_VALUE).length()));
}
}

View file

@ -20,7 +20,7 @@
package de.staropensource.engine.base.internal.implementation.placeholder;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.utility.Math;
import de.staropensource.engine.base.utility.misc.NumberUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Calendar;
@ -43,6 +43,6 @@ public final class TimeHour implements Placeholder {
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%time_hour%", Math.padNumbers(Calendar.getInstance().get(Calendar.HOUR_OF_DAY), 2));
return text.replace("%time_hour%", NumberUtil.padNumbers(Calendar.getInstance().get(Calendar.HOUR_OF_DAY), 2));
}
}

View file

@ -20,7 +20,7 @@
package de.staropensource.engine.base.internal.implementation.placeholder;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.utility.Math;
import de.staropensource.engine.base.utility.misc.NumberUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Calendar;
@ -43,6 +43,6 @@ public final class TimeMinute implements Placeholder {
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%time_minute%", Math.padNumbers(Calendar.getInstance().get(Calendar.MINUTE), 2));
return text.replace("%time_minute%", NumberUtil.padNumbers(Calendar.getInstance().get(Calendar.MINUTE), 2));
}
}

View file

@ -20,7 +20,7 @@
package de.staropensource.engine.base.internal.implementation.placeholder;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.utility.Math;
import de.staropensource.engine.base.utility.misc.NumberUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Calendar;
@ -43,6 +43,6 @@ public final class TimeSecond implements Placeholder {
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%time_second%", Math.padNumbers(Calendar.getInstance().get(Calendar.SECOND), 2));
return text.replace("%time_second%", NumberUtil.padNumbers(Calendar.getInstance().get(Calendar.SECOND), 2));
}
}

View file

@ -1,55 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.crashhandler;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code issuer_class} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class IssuerClass implements Placeholder {
/**
* Contains the issuer class to use.
*
* @since v1-alpha2
*/
private final @NotNull Class<?> issuerClass;
/**
* Creates and initializes an instance of this event.
*
* @param issuerClass issuer class to use
* @since v1-alpha0
*/
public IssuerClass(@NotNull Class<?> issuerClass) {
this.issuerClass = issuerClass;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%issuer_class%", issuerClass.getName().replace(issuerClass.getPackageName() + ".", ""));
}
}

View file

@ -1,61 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.crashhandler;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Implements the {@code issuer_metadata} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class IssuerMetadata implements Placeholder {
/**
* Contains the issuer metadata to use.
*
* @since v1-alpha0
*/
private final @Nullable String issuerMetadata;
/**
* Creates and initializes an instance of this event.
*
* @param issuerMetadata issuer metadata to use
* @since v1-alpha0
*/
public IssuerMetadata(@Nullable String issuerMetadata) {
this.issuerMetadata = issuerMetadata;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
String replacement = "\\<none>";
if (issuerMetadata != null)
replacement = issuerMetadata;
return text.replace("%issuer_metadata%", replacement);
}
}

View file

@ -1,57 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.crashhandler;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
import java.util.Locale;
/**
* Implements the {@code issuer_origin} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class IssuerOrigin implements Placeholder {
/**
* Contains the issuer origin to use.
*
* @since v1-alpha2
*/
private final @NotNull String issuerOrigin;
/**
* Creates and initializes an instance of this event.
*
* @param issuerOrigin issuer origin to use
* @since v1-alpha0
*/
public IssuerOrigin(@NotNull String issuerOrigin) {
this.issuerOrigin = issuerOrigin;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%issuer_origin%", issuerOrigin.toUpperCase(Locale.ROOT));
}
}

View file

@ -1,55 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.crashhandler;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code issuer_package} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class IssuerPackage implements Placeholder {
/**
* Contains the issuer class to use.
*
* @since v1-alpha2
*/
private final @NotNull Class<?> issuerClass;
/**
* Creates and initializes an instance of this event.
*
* @param issuerClass issuer class to use
* @since v1-alpha0
*/
public IssuerPackage(@NotNull Class<?> issuerClass) {
this.issuerClass = issuerClass;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%issuer_package%", issuerClass.getPackageName());
}
}

View file

@ -1,55 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.crashhandler;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code issuer_path} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class IssuerPath implements Placeholder {
/**
* Contains the issuer class to use.
*
* @since v1-alpha2
*/
private final @NotNull Class<?> issuerClass;
/**
* Creates and initializes an instance of this event.
*
* @param issuerClass issuer class to use
* @since v1-alpha0
*/
public IssuerPath(@NotNull Class<?> issuerClass) {
this.issuerClass = issuerClass;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%issuer_path%", issuerClass.getName());
}
}

View file

@ -1,101 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.crashhandler;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.utility.Miscellaneous;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.InvocationTargetException;
/**
* Implements the {@code stacktrace} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class Stacktrace implements Placeholder {
/**
* Contains the {@link Throwable} to use.
*
* @since v1-alpha0
*/
private final @Nullable Throwable throwable;
/**
* Creates and initializes an instance of this event.
*
* @param throwable {@link Throwable} to use
* @since v1-alpha0
*/
public Stacktrace(@Nullable Throwable throwable) {
this.throwable = throwable;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%stacktrace%", throwable == null ? "No stack trace is available." : getFullStackTrace(throwable));
}
/**
* Returns the full stack trace.
*
* @param throwable throwable get the full stack trace of
* @return full stack trace
* @since v1-alpha2
*/
@NotNull
private static String getFullStackTrace(@NotNull Throwable throwable) {
return getFullStackTrace(throwable, new StringBuilder());
}
/**
* Returns the full stack trace.
*
* @param throwable throwable to operate on
* @param stacktrace stacktrace to append and return
* @return full stack trace
* @since v1-alpha2
*/
@NotNull
private static String getFullStackTrace(@NotNull Throwable throwable, @NotNull StringBuilder stacktrace) {
// Add newline
if (!stacktrace.isEmpty())
stacktrace.append("\n");
// Append stack trace
stacktrace
.append(Miscellaneous.getStackTraceHeader(throwable))
.append("\n")
.append(Miscellaneous.getStackTraceAsString(throwable, true));
// Handle throwables which contain other throwables
if (throwable instanceof InvocationTargetException invocationTargetException)
getFullStackTrace(invocationTargetException.getTargetException(), stacktrace);
// Return stack trace
return stacktrace
.toString()
.replace("<", "\\<");
}
}

View file

@ -1,71 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.crashhandler;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.utility.Miscellaneous;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
/**
* Implements the {@code stacktrace_all} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class StacktraceAll implements Placeholder {
/**
* Creates and initializes an instance of this event.
*
* @since v1-alpha2
*/
public StacktraceAll() {}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
StringBuilder output = new StringBuilder();
Map<Thread, StackTraceElement[]> stacktraces = Thread.getAllStackTraces();
for (Thread thread : stacktraces.keySet()) {
if (!output.isEmpty())
output.append("\n\n");
output
.append(thread.getName())
.append(" (id=")
.append(thread.threadId())
.append(" priority=")
.append(thread.getPriority())
.append(" group=")
.append(thread.getThreadGroup() == null ? "<unknown>" : thread.getThreadGroup().getName())
.append(" state=")
.append(thread.getState().name())
.append(" daemon=")
.append(thread.isDaemon())
.append(")")
.append("\n")
.append(Miscellaneous.getStackTraceAsString(stacktraces.get(thread), false));
}
return text.replace("%stacktrace_all%", output.toString().replace("<", "\\<"));
}
}

View file

@ -1,26 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* Placeholders used in the {@link de.staropensource.engine.base.logging.CrashHandler}.
*
* @see de.staropensource.engine.base.logging.CrashHandler
* @since v1-alpha0
*/
package de.staropensource.engine.base.internal.implementation.placeholder.crashhandler;

View file

@ -1,55 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.logger;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code log_class} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class LogClass implements Placeholder {
/**
* Contains the issuer class to use.
*
* @since v1-alpha0
*/
private final @NotNull Class<?> issuerClass;
/**
* Creates and initializes an instance of this event.
*
* @param issuerClass issuer class to use
* @since v1-alpha0
*/
public LogClass(@NotNull Class<?> issuerClass) {
this.issuerClass = issuerClass;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%log_class%", issuerClass.getName().replace(issuerClass.getPackageName() + ".", ""));
}
}

View file

@ -1,68 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.logger;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.type.logging.LogLevel;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code log_color_primary} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class LogColorPrimary implements Placeholder {
/**
* Contains the {@link LogLevel} to use.
*
* @since v1-alpha0
*/
@NotNull
private final LogLevel level;
/**
* Creates and initializes an instance of this event.
*
* @param level {@link LogLevel} to use
* @since v1-alpha0
*/
public LogColorPrimary(@NotNull LogLevel level) {
this.level = level;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
String color;
switch (level) {
case DIAGNOSTIC, VERBOSE -> color = "<fg:blue>";
case SILENT_WARNING, WARNING -> color = "<fg:yellow>";
case INFORMATIONAL -> color = "<fg:white>";
case ERROR -> color = "<fg:red>";
case CRASH -> color = "You should not be seeing this";
default -> color = "";
}
return text.replace("%log_color_primary%", color);
}
}

View file

@ -1,64 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.logger;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.type.logging.LogLevel;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code log_color_secondary} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class LogColorSecondary implements Placeholder {
/**
* Contains the {@link LogLevel} to use.
*
* @since v1-alpha0
*/
@NotNull
private final LogLevel level;
/**
* Creates and initializes an instance of this event.
*
* @param level {@link LogLevel} to use
* @since v1-alpha0
*/
public LogColorSecondary(@NotNull LogLevel level) {
this.level = level;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
String color;
switch (level) {
case DIAGNOSTIC, SILENT_WARNING -> color = "<italic>";
default -> color = "";
}
return text.replace("%log_color_secondary%", color);
}
}

View file

@ -1,66 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.logger;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.type.logging.LogLevel;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code log_level} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class LogLevelEvent implements Placeholder {
/**
* Contains the {@link LogLevel} to use.
*
* @since v1-alpha0
*/
@NotNull
private final LogLevel level;
/**
* Creates and initializes an instance of this event.
*
* @param level {@link LogLevel} to use
* @since v1-alpha0
*/
public LogLevelEvent(@NotNull LogLevel level) {
this.level = level;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
String levelText;
switch (level) {
case CRASH -> levelText = "CRSH";
case ERROR -> levelText = "ERR!";
case SILENT_WARNING -> levelText = "SARN";
default -> levelText = level.name().substring(0, 4);
}
return text.replace("%log_level%", levelText);
}
}

View file

@ -1,61 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.logger;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Implements the {@code log_metadata} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class LogMetadata implements Placeholder {
/**
* Contains the issuer metadata to use
*
* @since v1-alpha0
*/
private final @Nullable String issuerMetadata;
/**
* Creates and initializes an instance of this event.
*
* @param issuerMetadata issuer metadata to use
* @since v1-alpha0
*/
public LogMetadata(@Nullable String issuerMetadata) {
this.issuerMetadata = issuerMetadata;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
String replacement = "";
if (issuerMetadata != null && !issuerMetadata.isEmpty())
replacement = "/" + issuerMetadata;
return text.replace("%log_metadata%", replacement);
}
}

View file

@ -1,57 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.logger;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
import java.util.Locale;
/**
* Implements the {@code log_origin} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class LogOrigin implements Placeholder {
/**
* Contains the issuer origin to use.
*
* @since v1-alpha0
*/
private final @NotNull String issuerOrigin;
/**
* Creates and initializes an instance of this event.
*
* @param issuerOrigin issuer origin to use
* @since v1-alpha0
*/
public LogOrigin(@NotNull String issuerOrigin) {
this.issuerOrigin = issuerOrigin;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%log_origin%", issuerOrigin.toUpperCase(Locale.ROOT));
}
}

View file

@ -1,55 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.logger;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code log_package} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class LogPackage implements Placeholder {
/**
* Contains the issuer class to use.
*
* @since v1-alpha0
*/
private final @NotNull Class<?> issuerClass;
/**
* Creates and initializes an instance of this event.
*
* @param issuerClass issuer class to use
* @since v1-alpha0
*/
public LogPackage(@NotNull Class<?> issuerClass) {
this.issuerClass = issuerClass;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%log_package%", issuerClass.getPackageName());
}
}

View file

@ -1,56 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.logger;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code log_path} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class LogPath implements Placeholder {
/**
* Contains the issuer class to use.
*
* @since v1-alpha0
*/
@NotNull
private final Class<?> issuerClass;
/**
* Creates and initializes an instance of this event.
*
* @param issuerClass issuer class to use
* @since v1-alpha0
*/
public LogPath(@NotNull Class<?> issuerClass) {
this.issuerClass = issuerClass;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%log_path%", issuerClass.getName());
}
}

View file

@ -1,26 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* Placeholders used in the {@link de.staropensource.engine.base.logging.Logger}.
*
* @see de.staropensource.engine.base.logging.Logger
* @since v1-alpha0
*/
package de.staropensource.engine.base.internal.implementation.placeholder.logger;

View file

@ -17,27 +17,27 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.type.logging;
package de.staropensource.engine.base.internal.type;
import de.staropensource.engine.base.logging.backend.async.LoggingThread;
import de.staropensource.engine.base.type.logging.LogLevel;
import org.jetbrains.annotations.NotNull;
/**
* Used for determining if a {@link LogRule} should allow (whitelist) or prevent (blacklist) log call processing.
* Represents a queued log call.
*
* @since v1-alpha1
* @param level level of the log call
* @param issuer {@link StackTraceElement} of the issuer
* @param message message
* @see LoggingThread
* @since v1-alpha8
*/
public enum LogRuleType {
@SuppressWarnings({ "unused" })
public record QueuedLogCall(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message) {
/**
* Indicates that log calls matching this rule will always be allowed, even if blacklisted.
* Creates and initializes an instance of this class.
*
* @see #BLACKLIST
* @since v1-alpha1
* @since v1-alpha8
*/
WHITELIST,
/**
* Indicates that log calls matching this will always be disallowed except when whitelisted.
*
* @see #WHITELIST
* @since v1-alpha1
*/
BLACKLIST
public QueuedLogCall {}
}

View file

@ -1,51 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.type;
import de.staropensource.engine.base.logging.LoggingThread;
import de.staropensource.engine.base.type.logging.LogLevel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Represents a queued log message.
*
* @param level Level of the log call.
* @param issuerClass Class of the issuer.
* @param issuerOrigin Origin of the issuer.
* @param issuerMetadata Metadata about the issuer.
* @param message Message of the log call.
* @see LoggingThread#startThread()
* @since v1-alpha1
*/
@SuppressWarnings({ "unused" })
public record QueuedLogMessage(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
/**
* Creates and initializes an instance of this class.
*
* @param level level
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha1
*/
public QueuedLogMessage {}
}

View file

@ -1,280 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.logging;
import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.event.EngineCrashEvent;
import de.staropensource.engine.base.event.EngineSoftCrashEvent;
import de.staropensource.engine.base.internal.implementation.placeholder.crashhandler.*;
import de.staropensource.engine.base.type.EngineState;
import de.staropensource.engine.base.type.logging.LogLevel;
import de.staropensource.engine.base.utility.PlaceholderEngine;
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
/**
* Handles engine and application crashes.
*
* @see Logger
* @see LoggerInstance
* @since v1-alpha0
*/
@SuppressWarnings({ "JavadocDeclaration" })
public final class CrashHandler {
/**
* Contains the template used to print a crash report.
*
* @since v1-alpha0
* -- GETTER --
* Gets the template used to print a crash report.
*
* @return crash report template
* @since v1-alpha0
* -- SETTER --
* Sets the template used to print a crash report.
*
* @param crashTemplate new crash template
* @since v1-alpha0
*/
@Getter
@Setter
private static @NotNull String crashTemplate = """
<fg:red><bold>
%handled%
------------------------
sos!engine crash
------------------------
Dear user: The application or game you've tried to use seems to have made an oopsie. Please report this to the developer so they can fix it! Thank you \\<3
Dear developer: FIX YOUR GODDAMN SHIT! Please check if your code or 3rd party subsystems are causing problems.
If not, please report it at https://git.staropensource.de/StarOpenSource/Engine/issues. Thank you \\<3
%content%
Dear user: The application or game you've tried to use seems to have made an oopsie. Please report this to the developer so they can fix it! Thank you \\<3
Dear developer: FIX YOUR GODDAMN SHIT! Please check if your code or 3rd party subsystems are causing problems.
If not, please report it at https://git.staropensource.de/StarOpenSource/Engine/issues. Thank you \\<3
------------------------
sos!engine crash
------------------------
%handled%<reset>
""";
/**
* Contains nested {@link LinkedHashMap}s that contain the content printed at the time of a crash.
*
* @since v1-alpha0
* -- GETTER --
* Returns the nested {@link LinkedHashMap}s that contain the content printed at the time of a crash.
*
* @return crash content
* @since v1-alpha0
*/
@Getter
private static final @NotNull LinkedHashMap<@NotNull Object, @NotNull Object> crashContent = new LinkedHashMap<>();
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha6
*/
private CrashHandler() {}
/**
* Handles a crash.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message crash error detail
* @param throwable simply to provide stacktrace and further insight into the crash, can be set to {@code null}
* @param throwableHandled declares the throwable has handled, not causing the engine to shutdown
* @since v1-alpha0
*/
public static synchronized void handleCrash(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @Nullable Throwable throwable, boolean throwableHandled) {
Engine.getInstance().setState(EngineState.CRASHED); // Update engine state
// Prevent throwable handled warning if set to true but no throwable has been supplied
if (throwable == null)
throwableHandled = false;
// Escape message
message = message
.replace("\n", "\n ")
.replace("\\", "\\\\")
.replace("<", "\\<");
// Replace %content% and %handled%
String base = crashTemplate
.replace("%content%", processCrashContent())
.replace("%handled%", throwableHandled ? "!!! This throwable is declared as handled and has been passed down the execution chain !!!" : "");
// Invoke LoggingAdapter#prePlaceholder
String temp = Logger.getLoggingAdapter().prePlaceholder(LogLevel.CRASH, issuerClass, issuerOrigin, issuerMetadata, message, base);
if (temp != null)
base = temp;
// Create list of temporary placeholders
List<@NotNull Placeholder> temporaryPlaceholders = new ArrayList<>();
temporaryPlaceholders.add(new CrashMessage(message)); // log_message is out of order to allow for placeholder usage
// issuer_*
temporaryPlaceholders.add(new IssuerClass(issuerClass));
temporaryPlaceholders.add(new IssuerOrigin(issuerOrigin));
temporaryPlaceholders.add(new IssuerMetadata(issuerMetadata));
temporaryPlaceholders.add(new IssuerPackage(issuerClass));
temporaryPlaceholders.add(new IssuerPath(issuerClass));
// stacktrace*
temporaryPlaceholders.add(new Stacktrace(throwable));
temporaryPlaceholders.add(new StacktraceAll());
// Replace placeholders
base = PlaceholderEngine.getInstance().process(base, temporaryPlaceholders);
// Invoke LoggingAdapter#postPlaceholder
base = Logger.getLoggingAdapter().postPlaceholder(LogLevel.CRASH, issuerClass, issuerOrigin, issuerMetadata, message, base);
// Print log message by invoking LoggingAdapter#print
Logger.flushLogMessages();
Logger.getLoggingAdapter().print(LogLevel.CRASH, issuerClass, issuerOrigin, issuerMetadata, message, base);
// Emit event
if (throwableHandled)
new EngineSoftCrashEvent().callEvent();
else
new EngineCrashEvent().callEvent();
// Shutdown engine/JVM
if (!throwableHandled)
if (EngineConfiguration.getInstance().isLoggerImmediateShutdown()) {
System.out.println("Halting JVM");
Runtime.getRuntime().halt(69);
} else
Engine.getInstance().shutdown(69);
}
/**
* Internal method for generating the crash message content. Do not call.
*
* @param map {@link LinkedHashMap} to process
* @param indentationSize indentation level
* @return crash content string
* @see #processCrashContent()
* @since v1-alpha0
*/
/*
* Note: This entire method causes a compilation warning as we are using "unchecked or unsecure operations".
* We can safely ignore this as this method
* 1. checks data types before using them,
* 2. only works on Strings, Lists and LinkedHashMaps and not on Files or something which could cause damage, and
* 3. we can trust our own engine and possibly subsystems not doing shit in here.
* As a subsystem developer you'll likely want useful crash information.
*
* But hey, if someone breaks this method (which may be possible idk didn't test it) then congrats!
*/
private static @NotNull String processCrashContent(@NotNull LinkedHashMap<Object, Object> map, int indentationSize) {
StringBuilder content = new StringBuilder();
for (Object key : map.keySet()) {
// Ensure key is of type String
if (!(key instanceof String))
continue;
// Ensure value is of type String, List or LinkedHashMap
if (!(map.get(key) instanceof String
|| map.get(key) instanceof List<?>
|| map.get(key) instanceof LinkedHashMap<?, ?>))
// Invalid content value, skip
continue;
// Add newline
if (!content.isEmpty())
content.append("\n");
// Indent key
if (indentationSize == 0)
content.append("\n");
else
content
.append(" ".repeat(indentationSize))
.append("-> ");
if (map.get(key) == null)
// Append key name, there's no content
// Format: %key%
content.append(key);
else if (map.get(key) instanceof String)
// Append key and it's value
// Format: %key%: %value%
content
.append(key)
.append(": ")
.append(map.get(key));
else if (map.get(key) instanceof List<?>) {
// Append key and list the list's contents
content.append(key);
for (Object item : (List<?>) map.get(key)) {
if (item instanceof String)
item = ((String) item)
.replace("\\", "\\\\")
.replace("\n", "\\n")
.replace("\"", "\\\"");
content
.append("\n")
.append(" ".repeat(indentationSize))
.append(" -> ")
.append(item);
}
} else
// So this one processes a map recursively
// Format:
// -> %parent_key%
// -> %child_key0%: %child_value0%
// -> %child_key1%
// -> %nested_key0%: %nested_value0%
// -> %nested_key1%: %nested_value1%
// -> %child_key2%: %child_value1%
//noinspection unchecked
content.append(key).append("\n").append(processCrashContent((LinkedHashMap<Object, Object>) map.get(key), indentationSize + 1));
}
return content.toString();
}
/**
* Generates the content for a crash report. Processes {@code crashContent} and spits out a String.
*
* @return crash content string
* @since v1-alpha0
*/
public static String processCrashContent() {
return processCrashContent(crashContent, 0);
}
}

View file

@ -1,201 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.logging;
import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.internal.implementation.placeholder.logger.LogLevelEvent;
import de.staropensource.engine.base.internal.implementation.placeholder.logger.LogPath;
import de.staropensource.engine.base.type.logging.LogLevel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Provides logging capabilities during engine startup.
*
* @since v1-alpha4
*/
public final class InitLogger {
/**
* Contains the logging template used during startup.
*
* @since v1-alpha4
*/
private static final @NotNull String template = "%log_level% %log_path% %log_message%";
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha6
*/
private InitLogger() {}
/**
* {@link Logger#log(LogLevel, Class, String, String, String)} and {@link Logger#processLogMessage(LogLevel, Class, String, String, String)} combined into one method.
*
* @param level level
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha4
*/
private static synchronized void log(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
// Dismiss if level is not allowed
if ((EngineConfiguration.getInstance() != null && level.compareTo(EngineConfiguration.getInstance().getLoggerLevel()) < 0) || level.compareTo(LogLevel.INFORMATIONAL) < 0)
return;
// Invoke LoggingAdapter#prePlaceholder
String base = Logger.getLoggingAdapter().prePlaceholder(level, issuerClass, issuerOrigin, issuerMetadata, message, template);
if (base == null)
base = template;
// Replace placeholders
// This is done manually to avoid depending on PlaceholderEngine
base = new LogLevelEvent(level).replace(base);
base = new LogPath(issuerClass).replace(base);
base = base.replace("%log_message%", message.replace("\n", ""));
// Invoke LoggingAdapter#postPlaceholder
base = Logger.getLoggingAdapter().postPlaceholder(level, issuerClass, issuerOrigin, issuerMetadata, message, base);
// Print log message by invoking LoggingAdapter#print
Logger.getLoggingAdapter().print(level, issuerClass, issuerOrigin, issuerMetadata, message, base);
}
/**
* Prints a diagnostic message.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha4
*/
public static void diag(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
log(LogLevel.DIAGNOSTIC, issuerClass, issuerOrigin, issuerMetadata, message);
}
/**
* Prints a verbose message.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha4
*/
public static void verb(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
log(LogLevel.VERBOSE, issuerClass, issuerOrigin, issuerMetadata, message);
}
/**
* Prints a silent warning message.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha4
*/
public static void sarn(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
log(LogLevel.SILENT_WARNING, issuerClass, issuerOrigin, issuerMetadata, message);
}
/**
* Prints an informational message.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha4
*/
public static void info(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
log(LogLevel.INFORMATIONAL, issuerClass, issuerOrigin, issuerMetadata, message);
}
/**
* Prints a warning message.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha4
*/
public static void warn(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
log(LogLevel.WARNING, issuerClass, issuerOrigin, issuerMetadata, message);
}
/**
* Prints an error message.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha4
*/
public static void error(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
log(LogLevel.ERROR, issuerClass, issuerOrigin, issuerMetadata, message);
}
/**
* Crashes the entire engine.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @param throwable the throwable that caused this crash
* @param handled declares the throwable has handled, not causing the engine to shutdown
* @since v1-alpha4
*/
public static void crash(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull Throwable throwable, boolean handled) {
Logger.crash(issuerClass, issuerOrigin, issuerMetadata, message, throwable, handled);
}
/**
* Crashes the entire engine.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @param throwable the throwable that caused this crash
* @since v1-alpha4
*/
public static void crash(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull Throwable throwable) {
Logger.crash(issuerClass, issuerOrigin, issuerMetadata, message, throwable);
}
/**
* Crashes the entire engine.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha4
*/
public static void crash(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
Logger.crash(issuerClass, issuerOrigin, issuerMetadata, message);
}
}

View file

@ -19,46 +19,26 @@
package de.staropensource.engine.base.logging;
import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.event.LogEvent;
import de.staropensource.engine.base.implementable.LoggingAdapter;
import de.staropensource.engine.base.implementable.helper.EventHelper;
import de.staropensource.engine.base.implementation.logging.PlainLoggingAdapter;
import de.staropensource.engine.base.implementation.shortcode.EmptyShortcodeConverter;
import de.staropensource.engine.base.internal.implementation.placeholder.logger.*;
import de.staropensource.engine.base.internal.type.QueuedLogMessage;
import de.staropensource.engine.base.logging.backend.CrashHandler;
import de.staropensource.engine.base.logging.backend.Filterer;
import de.staropensource.engine.base.logging.backend.Processor;
import de.staropensource.engine.base.logging.backend.async.LoggingQueue;
import de.staropensource.engine.base.type.logging.LogLevel;
import de.staropensource.engine.base.type.logging.LogRule;
import de.staropensource.engine.base.type.logging.LogRuleType;
import de.staropensource.engine.base.utility.PlaceholderEngine;
import lombok.Getter;
import lombok.Setter;
import org.intellij.lang.annotations.RegExp;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
/**
* Provides the engine's logging infrastructure, except for
* crash handling, which is handled by {@link CrashHandler}.
* The frontend class for sos!engine's logging system.
*
* @see LoggerInstance
* @see CrashHandler
* @since v1-alpha0
* @since v1-alpha8
*/
@SuppressWarnings({ "JavadocDeclaration" })
public final class Logger {
/**
* Contains a list of {@link QueuedLogMessage}s.
*
* @since v1-alpha1
*/
private static final LinkedList<QueuedLogMessage> queuedMessages = new LinkedList<>();
/**
* Refers to the active {@link LoggingAdapter} that is used to process and print log messages.
*
@ -82,286 +62,350 @@ public final class Logger {
private static @NotNull LoggingAdapter loggingAdapter = new PlainLoggingAdapter();
/**
* Contains all active {@link LogRule}s.
* Creates and initializes an instance of this class
*
* @since v1-alpha1
* -- GETTER --
* Returns all active {@link LogRule}s.
*
* @return active rules
* @since v1-alpha1
*/
@Getter
private static final List<LogRule> activeRules = new ArrayList<>();
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha6
* @since v1-alpha8
*/
private Logger() {}
// -----> Internal management methods
// These methods forward calls to internal methods so
// these can be accessed without exporting a whole package.
/**
* Prints all queued log messages.
* Handles incoming log calls and either
* processes them directly or queues them in.
* <p>
* **This is an internal method. Use with care.**
*
* @since v1-alpha1
* @param level level of the log call
* @param issuer {@link StackTraceElement} of the issuer
* @param message message
* @since v1-alpha8
*/
public static synchronized void flushLogMessages() {
// Only execute code if queued messages list is not empty
if (!queuedMessages.isEmpty()) {
// Clone queued messages and clear original to avoid issues
//noinspection unchecked
LinkedList<QueuedLogMessage> queuedMessagesCloned = (LinkedList<QueuedLogMessage>) queuedMessages.clone();
queuedMessages.clear();
// Invoke processLogMessage method for every queued message
for (QueuedLogMessage queuedLogMessage : queuedMessagesCloned) {
processLogMessage(queuedLogMessage.level(), queuedLogMessage.issuerClass(), queuedLogMessage.issuerOrigin(), queuedLogMessage.issuerMetadata(), queuedLogMessage.message());
}
}
public static void handle(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message) {
Processor.handle(level, issuer, message);
}
/**
* Processes a log message.
* Flushes the logging queue.
* <p>
* **This is an internal method. Use with care.**
*
* @param level level
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha1
* @since v1-alpha8
*/
private static void processLogMessage(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
// Evaluate active rules
for (LogRule rule : activeRules) {
if (rule.evaluate(level, issuerClass, issuerOrigin, issuerMetadata, message)) {
if (rule.getType() == LogRuleType.WHITELIST) break; // Continue processing
if (rule.getType() == LogRuleType.BLACKLIST) return; // Cancel processing
}
}
// Invoke LoggingAdapter#prePlaceholder
String format = loggingAdapter.prePlaceholder(level, issuerClass, issuerOrigin, issuerMetadata, message, EngineConfiguration.getInstance().getLoggerTemplate());
if (format == null)
format = EngineConfiguration.getInstance().getLoggerTemplate();
// Replace placeholders using PlaceholderEngine
format = PlaceholderEngine.getInstance().process(format);
// Replace logger placeholders (no colors)
format = new LogClass(issuerClass).replace(format);
format = new LogLevelEvent(level).replace(format);
format = new LogMetadata(issuerMetadata).replace(format);
format = new LogOrigin(issuerOrigin).replace(format);
format = new LogPackage(issuerClass).replace(format);
format = new LogPath(issuerClass).replace(format);
// Handle newlines
if (EngineConfiguration.getInstance().isLoggerEnableNewlineSupport() && message.contains("\n"))
try (Scanner scanner = new Scanner(message)) {
int indexPrefix = format.indexOf("%log_message_prefix%");
int indexMessage = format.indexOf("%log_message%");
StringBuilder formatNew = new StringBuilder();
String prefix;
String suffix;
String formatShadow;
if (indexMessage == -1)
crash(Logger.class, "ENGINE", null, "The log format must contain %log_message%");
prefix = indexPrefix == -1 ? "" : format.substring(indexPrefix + 20, indexMessage);
suffix = format.substring(indexMessage + 13);
formatShadow = " "
.repeat(new EmptyShortcodeConverter(
format.substring(0, indexPrefix == -1 ? indexMessage : indexPrefix)
.replace("%log_color_primary%", "")
.replace("%log_color_secondary%", ""), false
).getClean().length());
while (scanner.hasNextLine()) {
if (formatNew.isEmpty())
formatNew.append(format, 0, indexPrefix == -1 ? indexMessage : indexPrefix);
else
formatNew
.append("\n")
.append(formatShadow);
formatNew
.append(prefix)
.append(scanner.nextLine())
.append(suffix);
}
format = formatNew.toString();
}
else
// No newline found, use performance-efficient replacing
format = format
.replace("%log_message_prefix%", "")
.replace("%log_message%", message.replace("\n", "\\n"));
// Replace placeholders involving colors
format = new LogColorPrimary(level).replace(format);
format = new LogColorSecondary(level).replace(format);
// Replace placeholders using PlaceholderEngine again
format = PlaceholderEngine.getInstance().process(format);
// Invoke LoggingAdapter#postPlaceholder
format = loggingAdapter.postPlaceholder(level, issuerClass, issuerOrigin, issuerMetadata, message, format);
// Call event
if (!(issuerClass.getName().equals("de.staropensource.engine.slf4j_compat.CompatibilityLogger")
|| issuerClass.equals(EventHelper.class)))
new LogEvent().callEvent(level, issuerClass, issuerOrigin, issuerMetadata, message);
// Print log message by invoking LoggingAdapter#print
loggingAdapter.print(level, issuerClass, issuerOrigin, issuerMetadata, message, format);
public static void flush() {
LoggingQueue.flush();
}
/**
* Handler for all log messages.
* Disallows one or multiple classes.
*
* @param level level
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha0
* @param regex regex
* @since v1-alpha8
*/
private static synchronized void log(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
// Check if engine has initialized
if (Engine.getInstance() == null) return;
// Dismiss if level is not allowed
if (level.compareTo(EngineConfiguration.getInstance().getLoggerLevel()) < 0)
return;
if (EngineConfiguration.getInstance().isOptimizeLogging())
// Optimizations enabled, add to message queue
queuedMessages.add(new QueuedLogMessage(level, issuerClass, issuerOrigin, issuerMetadata, message));
else
// Optimizations disabled, print right away
processLogMessage(level, issuerClass, issuerOrigin, issuerMetadata, message);
public static void disallowClass(@RegExp @NotNull String regex) {
Filterer.disallowClass(regex);
}
/**
* Disallows one or multiple modules.
*
* @param regex regex
* @since v1-alpha8
*/
public static void disallowModule(@RegExp @NotNull String regex) {
Filterer.disallowModule(regex);
}
/**
* Disallows one or multiple messages.
*
* @param regex regex
* @since v1-alpha8
*/
public static void disallowMessage(@RegExp @NotNull String regex) {
Filterer.disallowMessage(regex);
}
// -----> Redirection methods
/**
* Redirects regular log messages.
*
* @param level level of the log call
* @param message message
* @since v1-alpha8
*/
public static void redirectCall(@NotNull LogLevel level, @NotNull String message) {
Processor.handle(level, Thread.currentThread().getStackTrace()[3], message);
}
/**
* Redirects crash calls.
*
* @param message message
* @param throwable {@link Throwable} which caused the error
* @param fatal if to terminate the engine
* @since v1-alpha8
*/
public static void redirectCall(@NotNull String message, @Nullable Throwable throwable, boolean fatal) {
CrashHandler.handleCrash(Thread.currentThread().getStackTrace()[3], message, throwable, fatal);
}
// -----> Frontend methods
/**
* Logs a diagnostic message.
*
* @param message message to log
* @since v1-alpha8
*/
public static void diag(@NotNull String message) {
redirectCall(LogLevel.DIAGNOSTIC, message);
}
/**
* Logs a verbose message.
*
* @param message message to log
* @since v1-alpha8
*/
public static void verb(@NotNull String message) {
redirectCall(LogLevel.VERBOSE, message);
}
/**
* Logs a silent warning.
*
* @param message message to log
* @since v1-alpha8
*/
public static void sarn(@NotNull String message) {
redirectCall(LogLevel.SILENT_WARNING, message);
}
/**
* Logs an informational message.
*
* @param message message to log
* @since v1-alpha8
*/
public static void info(@NotNull String message) {
redirectCall(LogLevel.INFORMATIONAL, message);
}
/**
* Logs a warning.
*
* @param message message to log
* @since v1-alpha8
*/
public static void warn(@NotNull String message) {
redirectCall(LogLevel.WARNING, message);
}
/**
* Logs an error.
*
* @param message message to log
* @since v1-alpha8
*/
public static void error(@NotNull String message) {
redirectCall(LogLevel.ERROR, message);
}
/**
* Prints a crash report and optionally crashes the engine.
*
* @param message message to log
* @param throwable {@link Throwable} which caused the crash
* @param fatal terminates the engine if {@code true}
* @since v1-alpha8
*/
public static void crash(@NotNull String message, @NotNull Throwable throwable, boolean fatal) {
redirectCall(message, throwable, fatal);
}
/**
* Prints a crash report and optionally crashes the engine.
*
* @param message message to log
* @param throwable {@link Throwable} which caused the crash
* @since v1-alpha8
*/
public static void crash(@NotNull String message, @NotNull Throwable throwable) {
redirectCall(message, throwable, true);
}
/**
* Prints a crash report and optionally crashes the engine.
*
* @param message message to log
* @param fatal terminates the engine if {@code true}
* @since v1-alpha8
*/
public static void crash(@NotNull String message, boolean fatal) {
redirectCall(message, null, fatal);
}
/**
* Prints a crash report and optionally crashes the engine.
*
* @param message message to log
* @since v1-alpha8
*/
public static void crash(@NotNull String message) {
redirectCall(message, null, true);
}
// -----> Legacy frontend methods
// This improves compatibility with old code
// still using the old logger frontend.
/**
* Prints a diagnostic message.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @param ignoredIssuerClass class of the issuer
* @param ignoredIssuerOrigin origin of the issuer
* @param ignoredIssuerMetadata metadata about the issuer
* @param message message
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see #diag(String)
* @since v1-alpha0
*/
public static void diag(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
log(LogLevel.DIAGNOSTIC, issuerClass, issuerOrigin, issuerMetadata, message);
@Deprecated(forRemoval = true)
public static void diag(@NotNull Class<?> ignoredIssuerClass, @NotNull String ignoredIssuerOrigin, @Nullable String ignoredIssuerMetadata, @NotNull String message) {
redirectCall(LogLevel.DIAGNOSTIC, message);
}
/**
* Prints a verbose message.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @param ignoredIssuerClass class of the issuer
* @param ignoredIssuerOrigin origin of the issuer
* @param ignoredIssuerMetadata metadata about the issuer
* @param message message
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see #verb(String)
* @since v1-alpha0
*/
public static void verb(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
log(LogLevel.VERBOSE, issuerClass, issuerOrigin, issuerMetadata, message);
@Deprecated(forRemoval = true)
public static void verb(@NotNull Class<?> ignoredIssuerClass, @NotNull String ignoredIssuerOrigin, @Nullable String ignoredIssuerMetadata, @NotNull String message) {
redirectCall(LogLevel.VERBOSE, message);
}
/**
* Prints a silent warning message.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @param ignoredIssuerClass class of the issuer
* @param ignoredIssuerOrigin origin of the issuer
* @param ignoredIssuerMetadata metadata about the issuer
* @param message message
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see #sarn(String)
* @since v1-alpha0
*/
public static void sarn(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
log(LogLevel.SILENT_WARNING, issuerClass, issuerOrigin, issuerMetadata, message);
@Deprecated(forRemoval = true)
public static void sarn(@NotNull Class<?> ignoredIssuerClass, @NotNull String ignoredIssuerOrigin, @Nullable String ignoredIssuerMetadata, @NotNull String message) {
redirectCall(LogLevel.SILENT_WARNING, message);
}
/**
* Prints an informational message.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @param ignoredIssuerClass class of the issuer
* @param ignoredIssuerOrigin origin of the issuer
* @param ignoredIssuerMetadata metadata about the issuer
* @param message message
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see #info(String)
* @since v1-alpha0
*/
public static void info(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
log(LogLevel.INFORMATIONAL, issuerClass, issuerOrigin, issuerMetadata, message);
@Deprecated(forRemoval = true)
public static void info(@NotNull Class<?> ignoredIssuerClass, @NotNull String ignoredIssuerOrigin, @Nullable String ignoredIssuerMetadata, @NotNull String message) {
redirectCall(LogLevel.INFORMATIONAL, message);
}
/**
* Prints a warning message.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @param ignoredIssuerClass class of the issuer
* @param ignoredIssuerOrigin origin of the issuer
* @param ignoredIssuerMetadata metadata about the issuer
* @param message message
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see #warn(String)
* @since v1-alpha0
*/
public static void warn(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
log(LogLevel.WARNING, issuerClass, issuerOrigin, issuerMetadata, message);
@Deprecated(forRemoval = true)
public static void warn(@NotNull Class<?> ignoredIssuerClass, @NotNull String ignoredIssuerOrigin, @Nullable String ignoredIssuerMetadata, @NotNull String message) {
redirectCall(LogLevel.WARNING, message);
}
/**
* Prints an error message.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @param ignoredIssuerClass class of the issuer
* @param ignoredIssuerOrigin origin of the issuer
* @param ignoredIssuerMetadata metadata about the issuer
* @param message message
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see #error(String)
* @since v1-alpha0
*/
public static void error(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
log(LogLevel.ERROR, issuerClass, issuerOrigin, issuerMetadata, message);
@Deprecated(forRemoval = true)
public static void error(@NotNull Class<?> ignoredIssuerClass, @NotNull String ignoredIssuerOrigin, @Nullable String ignoredIssuerMetadata, @NotNull String message) {
redirectCall(LogLevel.ERROR, message);
}
/**
* Crashes the entire engine.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @param throwable the throwable that caused this crash
* @param handled declares the throwable has handled, not causing the engine to shutdown
* @param ignoredIssuerClass class of the issuer
* @param ignoredIssuerOrigin origin of the issuer
* @param ignoredIssuerMetadata metadata about the issuer
* @param message message
* @param throwable the throwable that caused this crash
* @param handled declares the throwable has handled, not causing the engine to shutdown
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see #crash(String, Throwable, boolean)
* @since v1-alpha0
*/
public static void crash(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull Throwable throwable, boolean handled) {
CrashHandler.handleCrash(issuerClass, issuerOrigin, issuerMetadata, message, throwable, handled);
@Deprecated(forRemoval = true)
public static void crash(@NotNull Class<?> ignoredIssuerClass, @NotNull String ignoredIssuerOrigin, @Nullable String ignoredIssuerMetadata, @NotNull String message, @NotNull Throwable throwable, boolean handled) {
redirectCall(message, throwable, !handled);
}
/**
* Crashes the entire engine.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @param throwable the throwable that caused this crash
* @param ignoredIssuerClass class of the issuer
* @param ignoredIssuerOrigin origin of the issuer
* @param ignoredIssuerMetadata metadata about the issuer
* @param message message
* @param throwable the throwable that caused this crash
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see #crash(String, Throwable)
* @since v1-alpha0
*/
public static void crash(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull Throwable throwable) {
CrashHandler.handleCrash(issuerClass, issuerOrigin, issuerMetadata, message, throwable, false);
@Deprecated(forRemoval = true)
public static void crash(@NotNull Class<?> ignoredIssuerClass, @NotNull String ignoredIssuerOrigin, @Nullable String ignoredIssuerMetadata, @NotNull String message, @NotNull Throwable throwable) {
redirectCall(message, throwable, true);
}
/**
* Crashes the entire engine.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @param ignoredIssuerClass class of the issuer
* @param ignoredIssuerOrigin origin of the issuer
* @param ignoredIssuerMetadata metadata about the issuer
* @param message message
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see #crash(String)
* @since v1-alpha0
*/
public static void crash(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
CrashHandler.handleCrash(issuerClass, issuerOrigin, issuerMetadata, message, null, false);
@Deprecated(forRemoval = true)
public static void crash(@NotNull Class<?> ignoredIssuerClass, @NotNull String ignoredIssuerOrigin, @Nullable String ignoredIssuerMetadata, @NotNull String message) {
redirectCall(message, null, true);
}
}

View file

@ -19,69 +19,29 @@
package de.staropensource.engine.base.logging;
import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.type.EngineState;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Removes the need to add {@code getClass} to all calls to {@link Logger}.
* Legacy frontend.
* <p>
* This improves compatibility with old code
* still using the old logger frontend.
*
* @since v1-alpha0
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see Logger
* @since v1-alpha8
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
@Deprecated(forRemoval = true)
public final class LoggerInstance {
/**
* Contains the {@link Class} of the issuer.
*
* @since v1-alpha2
* -- GETTER --
* Returns the {@link Class} of the issuer.
*
* @return class of the issuer
* @since v1-alpha2
*/
private final @NotNull Class<?> clazz;
/**
* Contains the metadata about the issuer.
*
* @since v1-alpha2
* -- GETTER --
* Returns the metadata about the issuer.
*
* @return metadata about the issuer
* @since v1-alpha2
*/
private final @Nullable String metadata;
/**
* Contains the origin of the issuer.
*
* @since v1-alpha2
* -- GETTER --
* Returns the origin of the issuer.
*
* @return origin of the issuer
* @since v1-alpha2
*/
private final @NotNull String origin;
/**
* Creates and initializes an instance of this class.
*
* @param clazz class of the issuer
* @param origin origin of the issuer
* @param metadata metadata about the issuer
* @since v1-alpha0
* @since v1-alpha8
*/
private LoggerInstance(@NotNull Class<?> clazz, @NotNull String origin, @Nullable String metadata) {
this.clazz = clazz;
this.origin = origin;
this.metadata = metadata;
}
private LoggerInstance() {}
/**
* Prints a diagnostic message.
@ -90,10 +50,7 @@ public final class LoggerInstance {
* @since v1-alpha0
*/
public void diag(@NotNull String message) {
if (Engine.getInstance().getState() == EngineState.EARLY_STARTUP)
InitLogger.diag(clazz, origin, metadata, message);
else
Logger.diag(clazz, origin, metadata, message);
Logger.diag(message);
}
/**
@ -103,10 +60,7 @@ public final class LoggerInstance {
* @since v1-alpha0
*/
public void verb(@NotNull String message) {
if (Engine.getInstance().getState() == EngineState.EARLY_STARTUP)
InitLogger.verb(clazz, origin, metadata, message);
else
Logger.verb(clazz, origin, metadata, message);
Logger.verb(message);
}
/**
@ -116,10 +70,7 @@ public final class LoggerInstance {
* @since v1-alpha0
*/
public void sarn(@NotNull String message) {
if (Engine.getInstance().getState() == EngineState.EARLY_STARTUP)
InitLogger.sarn(clazz, origin, metadata, message);
else
Logger.sarn(clazz, origin, metadata, message);
Logger.sarn(message);
}
/**
@ -129,10 +80,7 @@ public final class LoggerInstance {
* @since v1-alpha0
*/
public void info(@NotNull String message) {
if (Engine.getInstance().getState() == EngineState.EARLY_STARTUP)
InitLogger.info(clazz, origin, metadata, message);
else
Logger.info(clazz, origin, metadata, message);
Logger.info(message);
}
/**
@ -142,10 +90,7 @@ public final class LoggerInstance {
* @since v1-alpha0
*/
public void warn(@NotNull String message) {
if (Engine.getInstance().getState() == EngineState.EARLY_STARTUP)
InitLogger.warn(clazz, origin, metadata, message);
else
Logger.warn(clazz, origin, metadata, message);
Logger.warn(message);
}
/**
@ -155,10 +100,7 @@ public final class LoggerInstance {
* @since v1-alpha0
*/
public void error(@NotNull String message) {
if (Engine.getInstance().getState() == EngineState.EARLY_STARTUP)
InitLogger.error(clazz, origin, metadata, message);
else
Logger.error(clazz, origin, metadata, message);
Logger.error(message);
}
/**
@ -167,11 +109,10 @@ public final class LoggerInstance {
* @param message message
* @param throwable throwable that caused the crash
* @param handled declares the throwable has handled
* @see CrashHandler
* @since v1-alpha0
*/
public void crash(@NotNull String message, @NotNull Throwable throwable, boolean handled) {
Logger.crash(clazz, origin, metadata, message, throwable, handled);
Logger.crash(message, throwable, !handled);
}
/**
@ -179,52 +120,50 @@ public final class LoggerInstance {
*
* @param message message
* @param throwable throwable that caused the crash
* @see CrashHandler
* @since v1-alpha0
*/
public void crash(@NotNull String message, @NotNull Throwable throwable) {
Logger.crash(clazz, origin, metadata, message, throwable);
Logger.crash(message, throwable);
}
/**
* Crashes the entire engine.
*
* @param message message
* @see CrashHandler
* @since v1-alpha0
*/
public void crash(@NotNull String message) {
Logger.crash(clazz, origin, metadata, message);
Logger.crash(message);
}
/**
* Provides an API for building {@link LoggerInstance}s more easily.
*
* @since v1-alpha2
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see Logger
* @since v1-alpha8
*/
@Deprecated(forRemoval = true)
@SuppressWarnings({ "unused" })
public static final class Builder {
/**
* Contains the class of the issuer.
*
* @see LoggerInstance#clazz
* @since v1-alpha2
* @since v1-alpha8
*/
private @Nullable Class<?> clazz = null;
/**
* Contains the origin of the issuer.
*
* @see LoggerInstance#origin
* @since v1-alpha2
* @since v1-alpha8
*/
private @Nullable String origin = null;
/**
* Contains metadata about the issuer.
*
* @see LoggerInstance#metadata
* @since v1-alpha2
* @since v1-alpha8
*/
private @Nullable String metadata = null;
@ -253,14 +192,13 @@ public final class LoggerInstance {
if (metadata == null || metadata.isBlank())
metadata = null;
return new LoggerInstance(clazz, origin, metadata);
return new LoggerInstance();
}
/**
* Returns the class of the issuer.
*
* @return class of the issuer
* @see LoggerInstance#clazz
* @since v1-alpha2
*/
public @Nullable Class<?> getClazz() {
@ -271,7 +209,6 @@ public final class LoggerInstance {
* Returns the origin of the issuer.
*
* @return origin of the issuer
* @see LoggerInstance#origin
* @since v1-alpha2
*/
public @Nullable String getOrigin() {
@ -282,7 +219,6 @@ public final class LoggerInstance {
* Returns metadata about the issuer.
*
* @return metadata about the issuer
* @see LoggerInstance#metadata
* @since v1-alpha2
*/
public @Nullable String getMetadata() {
@ -294,7 +230,6 @@ public final class LoggerInstance {
*
* @param clazz new class of the issuer
* @return builder instance
* @see LoggerInstance#clazz
* @since v1-alpha2
*/
public @NotNull Builder setClazz(@Nullable Class<?> clazz) {
@ -307,7 +242,6 @@ public final class LoggerInstance {
*
* @param origin new origin of the issuer
* @return builder instance
* @see LoggerInstance#origin
* @since v1-alpha2
*/
public @NotNull Builder setOrigin(@Nullable String origin) {
@ -320,7 +254,6 @@ public final class LoggerInstance {
*
* @param metadata new metadata about the issuer
* @return builder instance
* @see LoggerInstance#metadata
* @since v1-alpha2
*/
public @NotNull Builder setMetadata(@Nullable String metadata) {

View file

@ -1,144 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.logging;
import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.type.EngineState;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
/**
* Controls the logging thread of the engine.
*
* @since v1-alpha4
*/
@Slf4j
public class LoggingThread {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha4
*/
protected static final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(LoggingThread.class).setOrigin("ENGINE").build();
/**
* Contains the logic of the logging thread.
*
* @since v1-alpha4
*/
private static final @NotNull Runnable loggingThreadLogic = () -> {
while (!Thread.currentThread().isInterrupted()) {
// Stop thread when engine is shutting down
if (Engine.getInstance().getState() == EngineState.SHUTDOWN
|| Engine.getInstance().getState() == EngineState.CRASHED
|| !EngineConfiguration.getInstance().isOptimizeLogging())
return;
// Process all log messages
Logger.flushLogMessages();
// Sleep for whatever has been configured
if (EngineConfiguration.getInstance().getLoggerPollingSpeed() > 0) {
long sleepDuration = System.currentTimeMillis() + EngineConfiguration.getInstance().getLoggerPollingSpeed();
while (System.currentTimeMillis() < sleepDuration)
Thread.onSpinWait();
}
}
};
/**
* Contains a reference to the logging thread.
*
* @since v1-alpha4
*/
private static Thread loggingThread;
/**
* Creates and initializes an instance of this class
*
* @since v1-alpha4
*/
private LoggingThread() {}
/**
* Reconstructs the {@link #loggingThread} thread.
*
* @throws IllegalStateException if the logging thread's state is not {@link Thread.State#TERMINATED}
* @since v1-alpha4
*/
private static void reconstructThread() throws IllegalStateException {
if (loggingThread != null && loggingThread.getState() != Thread.State.TERMINATED)
throw new IllegalStateException("The logging thread needs to be terminated before reconstruction");
loggingThread = Thread
.ofPlatform()
.daemon()
.name("Logging thread")
.group(Engine.getThreadGroup())
.stackSize(10)
.unstarted(loggingThreadLogic);
}
/**
* Starts the logging thread.
*
* @since v1-alpha4
* @throws IllegalStateException if thread reconstruction fails because the thread isn't {@link Thread.State#TERMINATED}, see {@link #reconstructThread()}
* @see #loggingThread
*/
public static void startThread() {
if (loggingThread == null)
reconstructThread();
if (loggingThread.isAlive()) {
// Executing the thread restart logic prevents blocking the current thread
// while still ensuring that the logging thread is properly restarted
Thread
.ofVirtual()
.name("Logging thread restart thread")
.start(() -> {
logger.diag("Restarting the logging thread");
loggingThread.interrupt();
// Make sure that the logging thread is dead before reconstructing and starting it
while (loggingThread.isAlive())
Thread.onSpinWait();
reconstructThread();
loggingThread.start();
});
} else
loggingThread.start();
}
/**
* Returns the {@link Thread.State} of the logging thread.
*
* @return logging thread state
* @since v1-alpha4
* @see Thread.State
*/
public static @NotNull Thread.State getState() {
return loggingThread.getState();
}
}

View file

@ -19,6 +19,8 @@
package de.staropensource.engine.base.logging;
import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.type.EngineState;
import de.staropensource.engine.base.type.logging.LogLevel;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
@ -34,26 +36,18 @@ import java.nio.charset.StandardCharsets;
*
* @since v1-alpha4
*/
@SuppressWarnings({ "unused" })
@SuppressWarnings({ "unused", "JavadocDeclaration" })
public final class PrintStreamService {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha4
*/
private static final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(PrintStreamService.class).setOrigin("ENGINE").build();
/**
* Contains the diagnostic stream.
* Anything sent will be redirected to
* {@link Logger#info(Class, String, String, String)}
* {@link Logger#info(String)}
*
* @since v1-alpha4
* -- GETTER --
* Returns the diagnostic stream.
* Anything sent will be redirected to
* {@link Logger#info(Class, String, String, String)}
* {@link Logger#info(String)}
*
* @return diagnostic stream
* @since v1-alpha4
@ -64,13 +58,13 @@ public final class PrintStreamService {
/**
* Contains the verbose stream.
* Anything sent will be redirected to
* {@link Logger#error(Class, String, String, String)}
* {@link Logger#error(String)}
*
* @since v1-alpha4
* -- GETTER --
* Returns the verbose stream.
* Anything sent will be redirected to
* {@link Logger#error(Class, String, String, String)}
* {@link Logger#error(String)}
*
* @return verbose stream
* @since v1-alpha4
@ -81,13 +75,13 @@ public final class PrintStreamService {
/**
* Contains the silent warning stream.
* Anything sent will be redirected to
* {@link Logger#error(Class, String, String, String)}
* {@link Logger#error(String)}
*
* @since v1-alpha4
* -- GETTER --
* Returns the silent warning stream.
* Anything sent will be redirected to
* {@link Logger#error(Class, String, String, String)}
* {@link Logger#error(String)}
*
* @return silent warning stream
* @since v1-alpha4
@ -98,13 +92,13 @@ public final class PrintStreamService {
/**
* Contains the informational stream.
* Anything sent will be redirected to
* {@link Logger#info(Class, String, String, String)}
* {@link Logger#info(String)}
*
* @since v1-alpha4
* -- GETTER --
* Returns the informational stream.
* Anything sent will be redirected to
* {@link Logger#info(Class, String, String, String)}
* {@link Logger#info(String)}
*
* @return informational stream
* @since v1-alpha4
@ -115,13 +109,13 @@ public final class PrintStreamService {
/**
* Contains the warning stream.
* Anything sent will be redirected to
* {@link Logger#error(Class, String, String, String)}
* {@link Logger#error(String)}
*
* @since v1-alpha4
* -- GETTER --
* Returns the warning stream.
* Anything sent will be redirected to
* {@link Logger#error(Class, String, String, String)}
* {@link Logger#error(String)}
*
* @return warning stream
* @since v1-alpha4
@ -132,13 +126,13 @@ public final class PrintStreamService {
/**
* Contains the error stream.
* Anything sent will be redirected to
* {@link Logger#info(Class, String, String, String)}
* {@link Logger#info(String)}
*
* @since v1-alpha4
* -- GETTER --
* Returns the error stream.
* Anything sent will be redirected to
* {@link Logger#info(Class, String, String, String)}
* {@link Logger#info(String)}
*
* @return error stream
* @since v1-alpha4
@ -149,13 +143,13 @@ public final class PrintStreamService {
/**
* Contains the crash stream.
* Anything sent will be redirected to
* {@link Logger#error(Class, String, String, String)}
* {@link Logger#error(String)}
*
* @since v1-alpha4
* -- GETTER --
* Returns the crash stream.
* Anything sent will be redirected to
* {@link Logger#error(Class, String, String, String)}
* {@link Logger#error(String)}
*
* @return crash stream
* @since v1-alpha4
@ -172,18 +166,14 @@ public final class PrintStreamService {
/**
* Initializes all {@link PrintStream}s offered by this class.
* <p>
* Only works during early engine startup.
*
* @since v1-alpha4
* @since v1-alpha8
*/
public static void initializeStreams() {
// Close all existing streams
if (diag != null) diag.close();
if (verb != null) verb.close();
if (sarn != null) sarn.close();
if (info != null) info.close();
if (warn != null) warn.close();
if (error != null) error.close();
if (crash != null) crash.close();
if (Engine.getInstance() == null || Engine.getInstance().getState() != EngineState.EARLY_STARTUP)
return;
// Create streams
diag = LogStream.createPrintStream(LogLevel.DIAGNOSTIC);
@ -277,13 +267,13 @@ public final class PrintStreamService {
// Check for newline
if (sequence.indexOf("\n") != -1) {
switch (level) {
case DIAGNOSTIC -> logger.diag(sequence.toString());
case VERBOSE -> logger.verb(sequence.toString());
case SILENT_WARNING -> logger.sarn(sequence.toString());
case INFORMATIONAL -> logger.info(sequence.toString());
case WARNING -> logger.warn(sequence.toString());
case ERROR -> logger.error(sequence.toString());
case CRASH -> logger.crash(sequence.toString());
case DIAGNOSTIC -> Logger.diag(sequence.toString());
case VERBOSE -> Logger.verb(sequence.toString());
case SILENT_WARNING -> Logger.sarn(sequence.toString());
case INFORMATIONAL -> Logger.info(sequence.toString());
case WARNING -> Logger.warn(sequence.toString());
case ERROR -> Logger.error(sequence.toString());
case CRASH -> Logger.crash(sequence.toString());
}
sequence = new StringBuilder();

View file

@ -0,0 +1,338 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.logging.backend;
import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.EngineInternals;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.logging.LogLevel;
import de.staropensource.engine.base.utility.misc.NumberUtil;
import de.staropensource.engine.base.utility.misc.Miscellaneous;
import de.staropensource.engine.base.utility.information.EngineInformation;
import de.staropensource.engine.base.utility.information.JvmInformation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import static de.staropensource.engine.base.logging.backend.Processor.isFeatureEnabled;
/**
* Handles crashes.
*
* @since v1-alpha8
*/
public final class CrashHandler {
/**
* Contains all random witty comments.
*
* @since v1-alpha8
*/
public static final @NotNull String[] WITTYCOMMENTS = new String[]{
"Who fucked up here?",
"What is it now?",
":neofox_woozy:",
"Oh no!",
"my engine brokey brokey",
"weird",
"Is this a feature?",
"$ git blame",
};
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha8
*/
private CrashHandler() {}
/**
* Handles crash reports.
*
* @param issuer {@link StackTraceElement} of the issuer
* @param message message
* @param throwable {@link Throwable} which caused the error
* @param fatal if to terminate the engine
* @since v1-alpha8
*/
public static void handleCrash(@NotNull StackTraceElement issuer, @NotNull String message, @Nullable Throwable throwable, boolean fatal) {
StringBuilder output = new StringBuilder();
String outputFinal;
// Header
output
.append("==== sos!engine crash report ====")
.append("\nDear user: The application or game you just used seems to have run into a problem.")
.append("\n Please be so kind and report this crash report to the developers so they can fix the issue.")
.append("\nDear developer: FIX YOUR SHIT. If the engine is at fault here, please report the crash")
.append("\n to StarOpenSource here: https://git.staropensource.de/StarOpenSource/Engine/issues")
.append("\n\n// ")
.append(WITTYCOMMENTS[new Random().nextInt(WITTYCOMMENTS.length)])
.append("\n\n");
// Information about the crash
output
.append("---- Crash Information ----\n")
.append("Issuer: ")
.append(issuer.getClassName())
.append("@")
.append(issuer.getModuleName())
.append("#")
.append(issuer.getMethodName())
.append("~")
.append(issuer.getLineNumber())
.append("\nFatal: ")
.append(fatal);
if (throwable == null)
output
.append("\nCaused by:")
.append("\nNo throwable has been passed.");
else {
output
.append("\n")
.append(Miscellaneous.stacktraceAsStringRecursive(throwable, true, true))
.append("\n");
}
output.append("\nMessage: \n")
.append(message)
.append("\n\n");
// Environment information
output
.append("---- Environment ----")
.append("\nTime and date: ")
.append(NumberUtil.padNumbers(Calendar.getInstance().get(Calendar.DAY_OF_MONTH), 2))
.append(".")
.append(NumberUtil.padNumbers(Calendar.getInstance().get(Calendar.MONTH), 2))
.append(".")
.append(NumberUtil.padNumbers(Calendar.getInstance().get(Calendar.YEAR), 4))
.append(" ")
.append(NumberUtil.padNumbers(Calendar.getInstance().get(Calendar.HOUR_OF_DAY), 2))
.append(":")
.append(NumberUtil.padNumbers(Calendar.getInstance().get(Calendar.MINUTE), 2))
.append(":")
.append(NumberUtil.padNumbers(Calendar.getInstance().get(Calendar.SECOND), 2))
.append(" [")
.append(TimeZone.getDefault().getDisplayName(false, TimeZone.SHORT, Locale.US))
.append("]")
.append("\nUNIX Epoch: ")
.append(NumberUtil.padNumbers(System.currentTimeMillis(), String.valueOf(Long.MAX_VALUE).length()))
.append("\nOperating system: ")
.append(System.getProperty("os.name"))
.append("\nCPU architecture: ")
.append(System.getProperty("os.arch"))
.append("\nMemory: ")
.append(JvmInformation.getMemoryUsed() / 1024)
.append(" MiB")
.append("/")
.append(JvmInformation.getMemoryLimit() / 1024)
.append(" MiB")
.append(" (stack ")
.append(JvmInformation.getMemoryStack().getUsed() / 1024)
.append(" MiB")
.append("/")
.append(JvmInformation.getMemoryStack().getMax() == -1 ? "" : JvmInformation.getMemoryStack().getMax() / 1024)
.append(" MiB")
.append(", heap ")
.append(JvmInformation.getMemoryHeap().getUsed() / 1024)
.append(" MiB")
.append("/")
.append(JvmInformation.getMemoryHeap().getMax() == -1 ? "" : JvmInformation.getMemoryStack().getMax() / 1024)
.append(" MiB)")
.append("\nJVM: ")
.append(JvmInformation.getImplementationName())
.append(" ")
.append(JvmInformation.getImplementationVersion())
.append(" @ ")
.append(JvmInformation.getJavaVersion())
.append(" by ")
.append(JvmInformation.getImplementationVendor())
.append("\nJVM arguments: ");
for (String argument : JvmInformation.getArguments())
output
.append("\n- '")
.append(argument)
.append("'");
output.append("\n\n");
// Engine
output.append("---- sos!engine ----\n");
if (EngineInformation.getVersioningString() == null)
output.append("EngineInformation is not yet initialized");
else
output
.append("Version: ")
.append(EngineInformation.getVersioningString())
.append("\nCommit: ")
.append(EngineInformation.getGitCommitIdentifierLong())
.append("\nDirty: ")
.append(EngineInformation.isGitDirty());
output.append("\n\n");
// Engine configuration
output.append("---- sos!engine configuration ----\n");
if (EngineConfiguration.getInstance() == null)
output.append("EngineConfiguration is not yet initialized");
else
output
.append("EngineConfiguration#debug='")
.append(EngineConfiguration.getInstance().isDebug())
.append("'\n")
.append("EngineConfiguration#debugEvents='")
.append(EngineConfiguration.getInstance().isDebugEvents())
.append("'\n")
.append("EngineConfiguration#initialPerformSubsystemInitialization='")
.append(EngineConfiguration.getInstance().isInitialPerformSubsystemInitialization())
.append("'\n")
.append("EngineConfiguration#initialIncludeSubsystemClasses='")
.append(EngineConfiguration.getInstance().getInitialIncludeSubsystemClasses())
.append("'\n")
.append("EngineConfiguration#errorShortcodeParser='")
.append(EngineConfiguration.getInstance().isErrorShortcodeParser())
.append("'\n")
.append("EngineConfiguration#optimizeLogging='")
.append(EngineConfiguration.getInstance().isOptimizeLogging())
.append("'\n")
.append("EngineConfiguration#optimizeEvents='")
.append(EngineConfiguration.getInstance().isOptimizeEvents())
.append("'\n")
.append("EngineConfiguration#logLevel='")
.append(EngineConfiguration.getInstance().getLogLevel().name())
.append("'\n")
.append("EngineConfiguration#logSettings='")
.append(EngineConfiguration.getInstance().getLogFeatures())
.append("'\n")
.append("EngineConfiguration#logPollingSpeed='")
.append(EngineConfiguration.getInstance().getLogPollingSpeed())
.append("'\n")
.append("EngineConfiguration#logForceStandardOutput='")
.append(EngineConfiguration.getInstance().isLogForceStandardOutput())
.append("'\n")
.append("EngineConfiguration#hideFullTypePath='")
.append(EngineConfiguration.getInstance().isHideFullTypePath());
output.append("'\n\n");
// System properties
output.append("---- System properties ----");
for (String property : System.getProperties().stringPropertyNames().stream().sorted().toList())
output
.append("\n")
.append(property)
.append("='")
.append(System.getProperties().getProperty(property).replace("\n", "\\n"))
.append("'");
output.append("\n\n");
// Stacktraces of all threads
output.append("---- Stacktraces of all threads ----");
{
Map<Thread, StackTraceElement[]> stacktraces = Thread.getAllStackTraces();
for (Thread thread : stacktraces.keySet())
output
.append("\n")
.append(thread.getName())
.append(" (id=")
.append(thread.threadId())
.append(" priority=")
.append(thread.getPriority())
.append(" group=")
.append(thread.getThreadGroup() == null ? "<unknown>" : thread.getThreadGroup().getName())
.append(" state=")
.append(thread.getState().name())
.append(" daemon=")
.append(thread.isDaemon())
.append("):")
.append("\n")
.append(Miscellaneous.stacktraceAsString(stacktraces.get(thread), false))
.append("\n");
}
output.append("\n");
// Footer
output
.append("Dear user: The application or game you just used seems to have run into a problem.\n")
.append(" Please be so kind and report this crash report to the developers so they can fix the issue.\n")
.append("Dear developer: FIX YOUR SHIT. If the engine is at fault here, please report the crash\n")
.append(" to StarOpenSource here: https://git.staropensource.de/StarOpenSource/Engine/issues\n")
.append("==== sos!engine crash report ====");
// Formatting
if (isFeatureEnabled("formatting")) {
outputFinal =
"<fg:red><bold>"
+ output
.toString()
.replace("<", "\\<")
+ "<reset>";
} else
outputFinal = output.toString();
// Print
Logger.getLoggingAdapter().print(LogLevel.CRASH, issuer, message, outputFinal);
// Terminate engine
// We do a test on the engine state here
// to prevent bugs and multiple engine shutdowns.
if (fatal)
switch (Engine.getInstance().getState()) {
case UNKNOWN, EARLY_STARTUP, STARTUP -> {
if (EngineInternals.getInstance() == null)
Runtime.getRuntime().exit(69);
else
EngineInternals.getInstance().getShutdownHandler().shutdown((short) 69);
}
case RUNNING -> Engine.getInstance().shutdown(69);
case SHUTDOWN, CRASHED -> {}
}
}
}

View file

@ -0,0 +1,91 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.logging.backend;
import org.intellij.lang.annotations.RegExp;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
* Responsible for filtering log messages out.
*
* @since v1-alpha8
*/
public final class Filterer {
/**
* Contains a list of all disallowed classes.
*
* @since v1-alpha8
*/
static @NotNull List<@NotNull String> disallowedClasses = new ArrayList<>();
/**
* Contains a list of all disallowed modules.
*
* @since v1-alpha8
*/
static @NotNull List<@NotNull String> disallowedModules = new ArrayList<>();
/**
* Contains a list of all disallowed messages.
*
* @since v1-alpha8
*/
static @NotNull List<@NotNull String> disallowedMessages = new ArrayList<>();
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha8
*/
private Filterer() {}
/**
* Disallows one or multiple classes.
*
* @param regex regex
* @since v1-alpha8
*/
public static void disallowClass(@RegExp @NotNull String regex) {
disallowedClasses.add(regex);
}
/**
* Disallows one or multiple modules.
*
* @param regex regex
* @since v1-alpha8
*/
public static void disallowModule(@RegExp @NotNull String regex) {
disallowedModules.add(regex);
}
/**
* Disallows one or multiple messages.
*
* @param regex regex
* @since v1-alpha8
*/
public static void disallowMessage(@RegExp @NotNull String regex) {
disallowedMessages.add(regex);
}
}

View file

@ -0,0 +1,380 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.logging.backend;
import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.implementation.shortcode.EmptyShortcodeParser;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.logging.backend.async.LoggingQueue;
import de.staropensource.engine.base.type.logging.LogLevel;
import de.staropensource.engine.base.utility.misc.NumberUtil;
import de.staropensource.engine.base.utility.PlaceholderEngine;
import de.staropensource.engine.base.utility.information.JvmInformation;
import org.jetbrains.annotations.NotNull;
import java.util.Calendar;
/**
* Processes log messages.
*
* @see #handle(LogLevel, StackTraceElement, String)
* @since v1-alpha8
*/
public final class Processor {
/**
* Creates and initializes an instance of this class
*
* @since v1-alpha8
*/
private Processor() {}
/**
* Checks whether the specified feature is enabled.
*
* @param feature feature to check
* @return enabled?
* @since v1-alpha8
*/
public static boolean isFeatureEnabled(@NotNull String feature) {
return EngineConfiguration.getInstance() != null && EngineConfiguration.getInstance().getLogFeatures().contains(feature);
}
/**
* Handles incoming log calls and either
* processes them directly or queues them in.
*
* @param level level of the log call
* @param issuer {@link StackTraceElement} of the issuer
* @param message message
* @since v1-alpha8
*/
public static void handle(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message) {
if (EngineConfiguration.getInstance() != null && EngineConfiguration.getInstance().isOptimizeLogging())
LoggingQueue.add(level, issuer, message);
else
process(level, issuer, message);
}
/**
* Processes a log call.
*
* @param level level of the log call
* @param issuer {@link StackTraceElement} of the issuer
* @param message message
* @since v1-alpha8
*/
public static void process(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message) {
StringBuilder output = new StringBuilder();
// Filter out
if (EngineConfiguration.getInstance() == null) {
LogLevel maxLevel = LogLevel.INFORMATIONAL;
try {
maxLevel = LogLevel.valueOf(System.getProperties().getProperty("sosengine.base.logLevel", "informational").toUpperCase());
} catch (IllegalArgumentException ignored) {
Logger.error("The log level '" + System.getProperties().getProperty("sosengine.base.logLevel", "informational") + "' is not valid");
}
if (level.compareTo(maxLevel) < 0)
return;
} else if (level.compareTo(EngineConfiguration.getInstance().getLogLevel()) < 0)
return;
for (String classNameDisallowed : Filterer.disallowedClasses)
if (issuer.getClassName().matches(classNameDisallowed))
return;
for (String moduleNameDisallowed : Filterer.disallowedModules)
if (issuer.getModuleName().matches(moduleNameDisallowed))
return;
for (String messageDisallowed : Filterer.disallowedModules)
if (message.matches(messageDisallowed))
return;
format(output, level);
runtime(output);
if (isFeatureEnabled("date") || isFeatureEnabled("time")) {
output.append("[");
date(output);
if (isFeatureEnabled("date") && isFeatureEnabled("time"))
output.append(" ");
time(output);
output.append("] ");
}
if (isFeatureEnabled("level") || isFeatureEnabled("origin")) {
output.append("[");
level(output, level);
if (isFeatureEnabled("level") && isFeatureEnabled("origin"))
output.append(" ");
if (isFeatureEnabled("origin")) {
issuerClass(output, level, issuer);
issuerModule(output, level, issuer);
methodName(output, level, issuer);
lineNumber(output, level, issuer);
}
output.append("] ");
}
message(output, message);
format(output, "reset");
// Print
Logger.getLoggingAdapter().print(level, issuer, message, output.toString());
}
// -----> Formatting
/**
* Adds the {@code formatting} feature.
* <p>
* This method will reset and then color the following
* substring in the log level-specific color.
*
* @param builder {@link StringBuilder} instance to append to
* @param level level of the log call
* @see #format(StringBuilder, String)
* @since v1-alpha8
*/
private static void format(@NotNull StringBuilder builder, @NotNull LogLevel level) {
format(builder, "reset");
format(builder, switch (level) {
case DIAGNOSTIC, VERBOSE -> "fg:blue";
case SILENT_WARNING, WARNING -> "fg:yellow";
case INFORMATIONAL -> "fg:white";
case ERROR -> "fg:red";
case CRASH -> "you should not see this";
});
}
/**
* Adds the {@code formatting} feature.
*
* @param builder {@link StringBuilder} instance to append to
* @param component formatting component
* @see #format(StringBuilder, LogLevel)
* @since v1-alpha8
*/
private static void format(@NotNull StringBuilder builder, @NotNull String component) {
if (isFeatureEnabled("formatting"))
builder
.append("<")
.append(component)
.append(">");
}
/**
* Adds the {@code formatting} feature.
*
* @param string string to sanitize
* @return sanitized string
* @see #format(StringBuilder, LogLevel)
* @since v1-alpha8
*/
private static @NotNull String sanitizeFormat(@NotNull String string) {
if (isFeatureEnabled("formatting"))
return string.replace("<", "\\<");
else
return string;
}
// -----> Features and components
/**
* Adds the {@code runtime} feature.
*
* @param builder {@link StringBuilder} instance to append to
* @since v1-alpha8
*/
private static void runtime(@NotNull StringBuilder builder) {
if (isFeatureEnabled("runtime"))
builder
.append("[")
.append(JvmInformation.getUptime())
.append("ms")
.append("] ");
}
/**
* Adds the {@code time} feature.
*
* @param builder {@link StringBuilder} instance to append to
* @since v1-alpha8
*/
private static void time(@NotNull StringBuilder builder) {
if (isFeatureEnabled("time"))
builder
.append(NumberUtil.padNumbers(Calendar.getInstance().get(Calendar.HOUR_OF_DAY), 2))
.append(":")
.append(NumberUtil.padNumbers(Calendar.getInstance().get(Calendar.MINUTE), 2))
.append(":")
.append(NumberUtil.padNumbers(Calendar.getInstance().get(Calendar.SECOND), 2));
}
/**
* Adds the {@code date} feature.
*
* @param builder {@link StringBuilder} instance to append to
* @since v1-alpha8
*/
private static void date(@NotNull StringBuilder builder) {
if (isFeatureEnabled("date"))
builder
.append(NumberUtil.padNumbers(Calendar.getInstance().get(Calendar.DAY_OF_MONTH), 2))
.append(".")
.append(NumberUtil.padNumbers(Calendar.getInstance().get(Calendar.MONTH), 2))
.append(".")
.append(NumberUtil.padNumbers(Calendar.getInstance().get(Calendar.YEAR), 4));
}
/**
* Adds the {@code level} component.
*
* @param builder {@link StringBuilder} instance to append to
* @param level level of the log call
* @since v1-alpha8
*/
private static void level(@NotNull StringBuilder builder, @NotNull LogLevel level) {
if (isFeatureEnabled("level")) {
format(builder, "bold");
builder.append(switch (level) {
case DIAGNOSTIC -> "DIAG";
case VERBOSE -> "VERB";
case SILENT_WARNING -> "SARN";
case INFORMATIONAL -> "INFO";
case WARNING -> "WARN";
case ERROR -> "ERR!";
case CRASH -> "CRSH";
});
format(builder, level);
}
}
/**
* Adds the {@code issuer class} component.
*
* @param builder {@link StringBuilder} instance to append to
* @param level level of the log call
* @param issuer {@link StackTraceElement} of the issuer
* @since v1-alpha8
*/
private static void issuerClass(@NotNull StringBuilder builder, @NotNull LogLevel level, @NotNull StackTraceElement issuer) {
format(builder, "bold");
if (isFeatureEnabled("shortIssuerClass")) {
String[] classNameSplit = issuer.getClassName().split("\\.");
builder.append(classNameSplit[classNameSplit.length - 1]);
} else
builder.append(issuer.getClassName());
}
/**
* Adds the {@code moduleName} and {@code moduleVersion} features.
*
* @param builder {@link StringBuilder} instance to append to
* @param level level of the log call
* @param issuer {@link StackTraceElement} of the issuer
* @since v1-alpha8
*/
private static void issuerModule(@NotNull StringBuilder builder, @NotNull LogLevel level, @NotNull StackTraceElement issuer) {
if (isFeatureEnabled("moduleName") && issuer.getModuleName() != null) {
format(builder, "bold");
builder
.append("@")
.append(issuer.getModuleName());
if (isFeatureEnabled("moduleVersion") && issuer.getModuleVersion() != null)
builder
.append("v")
.append(issuer.getModuleVersion());
format(builder, level);
}
}
/**
* Adds the {@code methodName} feature.
*
* @param builder {@link StringBuilder} instance to append to
* @param level level of the log call
* @param issuer {@link StackTraceElement} of the issuer
* @since v1-alpha8
*/
private static void methodName(@NotNull StringBuilder builder, @NotNull LogLevel level, @NotNull StackTraceElement issuer) {
if (isFeatureEnabled("methodName")) {
builder.append("#");
format(builder, "bold");
builder.append(sanitizeFormat(issuer.getMethodName()));
format(builder, level);
}
}
/**
* Adds the {@code lineNumber} feature.
*
* @param builder {@link StringBuilder} instance to append to
* @param level level of the log call
* @param issuer {@link StackTraceElement} of the issuer
* @since v1-alpha8
*/
private static void lineNumber(@NotNull StringBuilder builder, @NotNull LogLevel level, @NotNull StackTraceElement issuer) {
if (isFeatureEnabled("lineNumber")) {
builder.append("~");
format(builder, "bold");
builder.append(issuer.getLineNumber());
format(builder, level);
}
}
/**
* Adds the {@code message} component.
*
* @param builder {@link StringBuilder} instance to append to
* @param message message
* @since v1-alpha8
*/
private static void message(@NotNull StringBuilder builder, @NotNull String message) {
builder.append(sanitizeFormat(handlePlaceholders(
message.replace(
"\n",
"\n" + " ".repeat(new EmptyShortcodeParser(builder.toString(), true).getClean().length())
)
)));
}
// -----> Utility methods
/**
* Uses the {@link PlaceholderEngine} to replace
* all placeholders within a specified string and
* returns it's result. The original string will
* be returned if the {@link PlaceholderEngine}
* is not yet initialized.
*
* @param string string to use
* @return updated string
* @since v1-alpha8
*/
private static @NotNull String handlePlaceholders(@NotNull String string) {
if (PlaceholderEngine.getInstance() == null)
return string;
else
return PlaceholderEngine.getInstance().process(string);
}
}

View file

@ -0,0 +1,76 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.logging.backend.async;
import de.staropensource.engine.base.internal.type.QueuedLogCall;
import de.staropensource.engine.base.logging.backend.Processor;
import de.staropensource.engine.base.type.logging.LogLevel;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Handles everything related to the logging queue.
*
* @since v1-alpha8
*/
public final class LoggingQueue {
/**
* Contains the logging queue.
*
* @since v1-alpha8
*/
private static final @NotNull List<@NotNull QueuedLogCall> queue = Collections.synchronizedList(new ArrayList<>());
/**
* Creates and initializes an instance of this class
*
* @since v1-alpha8
*/
private LoggingQueue() {}
/**
* Adds a new entry to the logging queue.
*
* @param level level of the log call
* @param issuer {@link StackTraceElement} of the issuer
* @param message message
* @since v1-alpha8
*/
public static void add(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message) {
queue.add(new QueuedLogCall(level, issuer, message));
}
/**
* Flushes the logging queue.
*
* @since v1-alpha8
*/
public static void flush() {
// Get copy of and clear the queue
List<@NotNull QueuedLogCall> queue = new ArrayList<>(LoggingQueue.queue);
LoggingQueue.queue.clear();
for (QueuedLogCall queuedCall : queue)
Processor.process(queuedCall.level(), queuedCall.issuer(), queuedCall.message());
}
}

View file

@ -0,0 +1,142 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.logging.backend.async;
import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.EngineState;
import org.jetbrains.annotations.NotNull;
/**
* Handles the logging thread.
*
* @since v1-alpha8
*/
public final class LoggingThread {
/**
* Contains the logging thread.
*
* @since v1-alpha8
*/
private static Thread thread;
/**
* Contains the code of the logging thread.
*
* @since v1-alpha8
*/
private static final @NotNull Runnable threadCode = () -> {
int pollingSpeed;
while (!(
Thread.currentThread().isInterrupted()
|| !(EngineConfiguration.getInstance() == null || EngineConfiguration.getInstance().isOptimizeLogging())
|| Engine.getInstance().getState() == EngineState.SHUTDOWN
|| Engine.getInstance().getState() == EngineState.CRASHED
)) {
if (EngineConfiguration.getInstance() == null)
pollingSpeed = 5;
else
pollingSpeed = EngineConfiguration.getInstance().getLogPollingSpeed();
// Flush all log messages
LoggingQueue.flush();
// Sleep for whatever has been configured
if (pollingSpeed > 0) {
long sleepDuration = System.currentTimeMillis() + pollingSpeed;
while (System.currentTimeMillis() < sleepDuration)
Thread.onSpinWait();
}
}
};
static {
constructThread();
}
/**
* Creates and initializes an instance of this class
*
* @since v1-alpha8
*/
private LoggingThread() {}
/**
* Constructs the logging thread.
*
* @see #thread
* @since v1-alpha8
*/
private static void constructThread() {
thread = Thread
.ofPlatform()
.daemon()
.name("Logging thread")
.group(Engine.getThreadGroup())
.priority(Thread.MAX_PRIORITY)
.stackSize(10)
.unstarted(threadCode);
}
/**
* (Re-)Starts the logging thread.
*
* @param allowRestart if the logging thread should be restarted if it's stopped
* @since v1-alpha8
*/
public static void startThread(boolean allowRestart) {
if (allowRestart && thread.isAlive()) {
// Executing the restart logic in another thread prevents
// this thread from being fully blocked while still ensuring
// that the logging thread is properly restarted
Thread
.ofVirtual()
.name("Logging thread restart thread")
.start(() -> {
Logger.diag("Restarting the logging thread");
// Interrupt thread
// This let's our thread code know that it should terminate
thread.interrupt();
// Make sure that the logging thread is dead before reconstructing and starting it
while (thread.isAlive())
Thread.onSpinWait();
constructThread();
thread.start();
});
} else
thread.start();
}
/**
* Returns the {@link Thread.State} of the logging thread.
*
* @return logging thread state
* @see Thread.State
* @since v1-alpha8
*/
public static @NotNull Thread.State getState() {
return thread.getState();
}
}

View file

@ -18,8 +18,9 @@
*/
/**
* Data types in form of enums and classes.
* Everything related to making the logging
* infrastructure asynchronous.
*
* @since v1-alpha2
* @since v1-alpha8
*/
package de.staropensource.engine.windowing.glfw.type;
package de.staropensource.engine.base.logging.backend.async;

View file

@ -18,8 +18,8 @@
*/
/**
* Immutable variations of regular Java data types.
* The backend of sos!engine's logging infrastructure.
*
* @since v1-alpha1
* @since v1-alpha8
*/
package de.staropensource.engine.base.type.immutable;
package de.staropensource.engine.base.logging.backend;

View file

@ -18,11 +18,9 @@
*/
/**
* The engine's custom logging infrastructure.
* The engine's logging infrastructure.
*
* @see de.staropensource.engine.base.logging.Logger
* @see de.staropensource.engine.base.logging.LoggerInstance
* @see de.staropensource.engine.base.logging.CrashHandler
* @since v1-alpha0
*/
package de.staropensource.engine.base.logging;

View file

@ -19,7 +19,7 @@
package de.staropensource.engine.base.reflection;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.base.logging.Logger;
import org.jetbrains.annotations.NotNull;
import java.io.File;
@ -39,14 +39,6 @@ import java.util.Map;
* @since v1-alpha2
*/
public final class ClasspathAccess {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha2
*/
private static final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(ClasspathAccess.class).setOrigin("ENGINE").build();
/**
* Creates and initializes an instance of this class.
*
@ -69,7 +61,7 @@ public final class ClasspathAccess {
try {
urls.add(new File(path).toURI().toURL());
} catch (Exception exception) {
logger.crash("Failed converting classpath to URL", exception);
Logger.crash("Failed converting classpath to URL", exception);
}
return fixURLs(urls);

View file

@ -20,7 +20,7 @@
package de.staropensource.engine.base.type;
import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.utility.Math;
import de.staropensource.engine.base.utility.misc.NumberUtil;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
@ -42,7 +42,7 @@ import java.util.Locale;
@Getter
@Setter
@SuppressWarnings({ "JavadocDeclaration" })
public final class Color {
public class Color {
/**
* Contains the red color value.
*
@ -118,10 +118,10 @@ public final class Color {
* @since v1-alpha6
*/
private Color(int red, int green, int blue, int alpha) {
this.red = Math.boundNumber(0, 255, red);
this.green = Math.boundNumber(0, 255, green);
this.blue = Math.boundNumber(0, 255, blue);
this.alpha = Math.boundNumber(0, 255, alpha);
this.red = NumberUtil.limitNumber(0, 255, red);
this.green = NumberUtil.limitNumber(0, 255, green);
this.blue = NumberUtil.limitNumber(0, 255, blue);
this.alpha = NumberUtil.limitNumber(0, 255, alpha);
}
/**

View file

@ -19,9 +19,6 @@
package de.staropensource.engine.base.type;
import de.staropensource.engine.base.logging.InitLogger;
import de.staropensource.engine.base.logging.Logger;
/**
* Determines in which state the engine is currently in.
*
@ -29,58 +26,52 @@ import de.staropensource.engine.base.logging.Logger;
*/
public enum EngineState {
/**
* The state of the engine is currently unknown.
* The engine likely has not been initialized yet.
* Indicates that the state of the engine is
* currently unknown. The engine is most likely
* not initialized yet.
*
* @since v1-alpha2
*/
UNKNOWN,
/**
* The engine is in early startup.
* The engine is largely uninitialized and
* the logging infrastructure is not yet ready
* to be used.
* <p>
* This state is used to indicate that the
* {@link InitLogger} shall be used instead
* of {@link Logger}.
* Indicates that the engine is largely
* uninitialized and unsafe to use.
*
* @since v1-alpha4
* @since v1-alpha8
*/
EARLY_STARTUP,
/**
* The engine is starting up.
* Some parts of the engine may not be initialized
* yet and may be unsafe to access. The logging
* infrastructure is ready to be used though and is
* safe to access.
* Indicates that the core engine has fully
* initialized, except for all subsystems.
*
* @since v1-alpha2
* @since v1-alpha8
*/
STARTUP,
/**
* The engine is in normal operation mode.
* Indicates that the engine is running
* and operating normally.
*
* @since v1-alpha2
*/
RUNNING,
/**
* The engine has crashed, either by itself or the application.
* Indicates that the engine or the
* application has crashed.
*
* @since v1-alpha2
*/
CRASHED,
/**
* The engine is shutting down.
* Some parts of the engine may have already
* shut down and may be unsafe to access.
* Indicates that the engine is shutting
* down. The engine is unusable in this
* state and should not be used.
*
* @since v1-alpha2
* @since v1-alpha8
*/
SHUTDOWN,
}

View file

@ -1,81 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.type;
import de.staropensource.engine.base.annotation.EventListener;
/**
* Allows an {@link EventListener} method to specify when it should be invoked.
*
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public enum EventPriority {
/**
* {@link EventListener}s with this priority are processed first, even before {@link #VERY_IMPORTANT}.
* This event is exclusive to subsystems and should not be used by applications.
*
* @since v1-alpha0
*/
EXCLUSIVELY_IMPORTANT,
/**
* {@link EventListener}s with this priority are invoked first.
*
* @since v1-alpha0
*/
VERY_IMPORTANT,
/**
* {@link EventListener}s with this priority are invoked second.
*
* @since v1-alpha0
*/
IMPORTANT,
/**
* The default event priority, {@link EventListener}s with this priority are invoked third.
*
* @since v1-alpha0
*/
DEFAULT,
/**
* {@link EventListener}s with this priority are invoked fourth.
*
* @since v1-alpha0
*/
UNIMPORTANT,
/**
* {@link EventListener}s with this priority are invoked last.
*
* @since v1-alpha0
*/
VERY_UNIMPORTANT,
/**
* {@link EventListener}s with this priority are invoked last, even after {@link #VERY_UNIMPORTANT}.
* This event is exclusive to subsystems and should not be used by applications.
*
* @since v1-alpha0
*/
EXCLUSIVELY_UNIMPORTANT
}

View file

@ -29,32 +29,32 @@ import org.jetbrains.annotations.NotNull;
*/
public enum Tristate {
/**
* An unset tristate.
* Defines an unset state.
*
* @since v1-alpha1
*/
UNSET,
/**
* A true tristate.
* Defines a true state.
*
* @since v1-alpha1
*/
TRUE,
/**
* A false tristate.
* Defines a false state.
*
* @since v1-alpha1
*/
FALSE;
/**
* Converts the {@link Boolean} into a {@link Tristate}.
* Converts the specified {@link Boolean} into a {@link Tristate}.
*
* @param bool boolean to convert
* @return tristated boolean
* @since v1-alpha5
* @return {@link Tristate} representation of the specified boolean
* @since v1-alpha9
*/
public static @NotNull Tristate toTristate(boolean bool) {
if (bool) return Tristate.TRUE;
@ -62,12 +62,28 @@ public enum Tristate {
}
/**
* Converts the {@link Tristate} into a {@link Boolean}.
* Converts the specified {@link Integer} into a {@link Tristate}.
*
* @param integer integer to convert
* @return {@link Tristate} representation of the specified integer
* @since v1-alpha9
*/
public static @NotNull Tristate toTristate(int integer) {
return switch (integer) {
case 0 -> Tristate.FALSE;
case 1 -> Tristate.TRUE;
case 2 -> Tristate.UNSET;
default -> throw new IndexOutOfBoundsException("Supplied integer '" + integer + "' is not in range 0-2");
};
}
/**
* Converts this {@link Tristate} into a {@link Boolean}.
* Make sure to check for {@link #UNSET} first.
*
* @return booleanized {@link Tristate}
* @throws TristateConversionException when encountering {@link #UNSET}
* @since v1-alpha2
* @return trimmed boolean representation of this {@link Tristate}
* @throws TristateConversionException on encountering {@link #UNSET}
* @since v1-alpha9
*/
public boolean toBoolean() {
return switch (this) {
@ -76,4 +92,19 @@ public enum Tristate {
case FALSE -> false;
};
}
/**
* Converts this {@link Tristate} into an {@link Integer}.
*
* @return integer representation of this {@link Tristate}
* @throws TristateConversionException when encountering {@link #UNSET}
* @since v1-alpha9
*/
public int toInteger() {
return switch (this) {
case FALSE -> 0;
case TRUE -> 1;
case UNSET -> 2;
};
}
}

View file

@ -22,7 +22,8 @@ package de.staropensource.engine.base.type;
import de.staropensource.engine.base.implementation.versioning.StarOpenSourceVersioningSystem;
/**
* Provides all available version types specified in the StarOpenSource Versioning System v2.
* Provides all available version types as specified
* by the StarOpenSource Versioning System v2.
*
* @see StarOpenSourceVersioningSystem
* @since v1-alpha0

View file

@ -1,222 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.type.immutable;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.function.UnaryOperator;
/**
* An unmodifiable {@link ArrayList}.
*
* @param <E> contained type
* @since v1-alpha1
*/
@SuppressWarnings({ "unused" })
public class ImmutableArrayList<E> extends ArrayList<E> {
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha1
*/
public ImmutableArrayList() {}
/**
* Creates and initializes an instance of this class.
* Converts a {@link LinkedList} into an {@link ImmutableArrayList}.
*
* @param list {@link List} to convert
* @since v1-alpha1
*/
public ImmutableArrayList(@NotNull List<E> list) {
super.addAll(list);
}
/**
* Converts the {@link ImmutableArrayList} into a regular {@link ArrayList}.
*
* @return mutable {@link ArrayList}
* @since v1-alpha2
*/
public @NotNull ArrayList<E> toMutable() {
return new ArrayList<>(this);
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public boolean add(E e) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableArrayList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableArrayList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public boolean addAll(@NotNull Collection<? extends E> c) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableArrayList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public boolean addAll(int index, @NotNull Collection<? extends E> c) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableArrayList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public boolean removeAll(@NotNull Collection<?> c) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableArrayList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public boolean retainAll(@NotNull Collection<?> c) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableArrayList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public void replaceAll(UnaryOperator<E> operator) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableArrayList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public void sort(Comparator<? super E> c) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableArrayList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public void clear() {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableArrayList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public E set(int index, E element) throws UnsupportedOperationException {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableArrayList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public void add(int index, E element) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableArrayList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public E remove(int index) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableArrayList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public void addFirst(E e) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableArrayList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public void addLast(E e) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableArrayList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public E removeFirst() {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableArrayList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public E removeLast() {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableArrayList");
}
}

View file

@ -1,167 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.type.immutable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
/**
* An unmodifiable {@link HashMap}.
*
* @param <K> contained key type
* @param <V> contained value type
* @since v1-alpha1
*/
@SuppressWarnings({ "unused" })
public class ImmutableHashMap<K, V> extends HashMap<K, V> {
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha1
*/
public ImmutableHashMap() {}
/**
* Creates and initializes an instance of this class.
* Converts a {@link Map} into an {@link ImmutableHashMap}.
*
* @param map {@link Map} to convert
* @since v1-alpha1
*/
public ImmutableHashMap(@NotNull Map<K, V> map) {
for (K key : map.keySet())
super.put(key, map.get(key));
}
/**
* Converts the {@link ImmutableHashMap} into a regular {@link HashMap}.
*
* @return mutable {@link HashMap}
* @since v1-alpha2
*/
public @NotNull HashMap<K, V> toMutable() {
return new HashMap<>(this);
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, hash map is immutable
*/
@Override
public @Nullable V put(K key, V value) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableHashMap");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, hash map is immutable
*/
@Override
public @Nullable V remove(Object key) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableHashMap");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, hash map is immutable
*/
@Override
public void putAll(@NotNull Map<? extends K, ? extends V> m) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableHashMap");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, hash map is immutable
*/
@Override
public void clear() {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableHashMap");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, hash map is immutable
*/
@Override
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableHashMap");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, hash map is immutable
*/
@Override
public @Nullable V putIfAbsent(K key, V value) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableHashMap");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, hash map is immutable
*/
@Override
public boolean remove(Object key, Object value) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableHashMap");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, hash map is immutable
*/
@Override
public boolean replace(K key, V oldValue, V newValue) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableHashMap");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, hash map is immutable
*/
@Override
public @Nullable V replace(K key, V value) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableHashMap");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, hash map is immutable
*/
@Override
public @Nullable V merge(K key, @NotNull V value, @NotNull BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableHashMap");
}
}

View file

@ -1,134 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.type.immutable;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
/**
* An unmodifiable {@link HashSet}.
*
* @param <E> contained type
* @since v1-alpha2
*/
@SuppressWarnings({ "unused" })
public class ImmutableHashSet<E> extends HashSet<E> {
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha2
*/
public ImmutableHashSet() {}
/**
* Creates and initializes an instance of this class.
* Converts a {@link Set} into an {@link ImmutableHashSet}.
*
* @param set {@link Set} to convert
* @since v1-alpha2
*/
public ImmutableHashSet(@NotNull Set<E> set) {
super.addAll(set);
}
/**
* Converts the {@link ImmutableHashSet} into a regular {@link HashSet}.
*
* @return mutable {@link HashSet}
* @since v1-alpha2
*/
public @NotNull HashSet<E> toMutable() {
return new HashSet<>(this);
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public boolean add(Object o) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableHashSet");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableHashSet");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public boolean addAll(@NotNull Collection collection) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableHashSet");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public boolean retainAll(@NotNull Collection collection) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableHashSet");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public boolean removeIf(Predicate filter) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableHashSet");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public void clear() {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableHashSet");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, array list is immutable
*/
@Override
public boolean removeAll(@NotNull Collection collection) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableHashSet");
}
}

View file

@ -1,167 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.type.immutable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.BiFunction;
/**
* An unmodifiable {@link Map}.
*
* @param <K> contained key type
* @param <V> contained value type
* @since v1-alpha1
*/
@SuppressWarnings({ "unused" })
public class ImmutableLinkedHashMap<K, V> extends LinkedHashMap<K, V> {
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha1
*/
public ImmutableLinkedHashMap() {}
/**
* Creates and initializes an instance of this class.
* Converts a {@link Map} into an {@link ImmutableLinkedHashMap}.
*
* @param map {@link Map} to convert
* @since v1-alpha1
*/
public ImmutableLinkedHashMap(@NotNull Map<K, V> map) {
for (K key : map.keySet())
super.put(key, map.get(key));
}
/**
* Converts the {@link ImmutableLinkedHashMap} into a regular {@link LinkedHashMap}.
*
* @return mutable {@link LinkedHashMap}
* @since v1-alpha2
*/
public @NotNull LinkedHashMap<K, V> toMutable() {
return new LinkedHashMap<>(this);
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked hash map is immutable
*/
@Override
public @Nullable V put(K key, V value) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedHashMap");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked hash map is immutable
*/
@Override
public @Nullable V remove(Object key) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedHashMap");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked hash map is immutable
*/
@Override
public void putAll(@NotNull Map<? extends K, ? extends V> m) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedHashMap");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked hash map is immutable
*/
@Override
public void clear() {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedHashMap");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked hash map is immutable
*/
@Override
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedHashMap");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked hash map is immutable
*/
@Override
public @Nullable V putIfAbsent(K key, V value) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedHashMap");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked hash map is immutable
*/
@Override
public boolean remove(Object key, Object value) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedHashMap");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked hash map is immutable
*/
@Override
public boolean replace(K key, V oldValue, V newValue) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedHashMap");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked hash map is immutable
*/
@Override
public @Nullable V replace(K key, V value) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedHashMap");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked hash map is immutable
*/
@Override
public @Nullable V merge(K key, @NotNull V value, @NotNull BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedHashMap");
}
}

View file

@ -1,222 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.type.immutable;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.function.UnaryOperator;
/**
* An unmodifiable {@link LinkedList}.
*
* @param <E> contained type
* @since v1-alpha1
*/
@SuppressWarnings({ "unused" })
public class ImmutableLinkedList<E> extends LinkedList<E> {
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha1
*/
public ImmutableLinkedList() {}
/**
* Creates and initializes an instance of this class.
* Converts a {@link LinkedList} into an {@link ImmutableLinkedList}.
*
* @param list {@link List} to convert
* @since v1-alpha1
*/
public ImmutableLinkedList(@NotNull List<E> list) {
super.addAll(size(), list);
}
/**
* Converts the {@link ImmutableLinkedList} into a regular {@link LinkedList}.
*
* @return mutable {@link LinkedList}
* @since v1-alpha2
*/
public @NotNull LinkedList<E> toMutable() {
return new LinkedList<>(this);
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked list is immutable
*/
@Override
public boolean add(E e) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked list is immutable
*/
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked list is immutable
*/
@Override
public boolean addAll(@NotNull Collection<? extends E> c) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked list is immutable
*/
@Override
public boolean addAll(int index, @NotNull Collection<? extends E> c) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked list is immutable
*/
@Override
public boolean removeAll(@NotNull Collection<?> c) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked list is immutable
*/
@Override
public boolean retainAll(@NotNull Collection<?> c) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked list is immutable
*/
@Override
public void replaceAll(UnaryOperator<E> operator) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked list is immutable
*/
@Override
public void sort(Comparator<? super E> c) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked list is immutable
*/
@Override
public void clear() {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked list is immutable
*/
@Override
public E set(int index, E element) throws UnsupportedOperationException {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked list is immutable
*/
@Override
public void add(int index, E element) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked list is immutable
*/
@Override
public E remove(int index) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked list is immutable
*/
@Override
public void addFirst(E e) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked list is immutable
*/
@Override
public void addLast(E e) {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked list is immutable
*/
@Override
public E removeFirst() {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedList");
}
/**
* {@inheritDoc}
*
* @throws UnsupportedOperationException always, linked list is immutable
*/
@Override
public E removeLast() {
throw new UnsupportedOperationException("This method cannot be executed on an ImmutableLinkedList");
}
}

View file

@ -1,68 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.type.logging;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Defines a rule used during logging to allow or prevent certain log calls.
*
* @since v1-alpha1
*/
@Getter
@SuppressWarnings({ "JavadocDeclaration" })
public abstract class LogRule {
/**
* Contains if the log rule should disallow or permit matching log calls.
*
* @see LogRuleType
* @since v1-alpha1
* -- GETTER --
* Returns if the log rule should disallow or permit matching log calls.
*
* @return rule type
* @see LogRuleType
* @since v1-alpha1
*/
private final @NotNull LogRuleType type;
/**
* Initializes this abstract class.
*
* @param type rule type
*/
public LogRule(@NotNull LogRuleType type) {
this.type = type;
}
/**
* Evaluates the rule and returns if the rule matches.
*
* @param level level
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message raw message
* @return if the rule matches
*/
public abstract boolean evaluate(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message);
}

View file

@ -22,7 +22,7 @@ package de.staropensource.engine.base.utility;
import de.staropensource.engine.base.exception.dependency.DependencyCycleException;
import de.staropensource.engine.base.exception.dependency.UnmetDependenciesException;
import de.staropensource.engine.base.implementable.VersioningSystem;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.DependencyVector;
import lombok.Getter;
import org.jetbrains.annotations.ApiStatus;
@ -39,14 +39,6 @@ import java.util.*;
*/
@SuppressWarnings({ "unused", "UnusedReturnValue", "JavadocDeclaration" })
public final class DependencyResolver {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha4
*/
private final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").setMetadata(String.valueOf(hashCode())).build();
/**
* List of {@link DependencyVector}s to resolve.
*
@ -275,7 +267,7 @@ public final class DependencyResolver {
try {
versioningSystemResolved = vectorDependency.getVersioningSystem().getDeclaredConstructor(String.class).newInstance(vectorDependency.getVersion());
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) {
logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + vectorDependency.getVersioningSystem().getName(), exception);
Logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + vectorDependency.getVersioningSystem().getName(), exception);
break;
}
@ -287,7 +279,7 @@ public final class DependencyResolver {
try {
versioningSystemEquals = vectorDependency.getVersioningSystem().getDeclaredConstructor(String.class).newInstance(versionEqual.toString());
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) {
logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + vectorDependency.getVersioningSystem().getName(), exception);
Logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + vectorDependency.getVersioningSystem().getName(), exception);
break;
}
@ -303,7 +295,7 @@ public final class DependencyResolver {
try {
versioningSystemSmaller = vectorDependency.getVersioningSystem().getDeclaredConstructor(String.class).newInstance(versionSmaller.toString());
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) {
logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + vectorDependency.getVersioningSystem().getName(), exception);
Logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + vectorDependency.getVersioningSystem().getName(), exception);
break;
}
if (!versionBigger.isEmpty())
@ -311,7 +303,7 @@ public final class DependencyResolver {
try {
versioningSystemBigger = vectorDependency.getVersioningSystem().getDeclaredConstructor(String.class).newInstance(versionBigger.toString());
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) {
logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + vectorDependency.getVersioningSystem().getName(), exception);
Logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + vectorDependency.getVersioningSystem().getName(), exception);
break;
}

File diff suppressed because it is too large Load diff

View file

@ -1,254 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.utility;
import de.staropensource.engine.base.event.ThrowableCatchEvent;
import de.staropensource.engine.base.exception.TristateConversionException;
import de.staropensource.engine.base.type.Tristate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Range;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.stream.Collectors;
/**
* Contains smaller functions that don't fit into other utility classes.
*
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class Miscellaneous {
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha6
*/
private Miscellaneous() {}
/**
* Converts a boolean into an integer.
*
* @param bool boolean to convert
* @return converted integer
* @since v1-alpha2
*/
@Range(from = 0, to = 1)
public static int getIntegerizedBoolean(boolean bool) {
return bool ? 1 : 0;
}
/**
* Converts an integer into a {@link Tristate}.
*
* @param integer integer to convert
* @return expected boolean result, except if neither {@code 0} or {@code 1}, in which case {@link Tristate#UNSET} is returned
* @since v1-alpha2
*/
public static Tristate getTristatedInteger(@Range(from = 0, to = 1) int integer) {
return switch (integer) {
case 0 -> Tristate.TRUE;
case 1 -> Tristate.FALSE;
default -> Tristate.UNSET;
};
}
/**
* Converts an integer into a {@link Tristate} and then into a boolean.
*
* @param integer integer to convert
* @return booleanized integer
* @throws TristateConversionException when encountering {@link Tristate#UNSET}.
* @since v1-alpha2
*/
public static boolean getBooleanizedInteger(@Range(from = 0, to = 1) int integer) throws TristateConversionException {
return getTristatedInteger(integer).toBoolean();
}
/**
* Searches for a value in a {@link Map}.
*
* @param map map to use
* @param value value to search for
* @return all keys matching the specified value
* @since v1-alpha0
*/
public static Set<?> getMapValues(@NotNull Map<?, ?> map, @Nullable Object value) {
return map
.entrySet().stream()
.filter(entry -> Objects.equals(entry.getValue(), value))
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
}
/**
* Counts the occurrences of a substring inside of a string.
*
* @param string string to search
* @param substring substring to search for
* @return occurrences
*/
public static long countOccurrences(@NotNull String string, @NotNull String substring) {
return (string.length() - string.replace(substring, "").length()) / substring.length();
}
/**
* Returns the correct separator to use when splitting a string.
*
* @param string string to split
* @param separators separators to check
* @param requiredOccurrences exact amount of occurrences for a separator to be deemed valid
* @return separator to use or {@code null}
* @since v1-alpha1
*/
public static @Nullable String getSeparator(@NotNull String string, @NotNull String @NotNull [] separators, int requiredOccurrences) {
if (string.isBlank() || separators.length == 0 || requiredOccurrences == 0)
return null;
for (String separator : separators)
if (countOccurrences(string, separator) == requiredOccurrences)
return separator;
return null;
}
/**
* Returns the correct separator to use when splitting a string.
*
* @param string string to split
* @param separators separators to check
* @param minimumOccurrences minimum amount of occurrences for a separator to be deemed valid
* @return separator to use or {@code null}
* @since v1-alpha1
*/
public static @Nullable String getSeparator(@NotNull String string, List<String> separators, Integer minimumOccurrences) {
for (String separator : separators)
if (countOccurrences(string, separator) >= minimumOccurrences)
return separator;
return null;
}
/**
* Measures the execution time of a {@link Runnable}.
*
* @param runnable {@link Runnable} to execute
* @return execution time in milliseconds
* @see Runnable
* @since v1-alpha0
*/
public static long measureExecutionTime(@NotNull Runnable runnable) {
long initTime = System.currentTimeMillis();
runnable.run();
return System.currentTimeMillis() - initTime;
}
/**
* Executes a {@link Runnable} and emits {@link ThrowableCatchEvent} if a throwable is caught.
*
* @param runnable {@link Runnable} to execute
* @param identifier some identifier to distinguish {@link Runnable}s
* @since v1-alpha1
*/
public static void executeSafely(@NotNull Runnable runnable, @NotNull String identifier) {
try {
runnable.run();
} catch (Throwable throwable) {
new ThrowableCatchEvent().callEvent(throwable, identifier);
}
}
/**
* Forcefully invokes the garbage collector
* and blocks execution until finished.
* If you want to run it in parallel to your
* program, consider running it in a {@code VirtualThread}.
* <p>
* This method does not guarantee full garbage collection,
* as the JVM only hints the garbage collector to do it's job.
* This is because all garbage collectors are non-deterministic.
*
* @since v1-alpha0
*/
@SuppressWarnings("UnusedAssignment")
public static void invokeGarbageCollector() {
Object object = new Object();
WeakReference<Object> weakReference = new WeakReference<>(object);
object = null;
while(weakReference.get() != null) System.gc();
}
/**
* Ensures that the code is running on the main thread.
*
* @return {@code true} if running on the main thread, {@code false} otherwise
* @since v1-alpha2
*/
public static boolean onMainThread() {
return Thread.currentThread().threadId() == 1;
}
/**
* Returns the {@code Caused by} message usually found when the JVM prints a throwable.
*
* @param throwable {@link Throwable} to use
* @return stack trace header
* @since v1-alpha4
*/
public static @NotNull String getStackTraceHeader(@NotNull Throwable throwable) {
return "Caused by: " + throwable.getClass().getName() + (throwable.getMessage() == null ? "" : ": " + throwable.getMessage());
}
/**
* Converts an array of {@link StackTraceElement}s into a regular string.
*
* @param stacktrace array of {@link StackTraceElement}s to convert
* @param indent if all lines should be indented with a single {@code \t} character, like in regular stack traces
* @return converted stacktrace string
* @since v1-alpha4
*/
public static @NotNull String getStackTraceAsString(@NotNull StackTraceElement @NotNull [] stacktrace, boolean indent) {
StringBuilder output = new StringBuilder();
for (StackTraceElement element : stacktrace) {
if (!output.isEmpty())
output.append("\n");
if (indent)
output.append("\t");
output.append("at ").append(element);
}
return output.toString();
}
/**
* Converts the stacktrace of a throwable into a regular string.
*
* @param throwable throwable to derive the stacktrace from
* @param indent if all lines should be indented with a single {@code \t} character, like in regular stack traces
* @return converted stacktrace string
* @since v1-alpha4
*/
public static @NotNull String getStackTraceAsString(@NotNull Throwable throwable, boolean indent) {
return getStackTraceAsString(throwable.getStackTrace(), indent);
}
}

View file

@ -22,7 +22,6 @@ package de.staropensource.engine.base.utility;
import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.internal.implementation.placeholder.*;
import de.staropensource.engine.base.logging.LoggerInstance;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
@ -50,14 +49,6 @@ public final class PlaceholderEngine {
@Getter
private static PlaceholderEngine instance;
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha1
*/
private final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").build();
/**
* Contains all global placeholders.
*
@ -106,6 +97,7 @@ public final class PlaceholderEngine {
placeholders.add(new EngineGitDirty());
// engine_version*
placeholders.add(new EngineVersion());
placeholders.add(new EngineVersionCodename());
placeholders.add(new EngineVersionVersion());
placeholders.add(new EngineVersionType());
placeholders.add(new EngineVersionTyperelease());

View file

@ -19,7 +19,7 @@
package de.staropensource.engine.base.utility;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.Tristate;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
@ -49,14 +49,6 @@ public final class PropertiesReader {
@Getter
private static final @NotNull PropertiesReader instance = new PropertiesReader(System.getProperties());
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha0
*/
private final @NotNull LoggerInstance logger;
/**
* Contains the {@link Properties} used by this parser instance to read properties.
*
@ -80,7 +72,6 @@ public final class PropertiesReader {
*/
public PropertiesReader(@NotNull Properties properties) {
this.properties = properties;
this.logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").setMetadata(String.valueOf(properties.hashCode())).build();
}
/**
@ -94,7 +85,7 @@ public final class PropertiesReader {
*/
public @NotNull String getString(@NotNull String name) throws NullPointerException {
if (properties.getProperty(name) == null) {
logger.sarn("Unable to get String from property '" + name + "': Property does not exist");
Logger.sarn("Unable to get String from property '" + name + "': Property does not exist");
throw new NullPointerException("Unable to get String from property '" + name + "': Property does not exist");
}
return properties.getProperty(name);
@ -111,7 +102,7 @@ public final class PropertiesReader {
*/
public boolean getBoolean(@NotNull String name) throws NullPointerException {
if (properties.getProperty(name) == null) {
logger.sarn("Unable to get Boolean from property '" + name + "': Property does not exist");
Logger.sarn("Unable to get Boolean from property '" + name + "': Property does not exist");
throw new NullPointerException("Unable to get Boolean from property '" + name + "': Property does not exist");
}
@ -136,7 +127,7 @@ public final class PropertiesReader {
*/
public @NotNull Tristate getTristate(@NotNull String name) throws NullPointerException {
if (properties.getProperty(name) == null) {
logger.sarn("Unable to get Tristate from property '" + name + "': Property does not exist");
Logger.sarn("Unable to get Tristate from property '" + name + "': Property does not exist");
throw new NullPointerException("Unable to get Tristate from property '" + name + "': Property does not exist");
}
@ -165,14 +156,14 @@ public final class PropertiesReader {
*/
public byte getByte(@NotNull String name) throws NullPointerException, NumberFormatException {
if (properties.getProperty(name) == null) {
logger.sarn("Unable to get Byte from property '" + name + "': Property does not exist");
Logger.sarn("Unable to get Byte from property '" + name + "': Property does not exist");
throw new NullPointerException("Unable to get Byte from property '" + name + "': Property does not exist");
}
try {
return Byte.parseByte(properties.getProperty(name));
} catch (NumberFormatException exception) {
logger.sarn("Unable to get Byte from property '" + name + "': String cannot be parsed as a Byte.");
Logger.sarn("Unable to get Byte from property '" + name + "': String cannot be parsed as a Byte.");
throw exception;
}
}
@ -189,14 +180,14 @@ public final class PropertiesReader {
*/
public short getShort(@NotNull String name) throws NullPointerException, NumberFormatException {
if (properties.getProperty(name) == null) {
logger.sarn("Unable to get Short from property '" + name + "': Property does not exist");
Logger.sarn("Unable to get Short from property '" + name + "': Property does not exist");
throw new NullPointerException("Unable to get Short from property '" + name + "': Property does not exist");
}
try {
return Short.parseShort(properties.getProperty(name));
} catch (NumberFormatException exception) {
logger.sarn("Unable to get Short from property '" + name + "': String cannot be parsed as a Short.");
Logger.sarn("Unable to get Short from property '" + name + "': String cannot be parsed as a Short.");
throw exception;
}
}
@ -214,7 +205,7 @@ public final class PropertiesReader {
*/
public int getInteger(@NotNull String name, boolean unsigned) throws NullPointerException, NumberFormatException {
if (properties.getProperty(name) == null) {
logger.sarn("Unable to get Integer from property '" + name + "': Property does not exist");
Logger.sarn("Unable to get Integer from property '" + name + "': Property does not exist");
throw new NullPointerException("Unable to get Integer from property '" + name + "': Property does not exist");
}
@ -224,7 +215,7 @@ public final class PropertiesReader {
else
return Integer.parseInt(properties.getProperty(name));
} catch (NumberFormatException exception) {
logger.sarn("Unable to get Integer from property '" + name + "': String cannot be parsed as an Integer.");
Logger.sarn("Unable to get Integer from property '" + name + "': String cannot be parsed as an Integer.");
throw exception;
}
}
@ -242,7 +233,7 @@ public final class PropertiesReader {
*/
public long getLong(@NotNull String name, boolean unsigned) throws NullPointerException, NumberFormatException {
if (properties.getProperty(name) == null) {
logger.sarn("Unable to get Long from property '" + name + "': Property does not exist");
Logger.sarn("Unable to get Long from property '" + name + "': Property does not exist");
throw new NullPointerException("Unable to get Long from property '" + name + "': Property does not exist");
}
@ -252,7 +243,7 @@ public final class PropertiesReader {
else
return Long.parseLong(properties.getProperty(name));
} catch (NumberFormatException exception) {
logger.sarn("Unable to get Long from property '" + name + "': String cannot be parsed as a Long.");
Logger.sarn("Unable to get Long from property '" + name + "': String cannot be parsed as a Long.");
throw exception;
}
}
@ -269,14 +260,14 @@ public final class PropertiesReader {
*/
public float getFloat(@NotNull String name) throws NullPointerException, NumberFormatException {
if (properties.getProperty(name) == null) {
logger.sarn("Unable to get Float from property '" + name + "': Property does not exist");
Logger.sarn("Unable to get Float from property '" + name + "': Property does not exist");
throw new NullPointerException("Unable to get Float from property '" + name + "': Property does not exist");
}
try {
return Float.parseFloat(properties.getProperty(name));
} catch (NumberFormatException exception) {
logger.sarn("Unable to get Float from property '" + name + "': String cannot be parsed as a Float.");
Logger.sarn("Unable to get Float from property '" + name + "': String cannot be parsed as a Float.");
throw exception;
}
}
@ -293,17 +284,17 @@ public final class PropertiesReader {
*/
public double getDouble(@NotNull String name) throws NullPointerException, NumberFormatException {
if (properties.getProperty(name) == null) {
logger.sarn("Unable to get Double from property '" + name + "': Property does not exist");
Logger.sarn("Unable to get Double from property '" + name + "': Property does not exist");
throw new NullPointerException("Unable to get Double from property '" + name + "': Property does not exist");
}
try {
return Double.parseDouble(properties.getProperty(name));
} catch (NullPointerException exception) {
logger.sarn("Unable to get Double from property '" + name + "': String is null.");
Logger.sarn("Unable to get Double from property '" + name + "': String is null.");
throw exception;
} catch (NumberFormatException exception) {
logger.sarn("Unable to get Double from property '" + name + "': String cannot be parsed as a Double.");
Logger.sarn("Unable to get Double from property '" + name + "': String cannot be parsed as a Double.");
throw exception;
}
}

View file

@ -19,13 +19,10 @@
package de.staropensource.engine.base.utility.information;
import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.VersionType;
import de.staropensource.engine.base.utility.Miscellaneous;
import de.staropensource.engine.base.utility.PropertiesReader;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.io.InputStream;
@ -44,14 +41,6 @@ import java.util.Properties;
*/
@SuppressWarnings({ "JavadocDeclaration" })
public final class EngineInformation {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha2
*/
private static final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(EngineInformation.class).setOrigin("ENGINE").build();
/**
* Contains the engine's version codename.
*
@ -348,14 +337,14 @@ public final class EngineInformation {
* @since v1-alpha1
*/
public static synchronized void update() {
logger.diag("Updating engine information");
Logger.diag("Updating engine information");
// Load properties from bundled gradle.properties
Properties gradleProperties = new Properties();
InputStream gradleStream = EngineInformation.class.getClassLoader().getResourceAsStream("sosengine-gradle.properties");
if (gradleStream == null) {
logger.crash("Unable to load build information: The bundled gradle.properties file could not be found.");
Logger.crash("Unable to load build information: The bundled gradle.properties file could not be found.");
return;
}
@ -363,7 +352,7 @@ public final class EngineInformation {
gradleProperties.load(gradleStream);
gradleStream.close();
} catch (IOException exception) {
logger.crash("Unable to load build information: InputStream 'gradleStream' failed", exception);
Logger.crash("Unable to load build information: InputStream 'gradleStream' failed", exception);
return;
}
@ -372,7 +361,7 @@ public final class EngineInformation {
Properties gitProperties = new Properties();
InputStream gitStream = EngineInformation.class.getClassLoader().getResourceAsStream("sosengine-git.properties");
if (gitStream == null) {
logger.error("Unable to load build information: The bundled git.properties file could not be found. Did you download a tarball?");
Logger.error("Unable to load build information: The bundled git.properties file could not be found. Did you download a tarball?");
// Fake information
gitProperties.setProperty("git.total.commit.count", "0");
@ -390,7 +379,7 @@ public final class EngineInformation {
gitProperties.load(gitStream);
gitStream.close();
} catch (IOException exception) {
logger.crash("Unable to load build information: InputStream 'gitStream' failed", exception);
Logger.crash("Unable to load build information: InputStream 'gitStream' failed", exception);
return;
}
}
@ -427,9 +416,7 @@ public final class EngineInformation {
calendar.setTime(date);
gitCommitTime = calendar.toZonedDateTime();
} catch (ParseException exception) {
System.out.println("Unable to load build information: Can't parse \"" + gitParser.getString("git.commit.time") + "\" using format \"yyyy-MM-dd'T'HH:mmZ\"");
System.out.println(Miscellaneous.getStackTraceHeader(exception) + "\n" + Miscellaneous.getStackTraceAsString(exception, true));
Engine.getInstance().shutdown(69);
Logger.crash("Unable to load build information: Can't parse \"" + gitParser.getString("git.commit.time") + "\" using format \"yyyy-MM-dd'T'HH:mmZ\"", exception);
return;
}
gitCommitterName = gitParser.getString("git.commit.user.name");

View file

@ -17,9 +17,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
//package de.staropensource.engine.base.utility.information;
/**
* Interfaces and abstract classes which can be used for implementing classes.
* Provides information about the environment
* ie. the operating system, paths, etc..
*
* @since v1-alpha6
* @since v1-alpha8
*/
package de.staropensource.engine.windowing.glfw.implementable;
//public final class EnvironmentInformation {
//}

View file

@ -19,11 +19,12 @@
package de.staropensource.engine.base.utility.information;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.base.logging.Logger;
import org.jetbrains.annotations.NotNull;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryUsage;
import java.util.Collections;
import java.util.List;
/**
@ -33,14 +34,6 @@ import java.util.List;
*/
@SuppressWarnings({ "unused" })
public final class JvmInformation {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha2
*/
private static final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(JvmInformation.class).setOrigin("ENGINE").build();
/**
* Creates and initializes an instance of this class.
*
@ -68,7 +61,7 @@ public final class JvmInformation {
try {
return Integer.parseInt(version);
} catch (NumberFormatException exception) {
logger.crash("Could not parse Java version: Integer conversion failed for string \"" + version + "\"", exception, true);
Logger.crash("Could not parse Java version: Integer conversion failed for string \"" + version + "\"", exception, true);
throw exception;
}
}
@ -117,11 +110,11 @@ public final class JvmInformation {
* Returns all arguments passed to the JVM.
* This excludes all arguments passed to the application.
*
* @return JVM arguments
* @return immutable list with all JVM arguments
* @since v1-alpha0
*/
public static @NotNull List<@NotNull String> getArguments() {
return ManagementFactory.getRuntimeMXBean().getInputArguments();
return Collections.unmodifiableList(ManagementFactory.getRuntimeMXBean().getInputArguments());
}
/**

View file

@ -0,0 +1,87 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.utility.misc;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collections;
/**
* Manipulates arrays.
*
* @since v1-alpha9
*/
public final class ArrayUtil {
/**
* Creates and initializes an
* instance of this class.
*
* @since v1-alpha9
*/
private ArrayUtil() {}
/**
* Removes the first {@code n} elements
* from the specified array.
* <p>
* If {@code n} is bigger than the
* amount of elements in the
* specified array, an empty array
* will be returned.
*
* @param <T> type
* @param array array to operate on
* @param n amount to remove
* @return array with the first elements removed
* @since v1-alpha9
*/
public static <T> @Nullable T @NotNull [] removeFirst(@Nullable T @NotNull [] array, int n) {
try {
return Arrays.copyOfRange(array, n, array.length);
} catch (ArrayIndexOutOfBoundsException | IllegalArgumentException exception) {
return Collections.emptyList().toArray(array);
}
}
/**
* Removes the last {@code n} elements
* from the specified array.
* <p>
* If {@code n} is bigger than the
* amount of elements in the
* specified array, an empty array
* will be returned.
*
* @param <T> type
* @param array array to operate on
* @param n amount to remove
* @return array with the last elements removed
* @since v1-alpha9
*/
public static <T> @Nullable T @NotNull [] removeLast(@Nullable T @NotNull [] array, int n) {
try {
return Arrays.copyOfRange(array, 0, array.length-n);
} catch (ArrayIndexOutOfBoundsException | IllegalArgumentException exception) {
return Collections.emptyList().toArray(array);
}
}
}

View file

@ -17,43 +17,49 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.utility;
package de.staropensource.engine.base.utility.misc;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
/**
* Converts various data types to {@link String}s.
* Converts arrays, arrays and maps to look like
* nicely formatted lists (as {@link String}s).
*
* @since v1-alpha4
* @since v1-alpha9
*/
public final class ListFormatter {
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha6
* @since v1-alpha9
*/
private ListFormatter() {}
/**
* Converts an array to a {@link String}.
* Converts the specified array to a {@link String}.
* <p>
* For {@code formatArray(array, ", ", " & ")} the
* something like following string will be returned:
* {@code element 1, element 2, element 3 & element 4}
*
* @param array array to convert
* @param array array to convert
* @param itemSeparator string used to separate two items
* @param finalSeparator string used to separate the final two items
* @return formatted string
* @since v1-alpha4
* @since v1-alpha9
*/
public static @NotNull String formatArray(@NotNull Object @NotNull [] array) {
public static @NotNull String formatArray(@NotNull Object @NotNull [] array, @NotNull String itemSeparator, @NotNull String finalSeparator) {
StringBuilder output = new StringBuilder();
for (int index = 0; index < array.length; index++) {
if (!output.isEmpty())
if (index == array.length - 1)
output.append(" & ");
output.append(finalSeparator);
else
output.append(", ");
output.append(itemSeparator);
output.append(array[index]);
}
@ -62,25 +68,50 @@ public final class ListFormatter {
}
/**
* Converts a {@link Set} to a {@link String}.
* Converts the specified array to a {@link String}.
* <p>
* This will produce something like this:
* {@code element 1, element 2, element 3 & element 4}
*
* @param set set to convert
* @param array array to convert
* @return formatted string
* @since v1-alpha4
* @since v1-alpha9
*/
public static @NotNull String formatSet(@NotNull Set<?> set) {
return formatArray(set.toArray());
public static @NotNull String formatArray(@NotNull Object @NotNull [] array) {
return formatArray(array, ", ", " & ");
}
/**
* Converts a {@link List} to a {@link String}.
/**
* Converts the specified array to a {@link String}.
* <p>
* For {@code formatArray(array, ", ", " & ")} the
* something like following string will be returned:
* {@code element 1, element 2, element 3 & element 4}
*
* @param list list to convert
* @param collection collection to convert
* @param itemSeparator string used to separate two items
* @param finalSeparator string used to separate the final two items
* @return formatted string
* @since v1-alpha4
* @since v1-alpha9
*/
public static @NotNull String formatList(@NotNull List<?> list) {
return formatArray(list.toArray());
public static @NotNull String formatCollection(@NotNull Collection<?> collection, @NotNull String itemSeparator, @NotNull String finalSeparator) {
return formatArray(collection.toArray(), itemSeparator, finalSeparator);
}
/**
* Converts the specified {@link Collection} to a {@link String}.
* <p>
* This will produce something like this:
* {@code element 1, element 2, element 3 & element 4}
*
* @param collection collection to convert
* @return formatted string
* @since v1-alpha9
*/
public static @NotNull String formatCollection(@NotNull Collection<?> collection) {
return formatArray(collection.toArray());
}
/**
@ -88,7 +119,7 @@ public final class ListFormatter {
*
* @param map map to convert
* @return formatted string
* @since v1-alpha4
* @since v1-alpha9
*/
public static @NotNull String formatMap(@NotNull Map<?, ?> map) {
StringBuilder output = new StringBuilder();

View file

@ -0,0 +1,211 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.utility.misc;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.stream.Collectors;
/**
* Contains the most miscellaneous of all miscellaneous methods.
*
* @since v1-alpha9
*/
@SuppressWarnings({ "unused" })
public final class Miscellaneous {
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha9
*/
private Miscellaneous() {}
/**
* Searches for a value in a {@link Map}.
*
* @param map map to use
* @param value value to search for
* @return all keys matching the specified value
* @since v1-alpha9
*/
public static Set<?> searchForValueInMap(@NotNull Map<?, ?> map, @Nullable Object value) {
return map
.entrySet().stream()
.filter(entry -> Objects.equals(entry.getValue(), value))
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
}
/**
* Measures the execution time of
* the specified {@link Runnable}.
*
* @param runnable {@link Runnable} to execute
* @return execution time in milliseconds
* @see Runnable
* @since v1-alpha9
*/
public static long measureExecutionTime(@NotNull Runnable runnable) {
long initTime = System.currentTimeMillis();
runnable.run();
return System.currentTimeMillis() - initTime;
}
/**
* Forcefully invokes the garbage collector
* and blocks execution until finished.
* If you want to run it in parallel to your
* program, consider running it in a thread.
* <p>
* This method does not guarantee full garbage collection,
* as the JVM only hints the garbage collector to do it's
* job. All garbage collectors are non-deterministic and
* cannot be invoked by force. And even if this method
* manages to invoke the garbage collector, a full garbage
* collection likely will never be archived. This is because
* the garbage collector will never throw everything into
* the trash. In addition, this method will only return if
* it's {@link WeakReference} becomes null. The garbage
* collector may or may not do more afterwards. This method
* just exists if someone wants to at least try to
* forcefully invoke the garbage collector. If you want
* a somewhat more reliable method, use Java Agents.
*
* @since v1-alpha9
*/
@SuppressWarnings("UnusedAssignment")
public static void invokeGarbageCollector() {
Object object = new Object();
WeakReference<Object> weakReference = new WeakReference<>(object);
object = null;
while(weakReference.get() != null) System.gc();
}
/**
* Returns if the code it is invoked by
* is running on the Java main thread.
*
* @return running on main thread?
* @since v1-alpha9
*/
public static boolean onMainThread() {
return Thread.currentThread().threadId() == 1;
}
/**
* Returns the {@code Caused by} message
* usually found in JVM stack traces.
*
* @param throwable {@link Throwable} to use
* @return {@link Throwable} header
* @since v1-alpha9
*/
public static @NotNull String throwableHeader(@NotNull Throwable throwable) {
return "Caused by: " + throwable.getClass().getName() + (throwable.getMessage() == null ? "" : ": " + throwable.getMessage());
}
/**
* Converts an array of {@link StackTraceElement}s into a regular string.
*
* @param stacktrace array of {@link StackTraceElement}s to convert
* @param indent if all lines shall be indented with a single tab.
* Enabling this will cause the output of this method
* to mimic the JVM's throwable handling output.
* @return specified stack trace as a String
* @since v1-alpha9
*/
public static @NotNull String stacktraceAsString(@NotNull StackTraceElement @NotNull [] stacktrace, boolean indent) {
StringBuilder output = new StringBuilder();
for (StackTraceElement element : stacktrace) {
if (!output.isEmpty())
output.append("\n");
if (indent)
output.append("\t");
output.append("at ").append(element);
}
return output.toString();
}
/**
* Converts an array of {@link StackTraceElement}s into a regular string.
*
* @param throwable throwable to derive the stacktrace from
* @param indent if all lines shall be indented with a single tab.
* Enabling this will cause the output of this method
* to mimic the JVM's throwable handling output.
* @return specified stack trace as a String
* @since v1-alpha9
*/
public static @NotNull String stacktraceAsString(@NotNull Throwable throwable, boolean indent) {
return stacktraceAsString(throwable.getStackTrace(), indent);
}
/**
* Returns the full stack trace of a {@link Throwable}.
* <p>
* This method recursively resolves, converts and then
* returns every {@link Throwable} and stacktrace found.
*
* @param throwable throwable to recursively convert
* @param indent if all lines shall be indented with a single tab.
* Enabling this will cause the output of this method
* to mimic the JVM's throwable handling output.
* @param includeHeader if to include the throwable header (see {@link #throwableHeader(Throwable)})
* @return full stack trace
* @since v1-alpha9
*/
public static @NotNull String stacktraceAsStringRecursive(@NotNull Throwable throwable, boolean indent, boolean includeHeader) {
StringBuilder output = new StringBuilder();
// Append header and stacktrace
if (includeHeader)
output
.append(throwableHeader(throwable))
.append("\n");
output.append(stacktraceAsString(throwable, indent));
// Process recursively
if (throwable.getCause() != null)
output
.append("\n")
.append(stacktraceAsStringRecursive(throwable.getCause(), indent, includeHeader));
if (throwable instanceof ClassNotFoundException exception && exception.getException() != null)
output
.append("\n")
.append(stacktraceAsStringRecursive(exception.getException(), indent, includeHeader));
if (throwable instanceof ExceptionInInitializerError exception && exception.getException() != null)
output
.append("\n")
.append(stacktraceAsStringRecursive(exception.getException(), indent, includeHeader));
if (throwable instanceof InvocationTargetException exception && exception.getTargetException() != null)
output
.append("\n")
.append(stacktraceAsStringRecursive(exception.getTargetException(), indent, includeHeader));
return output.toString();
}
}

View file

@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.utility;
package de.staropensource.engine.base.utility.misc;
import org.jetbrains.annotations.NotNull;
@ -27,31 +27,36 @@ import java.util.LinkedList;
/**
* Utility class for math operations.
*
* @since v1-alpha2
* @since v1-alpha9
*/
// All mean and double methods have been sourced
// from https://stackoverflow.com/a/4191729, tysm!
@SuppressWarnings({ "unused" })
public final class Math {
public final class NumberUtil {
/**
* Creates and initializes an instance of this class
*
* @since v1-alpha6
* @since v1-alpha9
*/
private Math() {}
private NumberUtil() {}
/**
* Adds padding zeros to a number.
* <p>
* Example:
* {@code padNumbers(505L, 5) = "00505"}
*
* @param number number
* @param length length
* @return the padded number
* @since v1-alpha2
* @since v1-alpha9
*/
public static @NotNull String padNumbers(long number, int length) {
return String.format("%0" + length + "d", number);
}
// -----> Number limiting
/**
* Ensures the integer is inside the
* specified bounds. If not, the
@ -61,10 +66,10 @@ public final class Math {
* @param max maximum value
* @param value value
* @return number in threshold
* @throws IndexOutOfBoundsException when the minimum value is bigger than the maximum value
* @since v1-alpha6
* @throws IndexOutOfBoundsException if the minimum value is bigger than the maximum value
* @since v1-alpha9
*/
public static int boundNumber(int min, int max, int value) throws IndexOutOfBoundsException {
public static int limitNumber(int min, int max, int value) throws IndexOutOfBoundsException {
if (min > max)
throw new IndexOutOfBoundsException();
@ -85,10 +90,10 @@ public final class Math {
* @param max maximum value
* @param value value
* @return number in threshold
* @throws IndexOutOfBoundsException when the minimum value is bigger than the maximum value
* @since v1-alpha6
* @throws IndexOutOfBoundsException if the minimum value is bigger than the maximum value
* @since v1-alpha9
*/
public static float boundNumber(float min, float max, float value) throws IndexOutOfBoundsException {
public static float limitNumber(float min, float max, float value) throws IndexOutOfBoundsException {
if (min > max)
throw new IndexOutOfBoundsException();
@ -109,10 +114,10 @@ public final class Math {
* @param max maximum value
* @param value value
* @return number in threshold
* @throws IndexOutOfBoundsException when the minimum value is bigger than the maximum value
* @since v1-alpha6
* @throws IndexOutOfBoundsException if the minimum value is bigger than the maximum value
* @since v1-alpha9
*/
public static double boundNumber(double min, double max, double value) throws IndexOutOfBoundsException {
public static double limitNumber(double min, double max, double value) throws IndexOutOfBoundsException {
if (min > max)
throw new IndexOutOfBoundsException();
@ -124,14 +129,16 @@ public final class Math {
return value;
}
// -----> Means and medians
/**
* Returns the mean of a collection of numbers.
*
* @param collection collection of {@code double}s
* @return mean
* @since v1-alpha2
* @since v1-alpha9
*/
public static double getMeanDouble(@NotNull Collection<@NotNull Double> collection) {
public static double calculateMeanDouble(@NotNull Collection<@NotNull Double> collection) {
double sum = 0;
for (double number : collection)
@ -145,9 +152,9 @@ public final class Math {
*
* @param collection collection of {@code float}s
* @return mean
* @since v1-alpha2
* @since v1-alpha9
*/
public static double getMeanFloat(@NotNull Collection<@NotNull Float> collection) {
public static double calculateMeanFloat(@NotNull Collection<@NotNull Float> collection) {
double sum = 0;
for (float number : collection)
@ -161,9 +168,9 @@ public final class Math {
*
* @param collection collection of {@code long}s
* @return mean
* @since v1-alpha2
* @since v1-alpha9
*/
public static double getMeanLong(@NotNull Collection<@NotNull Long> collection) {
public static double calculateMeanLong(@NotNull Collection<@NotNull Long> collection) {
double sum = 0;
for (long number : collection)
@ -177,9 +184,9 @@ public final class Math {
*
* @param collection collection of {@code int}s
* @return mean
* @since v1-alpha2
* @since v1-alpha9
*/
public static double getMeanInt(@NotNull Collection<@NotNull Integer> collection) {
public static double calculateMeanInt(@NotNull Collection<@NotNull Integer> collection) {
double sum = 0;
for (int number : collection)
@ -193,9 +200,9 @@ public final class Math {
*
* @param list linked list of {@code double}s
* @return median
* @since v1-alpha2
* @since v1-alpha9
*/
public static double getMedianDouble(@NotNull LinkedList<@NotNull Double> list) {
public static double calculateMedianDouble(@NotNull LinkedList<@NotNull Double> list) {
int middle = list.size() / 2;
if (list.size() % 2 == 1)
return list.get(middle);
@ -208,9 +215,9 @@ public final class Math {
*
* @param list linked list of {@code float}s
* @return median
* @since v1-alpha2
* @since v1-alpha9
*/
public static double getMedianFloat(@NotNull LinkedList<@NotNull Float> list) {
public static double calculateMedianFloat(@NotNull LinkedList<@NotNull Float> list) {
int middle = list.size() / 2;
if (list.size() % 2 == 1)
return list.get(middle);
@ -223,9 +230,9 @@ public final class Math {
*
* @param list linked list of {@code long}s
* @return median
* @since v1-alpha2
* @since v1-alpha9
*/
public static double getMedianLong(@NotNull LinkedList<@NotNull Long> list) {
public static double calculateMedianLong(@NotNull LinkedList<@NotNull Long> list) {
int middle = list.size() / 2;
if (list.size() % 2 == 1)
return list.get(middle);
@ -238,9 +245,9 @@ public final class Math {
*
* @param list linked list of {@code int}s
* @return median
* @since v1-alpha2
* @since v1-alpha9
*/
public static double getMedianInt(@NotNull LinkedList<@NotNull Integer> list) {
public static double calculateMedianInt(@NotNull LinkedList<@NotNull Integer> list) {
int middle = list.size() / 2;
if (list.size() % 2 == 1)
return list.get(middle);

View file

@ -0,0 +1,93 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.utility.misc;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Manipulates strings and characters.
*
* @since v1-alpha9
*/
public final class StringUtil {
/**
* Creates and initializes an
* instance of this class.
*
* @since v1-alpha9
*/
private StringUtil() {}
/**
* Counts the number of occurrences of the specified substring inside the specified string.
*
* @param string string to search in
* @param substring substring to count occurrences for
* @return number of times the specified substring was found inside the specified string
* @since v1-alpha9
*/
public static long count(@NotNull String string, @NotNull String substring) {
return (string.length() - string.replace(substring, "").length()) / substring.length();
}
/**
* Searches for the specified separators
* in the specified string and returns
* the first separator which matches the
* specified amount of required occurrences.
*
* @param string string to operate on
* @param separators separators to check for
* @param requiredOccurrences exact amount of occurrences for a separator to be deemed valid
* @return separator to use or {@code null}
* @since v1-alpha9
*/
public static @Nullable String getSeparatorRequired(@NotNull String string, @NotNull String @NotNull [] separators, int requiredOccurrences) {
if (string.isBlank() || separators.length == 0 || requiredOccurrences == 0)
return null;
for (String separator : separators)
if (count(string, separator) == requiredOccurrences)
return separator;
return null;
}
/**
* Searches for the specified separators
* in the specified string and returns
* the first separator which matches the
* specified amount of minimum occurrences.
*
* @param string string to operate on
* @param separators separators to check for
* @param minimumOccurrences minimum amount of occurrences for a separator to be deemed valid
* @return separator to use or {@code null}
* @since v1-alpha9
*/
public static @Nullable String getSeparatorMinimum(@NotNull String string, @NotNull String @NotNull [] separators, int minimumOccurrences) {
for (String separator : separators)
if (count(string, separator) >= minimumOccurrences)
return separator;
return null;
}
}

View file

@ -0,0 +1,61 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU Affero General Public License v3
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.utility.misc;
import de.staropensource.engine.base.type.Tristate;
import org.jetbrains.annotations.Range;
/**
* Converts various data types into other data types.
*
* @since v1-alpha9
*/
public final class TypeConversion {
/**
* Creates and initializes an
* instance of this class.
*
* @since v1-alpha9
*/
private TypeConversion() {}
/**
* Converts a boolean into an integer.
*
* @param bool boolean to convert
* @return converted integer
* @since v1-alpha9
*/
@Range(from = 0, to = 1)
public static int booleanToInteger(boolean bool) {
return bool ? 1 : 0;
}
/**
* Converts an integer into a {@link Tristate} and then into a boolean.
*
* @param integer integer to convert
* @return booleanized integer
* @since v1-alpha9
*/
public static boolean integerToBoolean(@Range(from = 0, to = 1) int integer) throws IndexOutOfBoundsException {
return integer != 0;
}
}

View file

@ -18,8 +18,8 @@
*/
/**
* Code of the GLFW subsystem.
* Miscellaneous utility classes.
*
* @since v1-alpha2
* @since v1-alpha9
*/
package de.staropensource.engine.windowing.glfw;
package de.staropensource.engine.base.utility.misc;

View file

@ -20,7 +20,7 @@
/**
* Provides (utility) classes specifically made for one task.
*
* @see de.staropensource.engine.base.utility.Miscellaneous
* @see de.staropensource.engine.base.utility.misc.Miscellaneous
* @since v1-alpha0
*/
package de.staropensource.engine.base.utility;

View file

@ -18,23 +18,22 @@ module sosengine.base {
exports de.staropensource.engine.base.implementable;
exports de.staropensource.engine.base.implementable.helper;
exports de.staropensource.engine.base.utility.information;
exports de.staropensource.engine.base.implementation.shortcode;
exports de.staropensource.engine.base.implementation.versioning;
exports de.staropensource.engine.base.event;
exports de.staropensource.engine.base.exception;
exports de.staropensource.engine.base.exception.dependency;
exports de.staropensource.engine.base.exception.reflection;
exports de.staropensource.engine.base.exception.versioning;
exports de.staropensource.engine.base.internal.event; // Internal: Required for subsystems
exports de.staropensource.engine.base.logging;
exports de.staropensource.engine.base.implementation.logging;
exports de.staropensource.engine.base.reflection;
exports de.staropensource.engine.base.type;
exports de.staropensource.engine.base.type.immutable;
exports de.staropensource.engine.base.type.logging;
exports de.staropensource.engine.base.type.reflection;
exports de.staropensource.engine.base.type.vector;
exports de.staropensource.engine.base.utility;
exports de.staropensource.engine.base.implementation.shortcode;
exports de.staropensource.engine.base.utility.misc;
// Reflection access
opens de.staropensource.engine.base;
@ -42,21 +41,20 @@ module sosengine.base {
opens de.staropensource.engine.base.implementable;
opens de.staropensource.engine.base.implementable.helper;
opens de.staropensource.engine.base.utility.information;
opens de.staropensource.engine.base.implementation.shortcode;
opens de.staropensource.engine.base.implementation.versioning;
opens de.staropensource.engine.base.event;
opens de.staropensource.engine.base.exception;
opens de.staropensource.engine.base.exception.dependency;
opens de.staropensource.engine.base.exception.reflection;
opens de.staropensource.engine.base.exception.versioning;
opens de.staropensource.engine.base.internal.event; // Internal: Required for subsystems
opens de.staropensource.engine.base.logging;
opens de.staropensource.engine.base.implementation.logging;
opens de.staropensource.engine.base.reflection;
opens de.staropensource.engine.base.type;
opens de.staropensource.engine.base.type.immutable;
opens de.staropensource.engine.base.type.logging;
opens de.staropensource.engine.base.type.reflection;
opens de.staropensource.engine.base.type.vector;
opens de.staropensource.engine.base.utility;
opens de.staropensource.engine.base.implementation.shortcode;
opens de.staropensource.engine.base.utility.misc;
}

Some files were not shown because too many files have changed in this diff Show more