From 66b3a2e3efede506e04e50c2e1c07534ad0a27a5 Mon Sep 17 00:00:00 2001 From: Nils M Date: Tue, 25 Jun 2024 00:50:04 +0200 Subject: [PATCH 01/17] Refactored DiscordWebhook logic and removed lombok references --- .../BackgroundWorkerThreadService.java | 1 + .../utils/datastructure/NotifiableList.java | 1 - .../network/webhook/discord/EmbedAuthor.java | 5 ---- .../network/webhook/discord/EmbedField.java | 6 ----- .../network/webhook/discord/EmbedFooter.java | 10 ++----- playground/pom.xml | 27 ------------------- pom.xml | 1 - 7 files changed, 3 insertions(+), 48 deletions(-) delete mode 100644 playground/pom.xml diff --git a/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorkerThreadService.java b/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorkerThreadService.java index e9e599d..9ed5e3a 100644 --- a/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorkerThreadService.java +++ b/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorkerThreadService.java @@ -92,6 +92,7 @@ public ScheduledFuture submitOnce(final Runnable runnable, final String name, /** * Stops the service and waits 5 seconds for all tasks to finish */ + @Override public void shutdown() { LOGGER.atInfo().withMessage("Shutting down background worker").log(); super.shutdown(); diff --git a/datastructures/src/main/java/de/haevn/utils/datastructure/NotifiableList.java b/datastructures/src/main/java/de/haevn/utils/datastructure/NotifiableList.java index a43bf9a..fed506b 100644 --- a/datastructures/src/main/java/de/haevn/utils/datastructure/NotifiableList.java +++ b/datastructures/src/main/java/de/haevn/utils/datastructure/NotifiableList.java @@ -56,7 +56,6 @@ public void clear() { super.clear(); } - public static interface IListUpdateConsumer { void changed(final T object, final boolean added); } diff --git a/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedAuthor.java b/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedAuthor.java index 2af6932..781af06 100644 --- a/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedAuthor.java +++ b/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedAuthor.java @@ -9,9 +9,4 @@ public EmbedAuthor(String name, String url) { this(name, url, null); } - public EmbedAuthor(String name, String url, String icon_url) { - this.name = name; - this.url = url; - this.icon_url = icon_url; - } } diff --git a/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedField.java b/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedField.java index 98353c8..e529690 100644 --- a/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedField.java +++ b/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedField.java @@ -4,10 +4,4 @@ public record EmbedField(String name, String value, boolean inline) { public EmbedField(String name, String value) { this(name, value, false); } - - public EmbedField(String name, String value, boolean inline) { - this.name = name; - this.value = value; - this.inline = inline; - } } diff --git a/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedFooter.java b/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedFooter.java index efc29fa..aa7b2c2 100644 --- a/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedFooter.java +++ b/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedFooter.java @@ -5,13 +5,7 @@ public EmbedFooter(String text) { this(text, null, null); } - public EmbedFooter(String text, String icon_url) { - this(text, icon_url, null); - } - - public EmbedFooter(String text, String icon_url, String proxy_icon_url) { - this.text = text; - this.icon_url = icon_url; - this.proxy_icon_url = proxy_icon_url; + public EmbedFooter(String text, String iconUrl) { + this(text, iconUrl, null); } } diff --git a/playground/pom.xml b/playground/pom.xml deleted file mode 100644 index 2e24e4c..0000000 --- a/playground/pom.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - 4.0.0 - - de.haevn - Utility - 2.1 - - - playground - - - 22 - 22 - UTF-8 - - - - - de.haevn - UtilsCore - 2.1 - - - \ No newline at end of file diff --git a/pom.xml b/pom.xml index 308a438..9495040 100644 --- a/pom.xml +++ b/pom.xml @@ -183,6 +183,5 @@ logger network utils - playground \ No newline at end of file From 4f056797aedc2a67973dfcd53f7da9a4bc7f7674 Mon Sep 17 00:00:00 2001 From: Nils M Date: Tue, 25 Jun 2024 00:50:04 +0200 Subject: [PATCH 02/17] Refactored DiscordWebhook logic and removed lombok references --- .../BackgroundWorkerThreadService.java | 1 + .../utils/datastructure/NotifiableList.java | 1 - .../network/webhook/discord/EmbedAuthor.java | 5 ---- .../network/webhook/discord/EmbedField.java | 6 ----- .../network/webhook/discord/EmbedFooter.java | 10 ++----- playground/pom.xml | 27 ------------------- pom.xml | 2 +- 7 files changed, 4 insertions(+), 48 deletions(-) delete mode 100644 playground/pom.xml diff --git a/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorkerThreadService.java b/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorkerThreadService.java index e9e599d..9ed5e3a 100644 --- a/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorkerThreadService.java +++ b/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorkerThreadService.java @@ -92,6 +92,7 @@ public ScheduledFuture submitOnce(final Runnable runnable, final String name, /** * Stops the service and waits 5 seconds for all tasks to finish */ + @Override public void shutdown() { LOGGER.atInfo().withMessage("Shutting down background worker").log(); super.shutdown(); diff --git a/datastructures/src/main/java/de/haevn/utils/datastructure/NotifiableList.java b/datastructures/src/main/java/de/haevn/utils/datastructure/NotifiableList.java index a43bf9a..fed506b 100644 --- a/datastructures/src/main/java/de/haevn/utils/datastructure/NotifiableList.java +++ b/datastructures/src/main/java/de/haevn/utils/datastructure/NotifiableList.java @@ -56,7 +56,6 @@ public void clear() { super.clear(); } - public static interface IListUpdateConsumer { void changed(final T object, final boolean added); } diff --git a/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedAuthor.java b/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedAuthor.java index 2af6932..781af06 100644 --- a/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedAuthor.java +++ b/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedAuthor.java @@ -9,9 +9,4 @@ public EmbedAuthor(String name, String url) { this(name, url, null); } - public EmbedAuthor(String name, String url, String icon_url) { - this.name = name; - this.url = url; - this.icon_url = icon_url; - } } diff --git a/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedField.java b/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedField.java index 98353c8..e529690 100644 --- a/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedField.java +++ b/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedField.java @@ -4,10 +4,4 @@ public record EmbedField(String name, String value, boolean inline) { public EmbedField(String name, String value) { this(name, value, false); } - - public EmbedField(String name, String value, boolean inline) { - this.name = name; - this.value = value; - this.inline = inline; - } } diff --git a/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedFooter.java b/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedFooter.java index efc29fa..aa7b2c2 100644 --- a/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedFooter.java +++ b/network/src/main/java/de/haevn/utils/network/webhook/discord/EmbedFooter.java @@ -5,13 +5,7 @@ public EmbedFooter(String text) { this(text, null, null); } - public EmbedFooter(String text, String icon_url) { - this(text, icon_url, null); - } - - public EmbedFooter(String text, String icon_url, String proxy_icon_url) { - this.text = text; - this.icon_url = icon_url; - this.proxy_icon_url = proxy_icon_url; + public EmbedFooter(String text, String iconUrl) { + this(text, iconUrl, null); } } diff --git a/playground/pom.xml b/playground/pom.xml deleted file mode 100644 index 2e24e4c..0000000 --- a/playground/pom.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - 4.0.0 - - de.haevn - Utility - 2.1 - - - playground - - - 22 - 22 - UTF-8 - - - - - de.haevn - UtilsCore - 2.1 - - - \ No newline at end of file diff --git a/pom.xml b/pom.xml index 308a438..3758a94 100644 --- a/pom.xml +++ b/pom.xml @@ -169,6 +169,7 @@ + html system @@ -183,6 +184,5 @@ logger network utils - playground \ No newline at end of file From ab199333afd0363de4b94712c45ce43f3d3fff40 Mon Sep 17 00:00:00 2001 From: Nils M Date: Tue, 25 Jun 2024 12:52:38 +0200 Subject: [PATCH 03/17] Refactored DiscordWebhook logic and removed lombok references --- crypto/pom.xml | 14 +++ .../de/haevn/utils/crypto/Base32Util.java | 65 ++++++++++ .../haevn/utils/crypto/OneTimePassword.java | 112 ++++++++++++++++++ crypto/src/main/java/module-info.java | 3 + .../main/java/de/haevn/utils/ArrayUtils.java | 6 + .../main/java/de/haevn/utils/StringUtils.java | 9 ++ 6 files changed, 209 insertions(+) create mode 100644 crypto/src/main/java/de/haevn/utils/crypto/Base32Util.java create mode 100644 crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java create mode 100644 utils/src/main/java/de/haevn/utils/ArrayUtils.java diff --git a/crypto/pom.xml b/crypto/pom.xml index 7539053..e61141a 100644 --- a/crypto/pom.xml +++ b/crypto/pom.xml @@ -4,6 +4,20 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 crypto + + + de.haevn + utils + 2.1 + compile + + + de.haevn + annotations + 2.1 + compile + + de.haevn Utility diff --git a/crypto/src/main/java/de/haevn/utils/crypto/Base32Util.java b/crypto/src/main/java/de/haevn/utils/crypto/Base32Util.java new file mode 100644 index 0000000..08b28a4 --- /dev/null +++ b/crypto/src/main/java/de/haevn/utils/crypto/Base32Util.java @@ -0,0 +1,65 @@ +package de.haevn.utils.crypto; + +import de.haevn.annotations.Draft; + +@Draft +public final class Base32Util { + private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + private static final String PADDING = "="; + private static final int MASK = 0x1F; + + public Base32Util() { + } + + public static String encode(final String data) { + return encode(data.getBytes()); + } + + public static String encode(final byte[] data) { + final var length = (data.length * 8 + 4) * 0.2; + final StringBuilder result = new StringBuilder((int)length); + int buffer = data[0]; + int next = 1; + int bitsLeft = 8; + while (bitsLeft > 0 || next < data.length) { + if (bitsLeft < 5) { + if (next < data.length) { + buffer <<= 8; + buffer |= data[next++] & 0xFF; + bitsLeft += 8; + } else { + final int pad = 5 - bitsLeft; + buffer <<= pad; + bitsLeft += pad; + } + } + final int index = MASK & (buffer >> (bitsLeft - 5)); + bitsLeft -= 5; + result.append(ALPHABET.charAt(index)); + } + + final int padding = result.length() % 8; + if (padding > 0) { + result.append(PADDING.repeat(8 - padding)); + } + + return result.toString(); + } + + public static byte[] decode(final String encodedString) { + final StringBuilder sb = new StringBuilder(); + for (char c : encodedString.toCharArray()) { + final int index = ALPHABET.indexOf(c); + sb.append(String.format("%5s", Integer.toBinaryString(index)).replace(' ', '0')); + } + + final String binaryString = sb.toString(); + final byte[] bytes = new byte[binaryString.length() / 8]; + for (int i = 0; i < bytes.length; i++) { + final String byteString = binaryString.substring(i * 8, (i + 1) * 8); + bytes[i] = (byte) Integer.parseInt(byteString, 2); + } + + return bytes; + } +} diff --git a/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java b/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java new file mode 100644 index 0000000..27826bb --- /dev/null +++ b/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java @@ -0,0 +1,112 @@ +package de.haevn.utils.crypto; + +import de.haevn.annotations.Draft; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import javax.imageio.ImageIO; +import javax.swing.*; +import javax.swing.border.Border; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.time.Instant; + +@Draft +public final class OneTimePassword { + + private static final long TIME_STEP = 30000L; + private static final int SECRET_KEY_LENGTH = 20; + + public static String generateTOTP(String secret) { + // Decode the Base64-encoded secret key + byte[] key = Base32Util.decode(secret); + + // Get the current timestamp + final long time = (Instant.now().toEpochMilli() / TIME_STEP); + + // Encode the time in a byte array + final byte[] data = ByteBuffer.allocate(8).putLong(time).array(); + + // Generate HMAC-SHA1 hash from the time and secret key + final byte[] hash = hmacSha1(key, data); + + // Extract the dynamic binary code + final int offset = hash[hash.length - 1] & 0xF; + final int binaryCode = (hash[offset] & 0x7F) << 24 | + (hash[offset + 1] & 0xFF) << 16 | + (hash[offset + 2] & 0xFF) << 8 | + (hash[offset + 3] & 0xFF); + + // Generate a 6-digit OTP + final int otp = binaryCode % 1_000_000; + + // Format the OTP to ensure it's 6 digits + return String.format("%06d", otp); + } + + private static byte[] hmacSha1(byte[] key, byte[] data) { + try { + final SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA1"); + final Mac mac = Mac.getInstance("HmacSHA1"); + mac.init(secretKeySpec); + return mac.doFinal(data); + } catch (NoSuchAlgorithmException | InvalidKeyException e) { + throw new RuntimeException("Error generating TOTP", e); + } + } + + public static String generateSecretKey() { + final SecureRandom random = new SecureRandom(); + byte[] bytes = new byte[SECRET_KEY_LENGTH]; + random.nextBytes(bytes); + return Base32Util.encode(bytes); + } + public static void main(String[] args) throws Exception { + + // Generate a secret key + String secret = generateSecretKey(); + + System.out.println("Secret: " + secret); + + URL url = new URL("https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=otpauth://totp/Test?secret=" + secret); + BufferedImage image = ImageIO.read(url); + JTextField secretField = new JTextField(secret); + + JLabel label = new JLabel(new ImageIcon(image)); + JLabel otp = new JLabel(); + + otp.setFont(new Font("Arial", Font.PLAIN, 20)); + secretField.setFont(new Font("Arial", Font.PLAIN, 20)); + secretField.setEditable(false); + + JFrame frame = new JFrame(); + + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.getContentPane().add(label, BorderLayout.CENTER); + frame.getContentPane().add(secretField, BorderLayout.NORTH); + frame.getContentPane().add(otp, BorderLayout.SOUTH); + + frame.pack(); + frame.setLocation(200, 200); + frame.setVisible(true); + + + while(true){ + String totp = generateTOTP(secret); + System.out.println("TOTP: " + totp); + otp.setText("TOTP: " + totp); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + } +} diff --git a/crypto/src/main/java/module-info.java b/crypto/src/main/java/module-info.java index 8f8ed21..75d76be 100644 --- a/crypto/src/main/java/module-info.java +++ b/crypto/src/main/java/module-info.java @@ -1,3 +1,6 @@ module de.haevn.utils.crypto { + requires de.haevn.utils.utils; + requires de.haevn.utils.annotations; + requires java.desktop; exports de.haevn.utils.crypto; } \ No newline at end of file diff --git a/utils/src/main/java/de/haevn/utils/ArrayUtils.java b/utils/src/main/java/de/haevn/utils/ArrayUtils.java new file mode 100644 index 0000000..7bb0a21 --- /dev/null +++ b/utils/src/main/java/de/haevn/utils/ArrayUtils.java @@ -0,0 +1,6 @@ +package de.haevn.utils; + + +public class ArrayUtils { + +} diff --git a/utils/src/main/java/de/haevn/utils/StringUtils.java b/utils/src/main/java/de/haevn/utils/StringUtils.java index 8d7cf9c..99ef293 100644 --- a/utils/src/main/java/de/haevn/utils/StringUtils.java +++ b/utils/src/main/java/de/haevn/utils/StringUtils.java @@ -88,4 +88,13 @@ public static String splitSecure(final String input, final char delimiter, final } return input; } + + public static String str2Hex(final String in){ + char[] chars = in.toCharArray(); + StringBuilder hex = new StringBuilder(); + for (char ch : chars) { + hex.append(Integer.toHexString((int) ch)); + } + return hex.toString(); + } } From d314346cb6167fbac9523c38de9a37a9511a667b Mon Sep 17 00:00:00 2001 From: Nils M Date: Tue, 25 Jun 2024 12:52:38 +0200 Subject: [PATCH 04/17] Refactored DiscordWebhook logic and removed lombok references --- .../de/haevn/utils/crypto/OneTimePassword.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java b/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java index 27826bb..18cb98c 100644 --- a/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java +++ b/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java @@ -86,16 +86,17 @@ public static void main(String[] args) throws Exception { secretField.setEditable(false); JFrame frame = new JFrame(); + Border padding = BorderFactory.createEmptyBorder(10, 10, 10, 10); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame.getContentPane().add(label, BorderLayout.CENTER); - frame.getContentPane().add(secretField, BorderLayout.NORTH); - frame.getContentPane().add(otp, BorderLayout.SOUTH); + frame.add(label, BorderLayout.CENTER); + frame.add(secretField, BorderLayout.NORTH); + frame.add(otp, BorderLayout.SOUTH); - frame.pack(); - frame.setLocation(200, 200); - frame.setVisible(true); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setVisible(true); + frame.pack(); + frame.setSize(450, 300); while(true){ String totp = generateTOTP(secret); From 0f3f898405b0acef6c0f3485de24e643314d380b Mon Sep 17 00:00:00 2001 From: Nils M Date: Tue, 25 Jun 2024 12:52:38 +0200 Subject: [PATCH 05/17] Refactored DiscordWebhook logic and removed lombok references --- .../de/haevn/utils/crypto/Base32Util.java | 2 - .../haevn/utils/crypto/OneTimePassword.java | 78 +++++++++++-------- 2 files changed, 44 insertions(+), 36 deletions(-) diff --git a/crypto/src/main/java/de/haevn/utils/crypto/Base32Util.java b/crypto/src/main/java/de/haevn/utils/crypto/Base32Util.java index 08b28a4..850cbd4 100644 --- a/crypto/src/main/java/de/haevn/utils/crypto/Base32Util.java +++ b/crypto/src/main/java/de/haevn/utils/crypto/Base32Util.java @@ -8,8 +8,6 @@ public final class Base32Util { private static final String PADDING = "="; private static final int MASK = 0x1F; - public Base32Util() { - } public static String encode(final String data) { return encode(data.getBytes()); diff --git a/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java b/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java index 18cb98c..c44b5fe 100644 --- a/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java +++ b/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java @@ -8,8 +8,12 @@ import javax.swing.*; import javax.swing.border.Border; import java.awt.*; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; import java.awt.image.BufferedImage; -import java.net.MalformedURLException; + +import java.io.IOException; +import java.net.URI; import java.net.URL; import java.nio.ByteBuffer; import java.security.InvalidKeyException; @@ -20,23 +24,16 @@ @Draft public final class OneTimePassword { - private static final long TIME_STEP = 30000L; + private static final long TIME_STEP = 30_000L; private static final int SECRET_KEY_LENGTH = 20; public static String generateTOTP(String secret) { - // Decode the Base64-encoded secret key byte[] key = Base32Util.decode(secret); - - // Get the current timestamp final long time = (Instant.now().toEpochMilli() / TIME_STEP); - // Encode the time in a byte array final byte[] data = ByteBuffer.allocate(8).putLong(time).array(); - - // Generate HMAC-SHA1 hash from the time and secret key final byte[] hash = hmacSha1(key, data); - // Extract the dynamic binary code final int offset = hash[hash.length - 1] & 0xF; final int binaryCode = (hash[offset] & 0x7F) << 24 | (hash[offset + 1] & 0xFF) << 16 | @@ -67,47 +64,60 @@ public static String generateSecretKey() { random.nextBytes(bytes); return Base32Util.encode(bytes); } - public static void main(String[] args) throws Exception { - // Generate a secret key - String secret = generateSecretKey(); - System.out.println("Secret: " + secret); + public static String generateCode() { + return generateTOTP(generateSecretKey()); + } + + public static String generateCode(final String secret) { + return generateTOTP(secret); + } + + public static String generateCodeAndShow(final String name) throws IOException { + return generateCodeAndShow(name, generateSecretKey()); + } + + public static String generateCodeAndShow(final String name, final String secret) throws IOException { + final String totp = generateTOTP(secret); - URL url = new URL("https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=otpauth://totp/Test?secret=" + secret); - BufferedImage image = ImageIO.read(url); - JTextField secretField = new JTextField(secret); + final String qrCodeUrl = "https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=otpauth://totp/%s?secret=%s"; + final URI uri = URI.create(String.format(qrCodeUrl, name, secret)); - JLabel label = new JLabel(new ImageIcon(image)); - JLabel otp = new JLabel(); + final BufferedImage image = ImageIO.read(uri.toURL()); + final JTextField secretField = new JTextField(secret); + final JLabel label = new JLabel(new ImageIcon(image)); + final JLabel otp = new JLabel(); otp.setFont(new Font("Arial", Font.PLAIN, 20)); secretField.setFont(new Font("Arial", Font.PLAIN, 20)); secretField.setEditable(false); - JFrame frame = new JFrame(); - Border padding = BorderFactory.createEmptyBorder(10, 10, 10, 10); - + final JFrame frame = new JFrame(); + frame.setTitle("One Time Password Generator"); frame.add(label, BorderLayout.CENTER); frame.add(secretField, BorderLayout.NORTH); frame.add(otp, BorderLayout.SOUTH); - - - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); frame.setVisible(true); frame.pack(); frame.setSize(450, 300); - - while(true){ - String totp = generateTOTP(secret); - System.out.println("TOTP: " + totp); - otp.setText("TOTP: " + totp); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - throw new RuntimeException(e); + Thread.ofVirtual().start(() -> { + while (frame.isVisible()) { + otp.setText(generateTOTP(secret)); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } } - } + }); + return totp; + } + + public static void main(String[] args) throws Exception { + + generateCodeAndShow("TEST"); } } From 8df2068893e1e4e8cd0d8bbe165b53a2afd0c3d8 Mon Sep 17 00:00:00 2001 From: Nils M Date: Tue, 25 Jun 2024 12:52:38 +0200 Subject: [PATCH 06/17] Refactored DiscordWebhook logic and removed lombok references --- .../de/haevn/annotations/AnnotationUtils.java | 2 +- .../BackgroundWorkerThreadService.java | 4 +- .../haevn/utils/concurrency/ProcessUtils.java | 6 +- .../de/haevn/utils/crypto/Base32Util.java | 1 + .../haevn/utils/crypto/OneTimePassword.java | 5 +- .../utils/datastructure/NotifiableList.java | 4 +- .../utils/datastructure/ObjectGroup.java | 26 +++--- .../haevn/utils/datastructure/Observable.java | 4 +- .../de/haevn/utils/datastructure/Tripple.java | 18 +++++ .../de/haevn/utils/datastructure/Tuple.java | 14 +++- .../de/haevn/utils/debug/ThreadTools.java | 13 +++ .../utils/exceptions/FileMergeException.java | 2 +- .../utils/io/merge/AbstractFileMerging.java | 6 +- .../de/haevn/utils/io/merge/IFileMerging.java | 4 +- .../java/de/haevn/utils/logging/LogEntry.java | 14 ++-- .../de/haevn/utils/logging/LoggerConfig.java | 16 ++-- .../java/de/haevn/utils/network/Ping.java | 10 +-- .../utils/network/webhook/discord/Embed.java | 22 ++--- pom.xml | 1 + swing/pom.xml | 34 ++++++++ .../java/de/haevn/utils/swing/Dialog.java | 81 +++++++++++++++++++ swing/src/main/java/module-info.java | 5 ++ .../java/de/haevn/utils/system/Tokenizer.java | 2 +- .../main/java/de/haevn/utils/NumberUtils.java | 31 +++++++ .../main/java/de/haevn/utils/StringUtils.java | 3 +- .../src/main/java/de/haevn/utils/System.java | 33 +------- 26 files changed, 264 insertions(+), 97 deletions(-) create mode 100644 swing/pom.xml create mode 100644 swing/src/main/java/de/haevn/utils/swing/Dialog.java create mode 100644 swing/src/main/java/module-info.java diff --git a/annotations/src/main/java/de/haevn/annotations/AnnotationUtils.java b/annotations/src/main/java/de/haevn/annotations/AnnotationUtils.java index 0961594..b6e0249 100644 --- a/annotations/src/main/java/de/haevn/annotations/AnnotationUtils.java +++ b/annotations/src/main/java/de/haevn/annotations/AnnotationUtils.java @@ -44,7 +44,7 @@ public static List findAnnotation(final String packageName .toList(); } - private static Class getClass(String className, String packageName) { + private static Class getClass(final String className, final String packageName) { try { return Class.forName(packageName + "." + className.substring(0, className.lastIndexOf('.'))); } catch (ClassNotFoundException ignored) { diff --git a/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorkerThreadService.java b/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorkerThreadService.java index 9ed5e3a..33d75c0 100644 --- a/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorkerThreadService.java +++ b/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorkerThreadService.java @@ -139,7 +139,7 @@ private void exceptionHandler(final Thread thread, final Throwable throwable) { * @param runnable the task that will be executed */ @Override - protected void beforeExecute(Thread thread, Runnable runnable) { + protected void beforeExecute(final Thread thread, final Runnable runnable) { super.beforeExecute(thread, runnable); LOGGER.atInfo().withMessage("Executing %s", thread.getName()).withObject(thread).log(); } @@ -151,7 +151,7 @@ protected void beforeExecute(Thread thread, Runnable runnable) { * @param throwable the exception that has been thrown */ @Override - protected void afterExecute(Runnable runnable, Throwable throwable) { + protected void afterExecute(final Runnable runnable, final Throwable throwable) { super.afterExecute(runnable, throwable); LOGGER.atInfo().withMessage("Finished").withException(throwable).log(); } diff --git a/concurrency/src/main/java/de/haevn/utils/concurrency/ProcessUtils.java b/concurrency/src/main/java/de/haevn/utils/concurrency/ProcessUtils.java index e2c3fea..e5636d0 100644 --- a/concurrency/src/main/java/de/haevn/utils/concurrency/ProcessUtils.java +++ b/concurrency/src/main/java/de/haevn/utils/concurrency/ProcessUtils.java @@ -31,17 +31,17 @@ private static final class Builder { args.add(name); } - public Builder addArg(String arg) { + public Builder addArg(final String arg) { args.add(arg); return this; } - public Builder directory(String directory) { + public Builder directory(final String directory) { this.directory = directory; return this; } - public Builder inheritIO(boolean inheritIO) { + public Builder inheritIO(final boolean inheritIO) { this.inheritIO = inheritIO; return this; } diff --git a/crypto/src/main/java/de/haevn/utils/crypto/Base32Util.java b/crypto/src/main/java/de/haevn/utils/crypto/Base32Util.java index 850cbd4..9b217b6 100644 --- a/crypto/src/main/java/de/haevn/utils/crypto/Base32Util.java +++ b/crypto/src/main/java/de/haevn/utils/crypto/Base32Util.java @@ -8,6 +8,7 @@ public final class Base32Util { private static final String PADDING = "="; private static final int MASK = 0x1F; + private Base32Util() {} public static String encode(final String data) { return encode(data.getBytes()); diff --git a/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java b/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java index c44b5fe..152639e 100644 --- a/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java +++ b/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java @@ -27,7 +27,7 @@ public final class OneTimePassword { private static final long TIME_STEP = 30_000L; private static final int SECRET_KEY_LENGTH = 20; - public static String generateTOTP(String secret) { + public static String generateTOTP(final String secret) { byte[] key = Base32Util.decode(secret); final long time = (Instant.now().toEpochMilli() / TIME_STEP); @@ -47,7 +47,7 @@ public static String generateTOTP(String secret) { return String.format("%06d", otp); } - private static byte[] hmacSha1(byte[] key, byte[] data) { + private static byte[] hmacSha1(final byte[] key, final byte[] data) { try { final SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA1"); final Mac mac = Mac.getInstance("HmacSHA1"); @@ -98,6 +98,7 @@ public static String generateCodeAndShow(final String name, final String secret) frame.add(label, BorderLayout.CENTER); frame.add(secretField, BorderLayout.NORTH); frame.add(otp, BorderLayout.SOUTH); + frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); frame.setVisible(true); frame.pack(); diff --git a/datastructures/src/main/java/de/haevn/utils/datastructure/NotifiableList.java b/datastructures/src/main/java/de/haevn/utils/datastructure/NotifiableList.java index fed506b..553830f 100644 --- a/datastructures/src/main/java/de/haevn/utils/datastructure/NotifiableList.java +++ b/datastructures/src/main/java/de/haevn/utils/datastructure/NotifiableList.java @@ -7,11 +7,11 @@ public class NotifiableList extends ArrayList { final List> consumers = new ArrayList<>(); - public void subscribe(IListUpdateConsumer consumer) { + public void subscribe(final IListUpdateConsumer consumer) { consumers.add(consumer); } - public void unsubscribe(IListUpdateConsumer consumer) { + public void unsubscribe(final IListUpdateConsumer consumer) { consumers.remove(consumer); } diff --git a/datastructures/src/main/java/de/haevn/utils/datastructure/ObjectGroup.java b/datastructures/src/main/java/de/haevn/utils/datastructure/ObjectGroup.java index 3121baf..7a0ebf3 100644 --- a/datastructures/src/main/java/de/haevn/utils/datastructure/ObjectGroup.java +++ b/datastructures/src/main/java/de/haevn/utils/datastructure/ObjectGroup.java @@ -24,26 +24,26 @@ public ObjectGroup() { } @SafeVarargs - public ObjectGroup(T... elements) { + public ObjectGroup(final T... elements) { this(List.of(elements)); } - public ObjectGroup(List elements) { + public ObjectGroup(final List elements) { this.elements = elements; } - public ObjectGroup add(T element) { + public ObjectGroup add(final T element) { elements.add(element); return this; } @SafeVarargs - public final ObjectGroup addAll(T... elements) { + public final ObjectGroup addAll(final T... elements) { this.elements.addAll(List.of(elements)); return this; } - public ObjectGroup remove(T element) { + public ObjectGroup remove(final T element) { elements.remove(element); return this; } @@ -65,31 +65,31 @@ public boolean isEmpty() { return elements.isEmpty(); } - public boolean contains(T element) { + public boolean contains(final T element) { return elements.contains(element); } - public T get(int index) { + public T get(final int index) { return elements.get(index); } - public List filter(Predicate predicate) { + public List filter(final Predicate predicate) { return elements.stream().filter(predicate).toList(); } - public Optional findFirst(Predicate predicate) { + public Optional findFirst(final Predicate predicate) { return elements.stream().filter(predicate).findFirst(); } - public Optional findAny(Predicate predicate) { + public Optional findAny(final Predicate predicate) { return elements.stream().filter(predicate).findAny(); } - public boolean allMatch(Predicate predicate) { + public boolean allMatch(final Predicate predicate) { return elements.stream().allMatch(predicate); } - public boolean anyMatch(Predicate predicate) { + public boolean anyMatch(final Predicate predicate) { return elements.stream().anyMatch(predicate); } @@ -97,7 +97,7 @@ public boolean noneMatch(Predicate predicate) { return elements.stream().noneMatch(predicate); } - public ObjectGroup forEach(Consumer action) { + public ObjectGroup forEach(final Consumer action) { elements.forEach(action); return this; } diff --git a/datastructures/src/main/java/de/haevn/utils/datastructure/Observable.java b/datastructures/src/main/java/de/haevn/utils/datastructure/Observable.java index b7b25e7..bbcaf59 100644 --- a/datastructures/src/main/java/de/haevn/utils/datastructure/Observable.java +++ b/datastructures/src/main/java/de/haevn/utils/datastructure/Observable.java @@ -7,7 +7,7 @@ public class Observable { private T value; private final List> observers = new ArrayList<>(); - public Observable(T value) { + public Observable(final T value) { this.value = value; } @@ -15,7 +15,7 @@ public T get() { return value; } - public void set(T value) { + public void set(final T value) { synchronized (this) { this.value = value; } diff --git a/datastructures/src/main/java/de/haevn/utils/datastructure/Tripple.java b/datastructures/src/main/java/de/haevn/utils/datastructure/Tripple.java index 97ae41c..067bce0 100644 --- a/datastructures/src/main/java/de/haevn/utils/datastructure/Tripple.java +++ b/datastructures/src/main/java/de/haevn/utils/datastructure/Tripple.java @@ -11,6 +11,7 @@ * @since 1.0 */ public class Tripple extends Tuple{ + public static final Tripple EMPTY = new Tripple<>(null, null, null); private T third; /** @@ -42,4 +43,21 @@ public T getThird() { public void setThird(final T value) { this.third = value; } + + @Override + public boolean isEmpty() { + return this.equals(EMPTY); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + Tripple tripple = (Tripple) obj; + return getFirst().equals(tripple.getFirst()) && getSecond().equals(tripple.getSecond()) && third.equals(tripple.third); + } } diff --git a/datastructures/src/main/java/de/haevn/utils/datastructure/Tuple.java b/datastructures/src/main/java/de/haevn/utils/datastructure/Tuple.java index 922138f..1767880 100644 --- a/datastructures/src/main/java/de/haevn/utils/datastructure/Tuple.java +++ b/datastructures/src/main/java/de/haevn/utils/datastructure/Tuple.java @@ -62,6 +62,18 @@ public void setSecond(final V value) { } public boolean isEmpty() { - return this == EMPTY; + return this.equals(EMPTY); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + Tuple tuple = (Tuple) obj; + return key.equals(tuple.key) && value.equals(tuple.value); } } diff --git a/debug/src/main/java/de/haevn/utils/debug/ThreadTools.java b/debug/src/main/java/de/haevn/utils/debug/ThreadTools.java index 4e69605..6971094 100644 --- a/debug/src/main/java/de/haevn/utils/debug/ThreadTools.java +++ b/debug/src/main/java/de/haevn/utils/debug/ThreadTools.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; /** @@ -35,4 +36,16 @@ public static List getThreads(final Thread.State state){ public static List getRunningThreadNames() { return getThreads().stream().map(Thread::getName).toList(); } + + public static void waitFor(final AtomicBoolean condition) { + try { + Thread.ofVirtual().start(() -> { + while(!condition.get()) { + Thread.onSpinWait(); + } + }).join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } } diff --git a/exceptions/src/main/java/de/haevn/utils/exceptions/FileMergeException.java b/exceptions/src/main/java/de/haevn/utils/exceptions/FileMergeException.java index cb0794b..c5071d1 100644 --- a/exceptions/src/main/java/de/haevn/utils/exceptions/FileMergeException.java +++ b/exceptions/src/main/java/de/haevn/utils/exceptions/FileMergeException.java @@ -4,7 +4,7 @@ import java.util.List; public class FileMergeException extends Exception{ -public FileMergeException(File output, List files) { +public FileMergeException(final File output, List files) { super(buildMessage(output, files)); } diff --git a/io/src/main/java/de/haevn/utils/io/merge/AbstractFileMerging.java b/io/src/main/java/de/haevn/utils/io/merge/AbstractFileMerging.java index e8a683e..1e23124 100644 --- a/io/src/main/java/de/haevn/utils/io/merge/AbstractFileMerging.java +++ b/io/src/main/java/de/haevn/utils/io/merge/AbstractFileMerging.java @@ -25,7 +25,7 @@ public abstract class AbstractFileMerging implements IFileMerging { * @param input the input files * @throws FileMergeException if an error occurs while merging the files */ - public void mergeFiles(File output, String... input) throws FileMergeException { + public void mergeFiles(final File output, final String... input) throws FileMergeException { mergeFiles(output, Arrays.stream(input).map(File::new).toList()); } @@ -36,7 +36,7 @@ public void mergeFiles(File output, String... input) throws FileMergeException { * @param input the input files * @throws FileMergeException if an error occurs while merging the files */ - public void mergeFiles(File output, File... input) throws FileMergeException { + public void mergeFiles(final File output, final File... input) throws FileMergeException { mergeFiles(output, List.of(input)); } @@ -77,7 +77,7 @@ protected void storeFile(final File file, final byte[] bytes) throws IOException * @param deleteOnExist if the file should be deleted if it already exists * @throws IOException if an error occurs while storing the bytes */ - protected void storeFile(final File file, final byte[] bytes, boolean deleteOnExist) throws IOException { + protected void storeFile(final File file, final byte[] bytes, final boolean deleteOnExist) throws IOException { if (file.exists() && deleteOnExist) { Files.delete(file.toPath()); } diff --git a/io/src/main/java/de/haevn/utils/io/merge/IFileMerging.java b/io/src/main/java/de/haevn/utils/io/merge/IFileMerging.java index 9a123f6..8741591 100644 --- a/io/src/main/java/de/haevn/utils/io/merge/IFileMerging.java +++ b/io/src/main/java/de/haevn/utils/io/merge/IFileMerging.java @@ -28,7 +28,7 @@ public interface IFileMerging { * @param input the input files * @throws FileMergeException if an error occurs while merging the files */ - void mergeFiles(File output, String... input) throws FileMergeException; + void mergeFiles(final File output, final String... input) throws FileMergeException; /** * Merges the given files into the output file. @@ -37,6 +37,6 @@ public interface IFileMerging { * @param input the input files * @throws FileMergeException if an error occurs while merging the files */ - void mergeFiles(File output, File... input) throws FileMergeException; + void mergeFiles(final File output, final File... input) throws FileMergeException; } \ No newline at end of file diff --git a/logger/src/main/java/de/haevn/utils/logging/LogEntry.java b/logger/src/main/java/de/haevn/utils/logging/LogEntry.java index 44e4d5e..88f3f41 100644 --- a/logger/src/main/java/de/haevn/utils/logging/LogEntry.java +++ b/logger/src/main/java/de/haevn/utils/logging/LogEntry.java @@ -32,7 +32,7 @@ public Level getLevel() { * * @param level The log level. */ - public void setLevel(Level level) { + public void setLevel(final Level level) { this.level = level; } @@ -50,7 +50,7 @@ public MethodTools getHelper() { * * @param helper The helper. */ - public void setHelper(MethodTools helper) { + public void setHelper(final MethodTools helper) { this.helper = helper; } @@ -68,7 +68,7 @@ public String getMessage() { * * @param message The message. */ - public void setMessage(String message) { + public void setMessage(final String message) { this.message = message; } @@ -87,7 +87,7 @@ public Throwable getThrowable() { * * @param throwable The throwable. */ - public void setThrowable(Throwable throwable) { + public void setThrowable(final Throwable throwable) { this.throwable = throwable; } @@ -105,7 +105,7 @@ public long getTimestamp() { * * @param timestamp The timestamp. */ - public void setTimestamp(long timestamp) { + public void setTimestamp(final long timestamp) { this.timestamp = timestamp; } @@ -116,7 +116,7 @@ public Object getObj() { return obj; } - public void setObj(Object obj) { + public void setObj(final Object obj) { this.obj = obj; } @@ -124,7 +124,7 @@ public String getThreadName() { return threadName; } - public void setThreadName(String name) { + public void setThreadName(final String name) { this.threadName = name; } } diff --git a/logger/src/main/java/de/haevn/utils/logging/LoggerConfig.java b/logger/src/main/java/de/haevn/utils/logging/LoggerConfig.java index d191be7..c673dae 100644 --- a/logger/src/main/java/de/haevn/utils/logging/LoggerConfig.java +++ b/logger/src/main/java/de/haevn/utils/logging/LoggerConfig.java @@ -17,7 +17,7 @@ public PrintStream getFileOutput() { return fileOutput; } - public void setFileOutput(PrintStream fileOutput) { + public void setFileOutput(final PrintStream fileOutput) { this.fileOutput = fileOutput; } @@ -25,7 +25,7 @@ public PrintStream getConsoleOutput() { return consoleOutput; } - public void setConsoleOutput(PrintStream consoleOutput) { + public void setConsoleOutput(final PrintStream consoleOutput) { this.consoleOutput = consoleOutput; } @@ -33,7 +33,7 @@ public Level getLevel() { return level; } - public void setLevel(Level level) { + public void setLevel(final Level level) { this.level = level; } @@ -41,7 +41,7 @@ public boolean isAutoFlush() { return autoFlush; } - public void setAutoFlush(boolean autoFlush) { + public void setAutoFlush(final boolean autoFlush) { this.autoFlush = autoFlush; } @@ -49,7 +49,7 @@ public boolean isUseShutdownHook() { return useShutdownHook; } - public void setUseShutdownHook(boolean useShutdownHook) { + public void setUseShutdownHook(final boolean useShutdownHook) { this.useShutdownHook = useShutdownHook; } @@ -57,7 +57,7 @@ public int getLogSize() { return logSize; } - public void setLogSize(int logSize) { + public void setLogSize(final int logSize) { this.logSize = logSize; } @@ -74,7 +74,7 @@ public void setLogSize(int logSize) { * * @param logFile The output stream. */ - public void setOutput(String logFile) throws FileNotFoundException { + public void setOutput(final String logFile) throws FileNotFoundException { setOutput(new File(logFile + System.currentTimeMillis() + ".log")); } @@ -83,7 +83,7 @@ public void setOutput(String logFile) throws FileNotFoundException { * * @param logFile The output stream. */ - public void setOutput(File logFile) throws FileNotFoundException { + public void setOutput(final File logFile) throws FileNotFoundException { this.fileOutput = new PrintStream(new FileOutputStream(logFile, true)); } } diff --git a/network/src/main/java/de/haevn/utils/network/Ping.java b/network/src/main/java/de/haevn/utils/network/Ping.java index 5448635..adab351 100644 --- a/network/src/main/java/de/haevn/utils/network/Ping.java +++ b/network/src/main/java/de/haevn/utils/network/Ping.java @@ -8,7 +8,7 @@ public class Ping { - public static PingBuilder open(String host){ + public static PingBuilder open(final String host){ return new PingBuilder(host); } @@ -50,21 +50,21 @@ public static final class PingBuilder{ private int count = 3; - public PingBuilder(String host){ + public PingBuilder(final String host){ this.host = host; } - public PingBuilder port(int port){ + public PingBuilder port(final int port){ this.port = port; return this; } - public PingBuilder timeout(int timeout){ + public PingBuilder timeout(final int timeout){ this.timeout = timeout; return this; } - public PingBuilder count(int count){ + public PingBuilder count(final int count){ this.count = count; return this; } diff --git a/network/src/main/java/de/haevn/utils/network/webhook/discord/Embed.java b/network/src/main/java/de/haevn/utils/network/webhook/discord/Embed.java index d7efd12..bd6264f 100644 --- a/network/src/main/java/de/haevn/utils/network/webhook/discord/Embed.java +++ b/network/src/main/java/de/haevn/utils/network/webhook/discord/Embed.java @@ -41,7 +41,7 @@ public String getTitle() { return title; } - public void setTitle(String title) { + public void setTitle(final String title) { this.title = title; } @@ -49,7 +49,7 @@ public String getType() { return type; } - public void setType(String type) { + public void setType(final String type) { this.type = type; } @@ -57,7 +57,7 @@ public String getDescription() { return description; } - public void setDescription(String description) { + public void setDescription(final String description) { this.description = description; } @@ -65,7 +65,7 @@ public String getUrl() { return url; } - public void setUrl(String url) { + public void setUrl(final String url) { this.url = url; } @@ -89,7 +89,7 @@ public long getColor() { return color; } - public void setColor(long color) { + public void setColor(final long color) { this.color = color; } @@ -97,7 +97,7 @@ public EmbedFooter getFooter() { return footer; } - public void setFooter(EmbedFooter footer) { + public void setFooter(final EmbedFooter footer) { this.footer = footer; } @@ -105,7 +105,7 @@ public EmbedImage getImage() { return image; } - public void setImage(EmbedImage image) { + public void setImage(final EmbedImage image) { this.image = image; } @@ -113,7 +113,7 @@ public EmbedThumbnail getThumbnail() { return thumbnail; } - public void setThumbnail(EmbedThumbnail thumbnail) { + public void setThumbnail(final EmbedThumbnail thumbnail) { this.thumbnail = thumbnail; } @@ -121,7 +121,7 @@ public EmbedVideo getVideo() { return video; } - public void setVideo(EmbedVideo video) { + public void setVideo(final EmbedVideo video) { this.video = video; } @@ -129,7 +129,7 @@ public EmbedProvider getProvider() { return provider; } - public void setProvider(EmbedProvider provider) { + public void setProvider(final EmbedProvider provider) { this.provider = provider; } @@ -150,7 +150,7 @@ public List getFields() { return fields; } - public void setFields(List fields) { + public void setFields(final List fields) { this.fields = fields; } diff --git a/pom.xml b/pom.xml index 3758a94..55495df 100644 --- a/pom.xml +++ b/pom.xml @@ -184,5 +184,6 @@ logger network utils + swing \ No newline at end of file diff --git a/swing/pom.xml b/swing/pom.xml new file mode 100644 index 0000000..8410a9c --- /dev/null +++ b/swing/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + de.haevn + Utility + 2.1 + + + swing + + + 22 + 22 + UTF-8 + + + + de.haevn + utils + 2.1 + compile + + + de.haevn + debug + 2.1 + compile + + + + \ No newline at end of file diff --git a/swing/src/main/java/de/haevn/utils/swing/Dialog.java b/swing/src/main/java/de/haevn/utils/swing/Dialog.java new file mode 100644 index 0000000..ca0df9f --- /dev/null +++ b/swing/src/main/java/de/haevn/utils/swing/Dialog.java @@ -0,0 +1,81 @@ +package de.haevn.utils.swing; + +import de.haevn.utils.TimeUtils; +import de.haevn.utils.debug.ThreadTools; + +import javax.swing.*; +import java.util.concurrent.atomic.AtomicBoolean; + +public final class Dialog extends JFrame { + private final AtomicBoolean visibility = new AtomicBoolean(false); + private DialogResult result = DialogResult.NONE; + + public Dialog(final String title, final String message, DialogResult ... result){ + setTitle(title); + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + setSize(300, 200); + setLocationRelativeTo(null); + + final JPanel bottomPanel = new JPanel(); + for (DialogResult r : result){ + final JButton btn = new JButton(r.name()); + btn.addActionListener(_ -> { + this.result = r; + setVisible(false); + dispose(); + }); + bottomPanel.add(btn); + } + + add(new JLabel(message), "Center"); + add(bottomPanel, "South"); + } + + public DialogResult getResult(){ + return result; + } + + public DialogResult showAndWait(){ + setVisible(true); + ThreadTools.waitFor(visibility); + return getResult(); + } + + @Override + public void setVisible(boolean visible) { + visibility.set(visible); + super.setVisible(visible); + } + + public static Dialog creeate(final String title, final String message, DialogResult ... result){ + return new Dialog(title, message, result); + } + + public static Dialog warningDialog(final String message){ + return creeate("Warning", message, DialogResult.OK, DialogResult.CANCEL); + } + + public static Dialog errorDialog(final String message){ + return creeate("Error", message, DialogResult.CLOSE); + } + + public static Dialog infoDialog(final String message){ + return creeate("Information", message, DialogResult.OK); + } + + public static Dialog confirmDialog(final String message){ + return creeate("Confirmation", message, DialogResult.YES, DialogResult.NO); + } + + + + + public enum DialogResult { + OK, + CANCEL, + YES, + NO, + CLOSE, + NONE + } +} diff --git a/swing/src/main/java/module-info.java b/swing/src/main/java/module-info.java new file mode 100644 index 0000000..8147163 --- /dev/null +++ b/swing/src/main/java/module-info.java @@ -0,0 +1,5 @@ +module de.haevn.utils.swing { + requires java.desktop; + requires de.haevn.utils.utils; + requires de.haevn.utils.debug; +} \ No newline at end of file diff --git a/system/src/main/java/de/haevn/utils/system/Tokenizer.java b/system/src/main/java/de/haevn/utils/system/Tokenizer.java index 2b2c6bf..6cca8e6 100644 --- a/system/src/main/java/de/haevn/utils/system/Tokenizer.java +++ b/system/src/main/java/de/haevn/utils/system/Tokenizer.java @@ -11,7 +11,7 @@ public Tokenizer() { this("="); } - public Tokenizer(String splitter) { + public Tokenizer(final String splitter) { this.splitter = splitter; } diff --git a/utils/src/main/java/de/haevn/utils/NumberUtils.java b/utils/src/main/java/de/haevn/utils/NumberUtils.java index 551a967..541f36b 100644 --- a/utils/src/main/java/de/haevn/utils/NumberUtils.java +++ b/utils/src/main/java/de/haevn/utils/NumberUtils.java @@ -1,6 +1,9 @@ package de.haevn.utils; import java.text.NumberFormat; +import java.util.List; +import java.util.Random; +import java.util.stream.Stream; /** * A simple class for number information. @@ -104,4 +107,32 @@ public static String longToHex(long errorCode) { public static long hexToLong(String hex) { return Long.parseLong(hex, 16); } + + public static List randomNumber(final int amount) { + List numbers = new java.util.ArrayList<>(); + for (int i = 0; i < amount; i++) { + Random random = new Random(java.lang.System.currentTimeMillis()); + numbers.add(random.nextInt()); + } + + return numbers; + } + + public static Stream randomNumberStream(final int amount) { + return randomNumber(amount).stream(); + } + + public static List randomDouble(final int amount) { + List numbers = new java.util.ArrayList<>(); + for (int i = 0; i < amount; i++) { + Random random = new Random(java.lang.System.currentTimeMillis()); + numbers.add(random.nextDouble()); + } + + return numbers; + } + + public static Stream randomDoubleStream(final int amount) { + return randomDouble(amount).stream(); + } } diff --git a/utils/src/main/java/de/haevn/utils/StringUtils.java b/utils/src/main/java/de/haevn/utils/StringUtils.java index 99ef293..152288e 100644 --- a/utils/src/main/java/de/haevn/utils/StringUtils.java +++ b/utils/src/main/java/de/haevn/utils/StringUtils.java @@ -93,7 +93,8 @@ public static String str2Hex(final String in){ char[] chars = in.toCharArray(); StringBuilder hex = new StringBuilder(); for (char ch : chars) { - hex.append(Integer.toHexString((int) ch)); + hex.append(Integer.toHexString(ch)); + hex.append(Integer.toHexString(ch)); } return hex.toString(); } diff --git a/utils/src/main/java/de/haevn/utils/System.java b/utils/src/main/java/de/haevn/utils/System.java index 3abc6f9..3b41e3f 100644 --- a/utils/src/main/java/de/haevn/utils/System.java +++ b/utils/src/main/java/de/haevn/utils/System.java @@ -17,12 +17,7 @@ public class System { private System() { } - - public static R map(final T value, final Function mapper) { - return mapper.apply(value); - } - - + public static String[] getKeyValue(final String key, final String value) { return new String[]{key, value}; } @@ -31,31 +26,5 @@ public static String[] property(final String key, final String value) { return getKeyValue(key, value); } - public static List randomNumber(final int amount) { - List numbers = new java.util.ArrayList<>(); - for (int i = 0; i < amount; i++) { - Random random = new Random(java.lang.System.currentTimeMillis()); - numbers.add(random.nextInt()); - } - - return numbers; - } - - public static Stream randomNumberStream(final int amount) { - return randomNumber(amount).stream(); - } - - public static List randomDouble(final int amount) { - List numbers = new java.util.ArrayList<>(); - for (int i = 0; i < amount; i++) { - Random random = new Random(java.lang.System.currentTimeMillis()); - numbers.add(random.nextDouble()); - } - return numbers; - } - - public static Stream randomDoubleStream(final int amount) { - return randomDouble(amount).stream(); - } } From f65ab9cf822d2bb35a4974b6a19c2aebc47b7f97 Mon Sep 17 00:00:00 2001 From: Nils M Date: Sat, 29 Jun 2024 14:54:04 +0200 Subject: [PATCH 07/17] Rewrote documentation --- .../de/haevn/annotations/AnnotationUtils.java | 88 +++++++++++++++++- .../de/haevn/annotations/AutoCollect.java | 92 +++++++++++++++++-- .../main/java/de/haevn/annotations/Draft.java | 32 ++++++- .../java/de/haevn/annotations/Launcher.java | 35 +++++++ .../de/haevn/annotations/LauncherUtils.java | 67 +++++++++++++- .../haevn/utils/concurrency/ProcessUtils.java | 2 +- .../haevn/utils/crypto/OneTimePassword.java | 11 --- .../de/haevn/utils/datastructure/Cache.java | 8 +- 8 files changed, 306 insertions(+), 29 deletions(-) diff --git a/annotations/src/main/java/de/haevn/annotations/AnnotationUtils.java b/annotations/src/main/java/de/haevn/annotations/AnnotationUtils.java index b6e0249..9fda5e9 100644 --- a/annotations/src/main/java/de/haevn/annotations/AnnotationUtils.java +++ b/annotations/src/main/java/de/haevn/annotations/AnnotationUtils.java @@ -9,7 +9,15 @@ import java.util.Objects; /** - * Utility class for annotations. + *

AnnotationUtils

+ *

This class provides utilities to handle {@link Annotation}

+ *

Currently implemented utilites are

+ *
    + *
  • Testing if given {@link AutoCollect.FeatureType FeatureType} is present
  • + *
  • Searching for a specific {@link Annotation}
  • + *
  • Quick access to retrieve a {@link Launcher}
  • + *
+ *

New features will be added continously.

* * @author haevn * @version 1.0 @@ -20,16 +28,77 @@ public class AnnotationUtils { private AnnotationUtils() { } - private static boolean isFeaturePresent(final Class annotation, final AutoCollect.FeatureType... features) { + /** + *

isFeaturePresent

+ *

Check if given {@link AutoCollect.FeatureType FeatureType} is present in the {@link AutoCollect} annotation

+ *
+ *

Example:

+ *
+     * {@code
+     * @AutoCollect(feature = AutoCollect.FeatureType.ENABLED)
+     * public class Example {}
+     * isFeaturePresent(Example.class, AutoCollect.FeatureType.ENABLED); // Returns true
+     * isFeaturePresent(Example.class, AutoCollect.FeatureType.DISABLED); // Returns false
+     * }
+     * 
+ * + * @param annotation The annotation to check + * @param features The features to check for + * @return True if all features are present, false otherwise + */ + public static boolean isFeaturePresent(final Class annotation, final AutoCollect.FeatureType... features) { return annotation.getAnnotation(AutoCollect.class).feature().has(features); } + /** + *

findLauncher

+ *

Searches a package for all {@link Launcher} annotated classes.

+ *
+ *

Internally the {@link AnnotationUtils#findAnnotation(String, Class) findAnnotation(String, Class)} is called + * with {@link Launcher} as argument

+ *

Example:

+ *
+     * {@code
+     *     @Launcher
+     *     public class Example {}
+     *     findLauncher("de.haevn.annotations"); // Returns a list with Example.class
+     * }
+     * 
+ * + * @param packageName The package to search in + * @return A list of all found {@link Launcher} + */ public static List findLauncher(final String packageName) { return findAnnotation(packageName, Launcher.class).stream() .map(Launcher.class::cast) .toList(); } + /** + *

findAnnotation

+ *

Searches a package for all classes annotated with a specific {@link Annotation}

+ *
+ *
    + * + *
  • First it request an inputstream from the {@link ClassLoader#getSystemClassLoader() SystemClassLoader}
  • + *
  • If the {@link InputStream} is null the operation yields an empty list
  • + *
  • Then every file is read and filtered for files ending with .class
  • + *
  • Next the class is requested using the {@link AnnotationUtils#getClass(String, String) getClass(String, String)} method
  • + *
  • After the conversion all null elements are discarded
  • + *
  • Elements not annotated with the given annotation are also discarded
  • + *
  • Finally the annotation is casted to the given annotation type and collected in a list
  • + *

    Example:

    + *
    +     *     {@code
    +     *     @AutoCollect
    +     *     public class Example {}
    +     *     findAnnotation("de.haevn.annotations", AutoCollect.class); // Returns a list with Example.class
    +     *     }
    +     * 
    + * @param packageName The package to search in + * @param annotation The annotation to search for + * @return A list of all found {@link Annotation} + */ public static List findAnnotation(final String packageName, final Class annotation) { final InputStream stream = ClassLoader.getSystemClassLoader() .getResourceAsStream(packageName.replaceAll("[.]", "/")); @@ -44,6 +113,21 @@ public static List findAnnotation(final String packageName .toList(); } + /** + *

    getClass

    + *

    THIS IS AN INTERNAL METHOD

    + *

    This method wraps the {@link Class#forName(String)}, it will return a null instead of throwing an {@link ClassNotFoundException}

    + *
    + *

    Example:

    + *
    +     *     {@code
    +     *     getClass("Example.class", "de.haevn); // Returns Example.class
    +     *     }
    +     * 
    + * @param className + * @param packageName + * @return + */ private static Class getClass(final String className, final String packageName) { try { return Class.forName(packageName + "." + className.substring(0, className.lastIndexOf('.'))); diff --git a/annotations/src/main/java/de/haevn/annotations/AutoCollect.java b/annotations/src/main/java/de/haevn/annotations/AutoCollect.java index 7ed5e5e..2adcb03 100644 --- a/annotations/src/main/java/de/haevn/annotations/AutoCollect.java +++ b/annotations/src/main/java/de/haevn/annotations/AutoCollect.java @@ -7,31 +7,82 @@ import java.util.Arrays; /** - * Auto collect annotation. + *

    AutoCollect

    + *

    This annotation is used to mark classes that should be collected by the {@link de.haevn.annotations.AnnotationUtils}

    + *

    It provides the following attributes:

    + *
      + *
    • order
    • + *
    • feature
    • + *
    + *
    + *

    It also provides a nested enum {@link FeatureType} to define the feature of the class.

    + *

    This class is finalized but new features can be added.

    + *
    + *

    Example:

    + *
    + * {@code
    + * @AutoCollect(feature = AutoCollect.FeatureType.ENABLED)
    + * public class Example {}
    + * }
    + * 
    * @version 1.0 * @since 1.0 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface AutoCollect { + /** - * The order of the collected class. - * It can be used to compare with other annotated classes, e.g. when this value is higher it means it's a higher prioritized class. - * example + *

    order

    + *

    The order of the collected class.

    + *

    Classes with a lower order will be collected first.

    + *
    + *

    Default value: 10

    + *
    + *

    Example:

    *
    +     * {@code
          * AnnotationUtils.collectBy("de.haevn.utils", AutoCollect.class)
          *      .stream()
          *      .sorted(Comparator.comparingInt(clazz -> clazz.getAnnotation(AutoCollect.class).order()))
          *      .toList();
    +     * }
          * 
    * @return The order. */ int order() default 10; + /** + *

    feature

    + *

    The feature of the collected class.

    + *

    Classes with a feature of {@link FeatureType#ENABLED} will be collected.

    + *
    + *

    Default value: {@link FeatureType#ENABLED}

    + *
    + *

    Example:

    + *
    +     * {@code
    +     * @AutoCollect(feature = AutoCollect.FeatureType.ENABLED)
    +     * public class Example {}
    +     * }
    +     * 
    + * @return The feature. + */ FeatureType feature() default FeatureType.ENABLED; + /** + *

    FeatureType

    + *

    Enum to define the feature of a class

    + *
    + *

    Example:

    + *
    +     * {@code
    +     * @AutoCollect(feature = AutoCollect.FeatureType.ENABLED)
    +     * public class Example {}
    +     * }
    +     * 
    + */ enum FeatureType { - ENABLED("enabled"), DISABLED("disabled"), HIDDEN("hidden"), @@ -45,13 +96,42 @@ enum FeatureType { this.name = name; } + /** + *

    has

    + *

    Check if the given {@link FeatureType} is present in the current {@link FeatureType}

    + *
    + *

    Example:

    + *
    +         * {@code
    +         * @AutoCollect(feature = AutoCollect.FeatureType.ENABLED)
    +         * public class Example {}
    +         * FeatureType.ENABLED.has(FeatureType.ENABLED); // Returns true
    +         * FeatureType.ENABLED.has(FeatureType.DISABLED); // Returns false
    +         * }
    +         *
    +         * @param features The features to check for
    +         * @return True iff all features are present otherwise false
    +         */
             public boolean has(final FeatureType... features) {
                 return Arrays.stream(features).anyMatch(feature -> feature == this);
             }
     
    +        /**
    +         * 

    fromString

    + *

    Get the {@link FeatureType} from a string

    + *
    + *

    Example:

    + *
    +         * {@code
    +         * FeatureType.fromString("enabled"); // Returns FeatureType.ENABLED
    +         * FeatureType.fromString("disabled"); // Returns FeatureType.DISABLED
    +         * }
    +         *
    +         * @param name The name of the feature
    +         * @return The associated {@link FeatureType}
    +         */
             public static FeatureType fromString(final String name) {
                 return Arrays.stream(FeatureType.values()).filter(featureType -> featureType.name.equalsIgnoreCase(name)).findFirst().orElse(UNKNOWN);
             }
    -
         }
     }
    diff --git a/annotations/src/main/java/de/haevn/annotations/Draft.java b/annotations/src/main/java/de/haevn/annotations/Draft.java
    index 6d02c4d..11a2c0e 100644
    --- a/annotations/src/main/java/de/haevn/annotations/Draft.java
    +++ b/annotations/src/main/java/de/haevn/annotations/Draft.java
    @@ -1,14 +1,38 @@
     package de.haevn.annotations;
     
     /**
    - * This annotation can be used to mark a class, method or field as draft.
    - * A draft is a piece of code that is not yet finished and should not be used in production.
    + *

    Draft

    + *

    This annotation can be used to mark a class, method or field as draft.

    + *

    A draft is a piece of code that is not yet finished and should not be used in production.

    + *

    It provides the following attributes:

    *
      - *
    • {@link Draft#description()} should contain information about the current state of the draft and what needs to be done
    • - *
    • {@link Draft#todo()} should contain a list of tasks that need to be done before the draft can be used in production
    • + *
    • {@link Draft#description()}
    • + *
    • {@link Draft#todo()}
    • *
    + *
    + *

    Example:

    + *
    + *     {@code
    + *     @Draft(description = "This class is not yet finished")
    + *     public class Example {}
    + *     }
    + * 
    + * @version 1.0 + * @since 2.1 + * @author haevn */ public @interface Draft { + /** + *

    description

    + *

    A description of the draft.

    + * @return The description of the draft. + */ String description() default ""; + + /** + *

    todo

    + *

    A list of things that need to be done.

    + * @return A list of things that need to be done. + */ String[] todo() default {}; } diff --git a/annotations/src/main/java/de/haevn/annotations/Launcher.java b/annotations/src/main/java/de/haevn/annotations/Launcher.java index d7b789a..aa879e9 100644 --- a/annotations/src/main/java/de/haevn/annotations/Launcher.java +++ b/annotations/src/main/java/de/haevn/annotations/Launcher.java @@ -5,6 +5,41 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + *

    Launcher

    + *

    This annotation is used to mark a class a launcher, the launcher contains information about the project.

    + *

    The {@link LauncherUtils} class should be used to access these information.

    + *

    Typically a launcher is the main class of a project.

    + *

    This class is finalized however new features or fields can be added

    + *
    + *

    Attributes:

    + *
      + *
    • name
    • + *
    • version
    • + *
    • author
    • + *
    • root
    • + *
    • icon
    • + *
    • description
    • + *
    • license
    • + *
    • website
    • + *
    + *
    + *

    Example:

    + *
    + *     {@code
    + *     @Launcher("Example")
    + *     public class Example {}
    + *     }
    + *
    + *     {@code
    + *     @Launcher(name = "Example", website = "https://example.com")
    + *     public class ExampleTwo {}
    + *     }
    + *
    + * @version 1.0 + * @since 2.1 + * @author haevn + */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Launcher { diff --git a/annotations/src/main/java/de/haevn/annotations/LauncherUtils.java b/annotations/src/main/java/de/haevn/annotations/LauncherUtils.java index 8b8fccf..82ccc9e 100644 --- a/annotations/src/main/java/de/haevn/annotations/LauncherUtils.java +++ b/annotations/src/main/java/de/haevn/annotations/LauncherUtils.java @@ -2,6 +2,15 @@ import java.io.File; +/** + *

    LauncherUtils

    + *

    This class provides utilities to handle the {@link Launcher} annotation

    + *

    It operates on the first found {@link Launcher}

    + * @version 1.0 + * @since 2.1 + * @author haevn + * @see Launcher + */ public class LauncherUtils { private final Launcher launcher; @@ -9,38 +18,94 @@ private LauncherUtils(final Launcher launcher) { this.launcher = launcher; } + /** + *

    getLauncher

    + *

    Get the first {@link Launcher} annotation of in the package "de.haevn"

    + * @return The first {@link Launcher} annotation + */ public static LauncherUtils getLauncher() { - return new LauncherUtils(AnnotationUtils.findLauncher("de.haevn").stream().findFirst().orElseThrow()); + return getLauncher("de.haevn"); } + /** + *

    getLauncher

    + *

    Get the first {@link Launcher} annotation of in the specified package

    + * @param packageName The package to search in + * @return The first {@link Launcher} annotation + */ + public static LauncherUtils getLauncher(final String packageName) { + return new LauncherUtils(AnnotationUtils.findLauncher(packageName).stream().findFirst().orElseThrow()); + } + + /** + *

    getRootPath

    + *

    The root path is inside the use.home directory, iff the {@link Launcher#root()} is not definied the { + * @link Launcher#name()} is used as root directory

    + * @return The root path of the launcher + */ public String getRootPath() { return System.getProperty("user.home") + File.separator + (launcher.root().isEmpty() ? launcher.name() : launcher.root()) + File.separator; } + /** + *

    getIcon

    + *

    Get the icon of the launcher

    + * @return The icon of the launcher + */ public String getIcon() { return launcher.icon(); } + /** + *

    getDescription

    + *

    Get the description of the launcher

    + * @return The description of the launcher + */ public String getDescription() { return launcher.description(); } + /** + *

    getLicense

    + *

    Get the license of the launcher

    + * @return The license of the launcher + */ public String getLicense() { return launcher.license(); } + /** + *

    getWebsite

    + *

    Get the website of the launcher

    + * @return The website of the launcher + */ public String getWebsite() { return launcher.website(); } + /** + *

    getAuthor

    + *

    Get the author of the launcher

    + * @return The author of the launcher + */ public String getAuthor() { return launcher.author(); } + /** + *

    getVersion

    + *

    Get the version of the launcher

    + * @return The version of the launcher + */ public String getVersion() { return launcher.version(); } + /** + *

    getName

    + *

    Get the name of the launcher

    + * @return The name of the launcher + */ public String getName() { return launcher.name(); } diff --git a/concurrency/src/main/java/de/haevn/utils/concurrency/ProcessUtils.java b/concurrency/src/main/java/de/haevn/utils/concurrency/ProcessUtils.java index e5636d0..6e31635 100644 --- a/concurrency/src/main/java/de/haevn/utils/concurrency/ProcessUtils.java +++ b/concurrency/src/main/java/de/haevn/utils/concurrency/ProcessUtils.java @@ -54,7 +54,7 @@ public Tuple start() throws IOException { public Tuple, Procc> startAsync() throws IOException { - ProcessBuilder processBuilder = new ProcessBuilder(args); + final ProcessBuilder processBuilder = new ProcessBuilder(args); if (!directory.isBlank()) processBuilder.directory(Path.of(directory).toFile()); if (inheritIO) processBuilder.inheritIO(); diff --git a/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java b/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java index 152639e..8b8d804 100644 --- a/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java +++ b/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java @@ -6,15 +6,10 @@ import javax.crypto.spec.SecretKeySpec; import javax.imageio.ImageIO; import javax.swing.*; -import javax.swing.border.Border; import java.awt.*; -import java.awt.event.WindowEvent; -import java.awt.event.WindowListener; import java.awt.image.BufferedImage; - import java.io.IOException; import java.net.URI; -import java.net.URL; import java.nio.ByteBuffer; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -115,10 +110,4 @@ public static String generateCodeAndShow(final String name, final String secret) }); return totp; } - - public static void main(String[] args) throws Exception { - - generateCodeAndShow("TEST"); - - } } diff --git a/datastructures/src/main/java/de/haevn/utils/datastructure/Cache.java b/datastructures/src/main/java/de/haevn/utils/datastructure/Cache.java index ca800c0..a08ce58 100644 --- a/datastructures/src/main/java/de/haevn/utils/datastructure/Cache.java +++ b/datastructures/src/main/java/de/haevn/utils/datastructure/Cache.java @@ -3,8 +3,8 @@ import de.haevn.utils.enumeration.MillisecondTimeUnits; /** - * A simple cache class. - * + * This is a simple cache class that can be used to cache values for a certain amount of time.
    + * The default duration is 1 day.
    * @param The type of the cached value. * @version 1.0 * @since 1.0 @@ -19,9 +19,9 @@ public Cache(final T value){ this(value, MillisecondTimeUnits.DAYS.getValue()); } - public Cache(final T value, long creationTime){ + public Cache(final T value, long duration){ this.value = value; - this.duration = creationTime; + this.duration = duration; this.creationTime = System.currentTimeMillis(); } From 26f4db5581e293d15d36e76f71e28d555c22b8ca Mon Sep 17 00:00:00 2001 From: Nils M Date: Sun, 30 Jun 2024 01:44:36 +0200 Subject: [PATCH 08/17] Rewrote documentation --- .../utils/concurrency/BackgroundWorker.java | 124 ++++++-- .../BackgroundWorkerThreadService.java | 102 +++++-- .../utils/concurrency/ConcurrencyUtils.java | 3 +- .../haevn/utils/concurrency/ProcessUtils.java | 3 + .../de/haevn/utils/crypto/Base32Util.java | 68 ++++- .../de/haevn/utils/crypto/Base64Util.java | 287 +++++++++++------- .../java/de/haevn/utils/crypto/HashUtil.java | 109 +++++++ .../de/haevn/utils/crypto/ICryptoUtils.java | 72 ++++- .../haevn/utils/crypto/OneTimePassword.java | 135 +++++++- .../haevn/utils/enumeration/BinarySize.java | 24 +- .../utils/enumeration/MicroTimeUnits.java | 20 +- .../enumeration/MillisecondTimeUnits.java | 19 +- .../utils/enumeration/NanoTimeUnits.java | 21 +- pom.xml | 1 + tools/pom.xml | 20 ++ .../main/java/de/haevn/utils/DocuHelper.java | 54 ++++ 16 files changed, 880 insertions(+), 182 deletions(-) create mode 100644 tools/pom.xml create mode 100644 tools/src/main/java/de/haevn/utils/DocuHelper.java diff --git a/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorker.java b/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorker.java index 388170c..fd24dc0 100644 --- a/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorker.java +++ b/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorker.java @@ -5,16 +5,19 @@ import java.util.concurrent.TimeUnit; /** - * This class provides a simple way to execute tasks in the background.
    - * It uses a {@link BackgroundWorkerThreadService} to execute the tasks.
    - * Accessing via {@link BackgroundWorker#getInstance()} will return a singleton instance with 70% of the available processors.
    - * Accessing via {@link BackgroundWorker#getInstance(int)} will return a singleton instance with the given amount of threads. + *

    BackgroundWorker

    + *
    This class provides a simple way to execute tasks in the background + *
    It uses the {@link BackgroundWorkerThreadService} to execute the tasks + *
    When accessed via the {@link BackgroundWorker#getInstance() getInstance()} method the maximum capacity for threads are 70% + *
    This behaviour can be overridden using the {@link BackgroundWorker#getInstance(int) getInstance(int)} method *
    - * Example + *

    Example

    *
      * {@code
      * BackgroundWorker.getInstance().submit(() -> System.out.println("Hello World"), "HelloWorld", 1, TimeUnit.SECONDS);
      * }
    + * 
    + * * @author haevn * @version 1.1 * @since 1.0 @@ -24,9 +27,17 @@ public class BackgroundWorker { private static BackgroundWorker instance; /** - * Initialize the singleton instance with the given amount of threads, e.g. 70% of the available processors + *

    initialize(int)

    + *

    Initializes the singleton instance with a given capacity

    * - * @param amountThreads the amount of threads + *

    Example:

    + *
    +     *     {@code
    +     *     BackgroundWorker.initialize(60);
    +     *     }
    +     *     
    + * + * @param amountThreads The amount of usable threads * @return the singleton instance */ public static BackgroundWorker initialize(final int amountThreads) { @@ -35,9 +46,16 @@ public static BackgroundWorker initialize(final int amountThreads) { } /** - * Get the singleton instance with the given amount of threads, e.g. 70% of the available processors + *

    initialize()

    + *

    Initializes the singleton instance with a given amount Threads

    + *

    Example:

    + *
    +     *     {@code
    +     *     BackgroundWorker.initialize(5);
    +     *     }
    +     * 
    * - * @param amountThreads the amount of threads + * @param amountThreads amount of usable threads * @return the singleton instance */ public static synchronized BackgroundWorker getInstance(final int amountThreads) { @@ -48,7 +66,14 @@ public static synchronized BackgroundWorker getInstance(final int amountThreads) } /** - * Get the singleton instance with 70% of the available processors + *

    getInstance()

    + *

    Initializes the singleton instance with 70% of the available processors

    + *

    Example:

    + *
    +     *     {@code
    +     *     BackgroundWorker.initialize();
    +     *     }
    +     * 
    * * @return the singleton instance */ @@ -59,24 +84,46 @@ public static synchronized BackgroundWorker getInstance() { private final BackgroundWorkerThreadService executor; + /** - * Creates a new BackgroundWorker with 70% of the available processors + *

    BackgroundWorker()

    + *

    Creates a new BackgroundWorker with 70% of the available processors

    + *

    Example:

    + *
    +     *     {@code
    +     *     BackgroundWorker worker = new BackgroundWorker();
    +     *     }
    +     * 
    */ public BackgroundWorker() { - this((int) (Runtime.getRuntime().availableProcessors() * 0.7)); + this(Runtime.getRuntime().availableProcessors() * 0.7); } /** - * Creates a new BackgroundWorker with the given amount of threads + *

    BackgroundWorker(double)

    + *

    Creates a new BackgroundWorker with the given amount of threads

    + *

    Example:

    + *
    +     *     {@code
    +     *     BackgroundWorker worker = new BackgroundWorker(5);
    +     *     }
    +     * 
    * * @param amountThreads the amount of threads */ - public BackgroundWorker(final int amountThreads) { - executor = new BackgroundWorkerThreadService(amountThreads); + public BackgroundWorker(final double amountThreads) { + executor = new BackgroundWorkerThreadService((int) amountThreads); } /** - * Submits a task to the background worker. + *

    submit(Runnable, String, int, TimeUnit)

    + *

    Submits a repeatable task to the background worker and return a {@link ScheduledFuture} as result

    + *

    Example:

    + *
    +     *     {@code
    +     *     worker.submit(() -> System.out.println("Hello World"), "HelloWorld", 1, TimeUnit.SECONDS);
    +     *     }
    +     * 
    * * @param runnable the task * @param name the name of the task @@ -89,7 +136,14 @@ public ScheduledFuture submit(final Runnable runnable, final String name, fin } /** - * Submits a task to the background worker. + *

    submit(Runnable, String, int, int, TimeUnit)

    + *

    Submits a repeatable delayed task to the background worker and return a {@link ScheduledFuture} as result

    + *

    Example:

    + *
    +     *     {@code
    +     *     worker.submit(() -> System.out.println("Hello World"), "HelloWorld", 1, 1, TimeUnit.SECONDS);
    +     *     }
    +     * 
    * * @param runnable the task * @param name the name of the task @@ -103,7 +157,14 @@ public ScheduledFuture submit(final Runnable runnable, final String name, fin } /** - * Submits a task to the background worker. + *

    submitOnce(Runnable, String)

    + *

    Submits a task to the background worker and return a {@link ScheduledFuture} as result

    + *

    Example:

    + *
    +     *     {@code
    +     *     worker.submitOnce(() -> System.out.println("Hello World"), "HelloWorld");
    +     *     }
    +     * 
    * * @param runnable the task * @param name the name of the task @@ -114,7 +175,14 @@ public ScheduledFuture submitOnce(final Runnable runnable, final String name) } /** - * Submits a task to the background worker. + *

    submitOnce(Runnable, String, long)

    + *

    Submits a delayed task to the background worker and return a {@link ScheduledFuture} as result

    + *

    Example:

    + *
    +     *     {@code
    +     *     worker.submitOnce(() -> System.out.println("Hello World"), "HelloWorld", 1);
    +     *     }
    +     * 
    * * @param runnable the task * @param name the name of the task @@ -126,14 +194,28 @@ public ScheduledFuture submitOnce(final Runnable runnable, final String name, } /** - * Shuts down the background worker. + *

    shutdown()

    + *

    Request a shutdown of the {@link BackgroundWorker}

    + *

    Example:

    + *
    +     *     {@code
    +     *      worker.shutdown();
    +     *     }
    +     * 
    */ public void shutdown() { executor.shutdown(); } /** - * Waits for all tasks to finish. + *

    join()

    + *

    Waits for all tasks to finish

    + *

    Example:

    + *
    +     *     {@code
    +     *     worker.join();
    +     *     }
    +     * 
    */ public void join() { executor.join(); diff --git a/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorkerThreadService.java b/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorkerThreadService.java index 33d75c0..7021fb1 100644 --- a/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorkerThreadService.java +++ b/concurrency/src/main/java/de/haevn/utils/concurrency/BackgroundWorkerThreadService.java @@ -7,16 +7,25 @@ import java.util.concurrent.TimeUnit; /** - * This is an internal class that enhances the {@link ScheduledThreadPoolExecutor} with logging and exception handling. - * It is used by the {@link BackgroundWorker} to execute tasks in the background. + *

    BackgroundWorkerThreadService

    + *
    This class extends the {@link ScheduledThreadPoolExecutor} to provide custom behaviour. + *
    Only the {@link BackgroundWorker} should uses this class to execute tasks in the background *
    - * Example + *

    Example

    *
      *     {@code
      *     BackgroundWorkerThreadService service = new BackgroundWorkerThreadService();
      *     service.submit(() -> System.out.println("Hello World"), "HelloWorld", 1, TimeUnit.SECONDS);
      *     }
      * 
    + *
    + *

    Custom extension

    + *
      + *
    • Adds logging to start and finishing of tasks
    • + *
    • Overrides the default shutdown method to wait for all tasks to finish
    • + *
    • Use virtual threads instead of platform ones
    • + *
    • Adds exception handling for threads
    • + *
    * * @author haevn * @version 1.0 @@ -29,7 +38,16 @@ final class BackgroundWorkerThreadService extends ScheduledThreadPoolExecutor { private static final Logger LOGGER = new Logger(BackgroundWorker.class); /** - * Creates a new {@link BackgroundWorkerThreadService} with the given amount of threads + *

    BackgroundWorkerThreadService(double)

    + *

    Creates a new BackgroundWorkerThreadService with the given amount of threads

    + *

    It will set the innerhited poolsize to the given amount

    + *

    Overrides the thread creation to use a virtual thread with {@link BackgroundWorkerThreadService#exceptionHandler(Thread, Throwable)}

    + *

    Example:

    + *
    +     *     {@code
    +     *     BackgroundWorkerThreadService worker = new BackgroundWorkerThreadService(5);
    +     *     }
    +     * 
    * * @param corePoolSize the amount of threads */ @@ -41,7 +59,15 @@ public BackgroundWorkerThreadService(final int corePoolSize) { /** - * Creates a new {@link BackgroundWorkerThreadService} with 70% of the available processors + *

    BackgroundWorkerThreadService()

    + *

    Creates a new BackgroundWorkerThreadService with 70% of available cores

    + *

    internally the {@link BackgroundWorkerThreadService#BackgroundWorkerThreadService(int)} constructor is called

    + *

    Example:

    + *
    +     *     {@code
    +     *     BackgroundWorkerThreadService worker = new BackgroundWorkerThreadService();
    +     *     }
    +     * 
    */ public BackgroundWorkerThreadService() { this((int) (Runtime.getRuntime().availableProcessors() * 0.7)); @@ -49,7 +75,15 @@ public BackgroundWorkerThreadService() { /** - * Submits a {@link Runnable} to the service, it will be executed as soon as possible and then every {@code interval} time units + *

    submit(Runnable, String, int, TimeUnit)

    + *

    This method logs the submission of a task to the background worker and returns a {@link ScheduledFuture} as result

    + *

    After the logging the task is scheduled to be executed in the given interval

    + *

    Example:

    + *
    +     *     {@code
    +     *     worker.submit(() -> System.out.println("Hello World"), "HelloWorld", 1, TimeUnit.SECONDS);
    +     *     }
    +     * 
    * * @param runnable the task to be executed * @param name the name of the task @@ -63,14 +97,21 @@ public ScheduledFuture submit(final Runnable runnable, final String name, fin } /** - * Submits a {@link Runnable} to the service, it will be executed after {@code delay} time units and then every {@code interval} time units + *

    submit(Runnable, String, int, TimeUnit)

    + *

    This method logs the submission of a task to the background worker and returns a {@link ScheduledFuture} as result

    + *

    After both logging and a delay the task is scheduled to be executed in the given interval

    + *

    Example:

    + *
    +     *     {@code
    +     *     worker.submit(() -> System.out.println("Hello World"), "HelloWorld", 1, TimeUnit.SECONDS);
    +     *     }
    +     * 
    * - * @param runnable the task to be executed + * @param runnable the task * @param name the name of the task - * @param delay the delay before the task should be executed * @param interval the interval in which the task should be executed * @param unit the unit of the interval - * @return a ScheduledFuture representing pending completion of the task + * @return a {@link ScheduledFuture} representing pending completion of the task */ public ScheduledFuture submit(final Runnable runnable, final String name, final int delay, final int interval, final TimeUnit unit) { LOGGER.atInfo().withMessage("Submitting %s to background worker", name).log(); @@ -78,7 +119,14 @@ public ScheduledFuture submit(final Runnable runnable, final String name, fin } /** - * Submits a {@link Runnable} to the service, it will be executed as soon as possible + *

    submitOnce(Runnable, String, long)

    + *

    Submits a {@link Runnable} to the service, it will be executed as soon as possible

    + *

    Example:

    + *
    +     *     {@code
    +     *     worker.submitOnce(() -> System.out.println("Hello World"), "HelloWorld", 1);
    +     *     }
    +     * 
    * * @param runnable the task to be executed * @param name the name of the task @@ -90,7 +138,14 @@ public ScheduledFuture submitOnce(final Runnable runnable, final String name, } /** - * Stops the service and waits 5 seconds for all tasks to finish + *

    shutdown()

    + *

    Shuts down the service and waits for all tasks to finish

    + *

    Example:

    + *
    +     *     {@code
    +     *     worker.shutdown();
    +     *     }
    +     * 
    */ @Override public void shutdown() { @@ -107,7 +162,14 @@ public void shutdown() { } /** - * Stops the service and waits for all tasks to finish + *

    join()

    + *

    Request a shutdown and waits for all tasks to finish

    + *

    Example:

    + *
    +     *     {@code
    +     *     worker.join();
    +     *     }
    +     * 
    */ public void join() { LOGGER.atInfo().withMessage("Waiting for all tasks to finish").log(); @@ -119,11 +181,11 @@ public void join() { } } - - - /** - * Logs an uncaught exception in a thread + *

    exceptionHandler(Thread, Throwable)

    + *

    Logs an uncaught exception in a thread

    + *

    Example:

    + * This is an internal method and should not be called directly * * @param thread the thread * @param throwable the throwable @@ -133,7 +195,8 @@ private void exceptionHandler(final Thread thread, final Throwable throwable) { } /** - * Logs the start of a task + *

    beforeExecute(Thread, Runnable)

    + *

    Overrides the default beforeExecute method to log the start of a task

    * * @param thread the thread that will run task {@code r} * @param runnable the task that will be executed @@ -145,7 +208,8 @@ protected void beforeExecute(final Thread thread, final Runnable runnable) { } /** - * Logs the end of a task + *

    afterExecute(Runnable, Throwable)

    + *

    Overrides the default afterExecute method to log the end of a task

    * * @param runnable the task that has been executed * @param throwable the exception that has been thrown diff --git a/concurrency/src/main/java/de/haevn/utils/concurrency/ConcurrencyUtils.java b/concurrency/src/main/java/de/haevn/utils/concurrency/ConcurrencyUtils.java index b81a645..9108f57 100644 --- a/concurrency/src/main/java/de/haevn/utils/concurrency/ConcurrencyUtils.java +++ b/concurrency/src/main/java/de/haevn/utils/concurrency/ConcurrencyUtils.java @@ -5,7 +5,8 @@ import java.util.concurrent.Callable; -@Draft(description = "This class is a utility class for running tasks concurrently.") +@Draft(description = "This class is a utility class for running tasks concurrently.", + todo = {"Add javadoc", "Refactor"}) public final class ConcurrencyUtils { private static final Logger LOGGER = new Logger(ConcurrencyUtils.class); diff --git a/concurrency/src/main/java/de/haevn/utils/concurrency/ProcessUtils.java b/concurrency/src/main/java/de/haevn/utils/concurrency/ProcessUtils.java index 6e31635..454bbb0 100644 --- a/concurrency/src/main/java/de/haevn/utils/concurrency/ProcessUtils.java +++ b/concurrency/src/main/java/de/haevn/utils/concurrency/ProcessUtils.java @@ -1,5 +1,6 @@ package de.haevn.utils.concurrency; +import de.haevn.annotations.Draft; import de.haevn.utils.datastructure.Tuple; import java.io.IOException; @@ -9,6 +10,8 @@ import java.util.concurrent.CompletableFuture; +@Draft(description = "This class should be used to start processes in a more convenient way", + todo = {"Add javadoc", "Refactor pipe"}) public class ProcessUtils { diff --git a/crypto/src/main/java/de/haevn/utils/crypto/Base32Util.java b/crypto/src/main/java/de/haevn/utils/crypto/Base32Util.java index 9b217b6..c308272 100644 --- a/crypto/src/main/java/de/haevn/utils/crypto/Base32Util.java +++ b/crypto/src/main/java/de/haevn/utils/crypto/Base32Util.java @@ -1,22 +1,44 @@ package de.haevn.utils.crypto; -import de.haevn.annotations.Draft; - -@Draft +/** + *

    Base32Util

    + *
    This class provides utility methods to encode and decode base32 strings + *
    + *

    Example:

    + *
    + *     {@code
    + *     Base32Util.encode("Hello World");
    + *     }
    + * 
    + * + * @author haevn + * @version 1.0 + * @since 2.1 + */ public final class Base32Util { private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; private static final String PADDING = "="; private static final int MASK = 0x1F; - private Base32Util() {} - - public static String encode(final String data) { - return encode(data.getBytes()); + private Base32Util() { } + /** + *

    encode(byte[])

    + *

    Encodes the given byte array to a base32 string

    + *

    Example:

    + *
    +     *     {@code
    +     *     Base32Util.encode(new byte[]{1, 2, 3, 4, 5});
    +     *     }
    +     * 
    + * + * @param data the data to be encoded + * @return the encoded string + */ public static String encode(final byte[] data) { final var length = (data.length * 8 + 4) * 0.2; - final StringBuilder result = new StringBuilder((int)length); + final StringBuilder result = new StringBuilder((int) length); int buffer = data[0]; int next = 1; int bitsLeft = 8; @@ -45,6 +67,36 @@ public static String encode(final byte[] data) { return result.toString(); } + /** + *

    encode(String)

    + *

    Encodes the given string to a base32 string

    + *

    Example:

    + *
    +     *     {@code
    +     *     Base32Util.encode("Hello World");
    +     *     }
    +     * 
    + * + * @param data the data to be encoded + * @return the encoded string + */ + public static String encode(final String data) { + return encode(data.getBytes()); + } + + /** + *

    decode(String)

    + *

    Decodes the given base32 string to a byte array

    + *

    Example:

    + *
    +     *     {@code
    +     *     Base32Util.decode("JBSWY3DPEBLW64TMMQQQ====");
    +     *     }
    +     * 
    + * + * @param encodedString the string to be decoded + * @return the decoded byte array + */ public static byte[] decode(final String encodedString) { final StringBuilder sb = new StringBuilder(); for (char c : encodedString.toCharArray()) { diff --git a/crypto/src/main/java/de/haevn/utils/crypto/Base64Util.java b/crypto/src/main/java/de/haevn/utils/crypto/Base64Util.java index 986f42b..8510519 100644 --- a/crypto/src/main/java/de/haevn/utils/crypto/Base64Util.java +++ b/crypto/src/main/java/de/haevn/utils/crypto/Base64Util.java @@ -7,7 +7,10 @@ import java.util.Base64; /** - * This class provides method to encode and decode data with Base64. + *

    Base64Util

    + *
    + *
    This class provides method to encode and decode data with Base64. + *
    The data can be a text, a byte array or a file. *
      * {@code
      * // Encoding example
    @@ -33,130 +36,190 @@ public final class Base64Util {
         private Base64Util() {
         }
     
    +
         /**
    -     * This class provides methods to encode data with Base64.
    +     * 

    encode(byte[])

    + *

    Encodes the given byte array.

    + * + * @param bytes The bytes to encode + * @return The encoded bytes */ - public static class Encoder { - private Encoder() { - } - - - /** - * Encodes the given text. - * - * @param text The text to encode - * @return The encoded text - */ - public static String encode(final String text) { - return encode(text.getBytes()); - } - - /** - * Encodes the given bytes. - * - * @param bytes The bytes to encode - * @return The encoded bytes - */ - public static String encode(final byte[] bytes) { - return Base64.getEncoder().encodeToString(bytes); - } + public static String encode(final byte[] bytes) { + return Base64.getEncoder().encodeToString(bytes); + } - /** - * Reads the content of the given file and encodes it. - * - * @param file The file to encode - * @return The encoded content of the file - * @throws IOException If an I/O error occurs - */ - public static String encode(final File file) throws IOException { - return encode(new FileInputStream(file)); - } + /** + *

    encode(String)

    + *

    Encodes the given text.

    + *

    This method converts the given text into a byte array and calls {@link Base64Util#encode(byte[])}

    + *

    Example:

    + *
    +     *     {@code
    +     *     Base64Util.encode("Hello World");
    +     *     }
    +     * 
    + * + * @param text The text to encode + * @return The encoded text + */ + public static String encode(final String text) { + return encode(text.getBytes()); + } - /** - * Reads the content of the given file and encodes it. - * - * @param fileInputStream The file to encode - * @return The encoded content of the file - * @throws IOException If an I/O error occurs - */ - public static String encode(final FileInputStream fileInputStream) throws IOException { - final byte[] data = fileInputStream.readAllBytes(); - return encode(data); - } + /** + *

    encode({@link File})

    + *

    Reads the content of the given file and encodes it.

    + *

    This method create a new {@link FileInputStream} and calls {@link Base64Util#encode(InputStream)}

    + *

    Example:

    + *
    +     *     {@code
    +     *     Base64Util.encode(new File("./home/test.txt"));
    +     *     }
    +     * 
    + * + * @param file The file to encode + * @return The encoded content of the file + * @throws IOException If an I/O error occurs + */ + public static String encode(final File file) throws IOException { + return encode(new FileInputStream(file)); + } - /** - * Reads the content of the given file and encodes it. - * - * @param inputStream The file to encode - * @return The encoded content of the file - * @throws IOException If an I/O error occurs - */ - public static String encode(final InputStream inputStream) throws IOException { - final byte[] data = inputStream.readAllBytes(); - return encode(data); - } + /** + *

    encode({@link FileInputStream})

    + *

    Reads the content of the given {@link FileInputStream} and encodes it.

    + *

    This method reads all bytes from the {@link FileInputStream} and calls {@link Base64Util#encode(byte[])}

    + *

    Example:

    + *
    +     *     {@code
    +     *     Base64Util.encode(new FileInputStream(new File("./home/test.txt")));
    +     *     }
    +     * 
    + * + * @param fileInputStream The file to encode + * @return The encoded content of the file + * @throws IOException If an I/O error occurs + */ + public static String encode(final FileInputStream fileInputStream) throws IOException { + final byte[] data = fileInputStream.readAllBytes(); + return encode(data); } /** - * This class provides methods to decode data with Base64. + *

    encode({@link InputStream})

    + *

    Reads the content of the given {@link InputStream} and encodes it.

    + *

    This method reads all bytes from the {@link InputStream} and calls {@link Base64Util#encode(byte[])}

    + *

    Example:

    + *
    +     *     {@code
    +     *     Base64Util.encode(new new DataInputStream(new FileInputStream(data)));
    +     *     Base64Util.encode(new new DataInputStream(new ByteArrayInputStream(data)));
    +     *     }
    +     * 
    + * + * @param inputStream The file to encode + * @return The encoded content of the file + * @throws IOException If an I/O error occurs */ - public static class Decoder { - private Decoder() { - } + public static String encode(final InputStream inputStream) throws IOException { + final byte[] data = inputStream.readAllBytes(); + return encode(data); + } - /** - * Decodes the given text. - * - * @param text The text to decode - * @return The decoded text - */ - public static String decode(final String text) { - return decode(text.getBytes()); - } + /** + *

    decode(byte[])

    + *

    Decodes the given bytes.

    + * + *

    Example:

    + *
    +     *     {@code
    +     *     byte[] data = {...}
    +     *     Base64Util.decode(data);
    +     *     }
    +     * 
    + * + * @param bytes The bytes to decode + * @return The decoded bytes + */ + public static String decode(final byte[] bytes) { + return new String(Base64.getDecoder().decode(bytes)); + } - /** - * Decodes the given bytes. - * - * @param bytes The bytes to decode - * @return The decoded bytes - */ - public static String decode(final byte[] bytes) { - return new String(Base64.getDecoder().decode(bytes)); - } + /** + *

    decode(String)

    + *

    Decodes the given text.

    + *

    This method converts the given text into a byte array and calls {@link Base64Util#decode(byte[])}

    + *

    Example:

    + *
    +     *     {@code
    +     *     Base64Util.decode("SGVsbG8gV29ybGQ=");
    +     *     }
    +     * 
    + * + * @param text The text to decode + * @return The decoded text + */ + public static String decode(final String text) { + return decode(text.getBytes()); + } - /** - * Reads the content of the given file and decodes it. - * - * @param file The file to decode - * @return The decoded content of the file - * @throws IOException If an I/O error occurs - */ - public static String decode(final File file) throws IOException { - return decode(new FileInputStream(file)); - } + /** + *

    decode({@link File})

    + *

    Reads the content of the given file and decodes it.

    + *

    This method create a new {@link FileInputStream} and calls {@link Base64Util#decode(InputStream)}

    + *

    Example:

    + *
    +     *     {@code
    +     *     Base64Util.decode(new File("./home/test.txt"));
    +     *     }
    +     * 
    + * + * @param file The file to decode + * @return The decoded content of the file + * @throws IOException If an I/O error occurs + */ + public static String decode(final File file) throws IOException { + return decode(new FileInputStream(file)); + } - /** - * Reads the content of the given file and decodes it. - * - * @param fileInputStream The file to decode - * @return The decoded content of the file - * @throws IOException If an I/O error occurs - */ - public static String decode(final FileInputStream fileInputStream) throws IOException { - final byte[] data = fileInputStream.readAllBytes(); - return decode(data); - } + /** + *

    decode({@link FileInputStream})

    + *

    Reads the content of the given file and decodes it.

    + *

    This method reads all bytes from the {@link FileInputStream} and calls {@link Base64Util#decode(byte[])}

    + *

    Example:

    + *
    +     *     {@code
    +     *     Base64Util.decode(new FileInputStream(new File("./home/test.txt")));
    +     *     }
    +     * 
    + * + * @param fileInputStream The file to decode + * @return The decoded content of the file + * @throws IOException If an I/O error occurs + */ + public static String decode(final FileInputStream fileInputStream) throws IOException { + final byte[] data = fileInputStream.readAllBytes(); + return decode(data); + } - /** - * Reads the content of the given file and decodes it. - * - * @param inputStream The file to decode - * @return The decoded content of the file - * @throws IOException If an I/O error occurs - */ - public static String decode(final InputStream inputStream) throws IOException { - final byte[] data = inputStream.readAllBytes(); - return decode(data); - } + /** + *

    decode({@link InputStream})

    + *

    Reads the content of the given file and decodes it.

    + *

    This method reads all bytes from the {@link InputStream} and calls {@link Base64Util#decode(byte[])}

    + *

    Example:

    + *
    +     *     {@code
    +     *     Base64Util.decode(new new DataInputStream(new FileInputStream(data)));
    +     *     Base64Util.decode(new new DataInputStream(new ByteArrayInputStream(data)));
    +     *     }
    +     * 
    + * + * @param inputStream The file to decode + * @return The decoded content of the file + * @throws IOException If an I/O error occurs + */ + public static String decode(final InputStream inputStream) throws IOException { + final byte[] data = inputStream.readAllBytes(); + return decode(data); } } diff --git a/crypto/src/main/java/de/haevn/utils/crypto/HashUtil.java b/crypto/src/main/java/de/haevn/utils/crypto/HashUtil.java index 3d03d27..3d902d5 100644 --- a/crypto/src/main/java/de/haevn/utils/crypto/HashUtil.java +++ b/crypto/src/main/java/de/haevn/utils/crypto/HashUtil.java @@ -1,22 +1,77 @@ package de.haevn.utils.crypto; + import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +/** + *

    HashUtil

    + *

    Utility class to hash strings, byte arrays or files.

    + *

    Supported algorithms: MD5, SHA-1, SHA-256, SHA-512

    + *

    Example usage:

    + *
    + * {@code
    + *     HashUtil.Result result = HashUtil.getInstance(HashUtil.HashType.SHA256)
    + *    .hash("Hello World!")
    + *    .getResult();
    + * }
    + *    
    + */ public class HashUtil { private final HashType type; private byte[] hash; + /** + *

    HashUtil({@link HashType})

    + *

    Private constructor to create a new HashUtil instance.

    + *

    Use {@link #getInstance(HashType)} to create a new instance.

    + *

    Supported algorithms: MD5, SHA-1, SHA-256, SHA-512

    + * + * @param type HashType (MD5, SHA-1, SHA-256, SHA-512) + */ private HashUtil(HashType type) { this.type = type; } + /** + *

    getInstance({@link HashType})

    + *

    Factory method to create a new {@link HashUtil HashUtil pipe}.

    + *

    Supported algorithms: MD5, SHA-1, SHA-256, SHA-512

    + *

    Example usage:

    + *
    +     *     {@code
    +     *     HashUtil.Result result = HashUtil.getInstance(HashUtil.HashType.SHA256)
    +     *     .hash("Hello World!")
    +     *     .getResult();
    +     *     }
    +     * 
    + * + * @param type HashType (MD5, SHA-1, SHA-256, SHA-512) + * @return HashUtil instance + */ public static HashUtil getInstance(final HashType type) { return new HashUtil(type); } + /** + *

    hash(byte[])

    + *

    Hashes a byte array and returns the {@link HashUtil HashUtil pipe}.

    + *

    Example usage:

    + *
    +     *     {@code
    +     *     byte[] data = "Hello World!".getBytes();
    +     *     HashUtil.Result result = HashUtil.getInstance(HashUtil.HashType.SHA256)
    +     *     .hash(data)
    +     *     .getResult();
    +     *     }
    +     * 
    + * + * @param input byte array + * @return HashUtil instance + * @throws NoSuchAlgorithmException + */ public HashUtil hash(final byte[] input) throws NoSuchAlgorithmException { final MessageDigest md = MessageDigest.getInstance(type.algorithm); md.update(input); @@ -24,20 +79,70 @@ public HashUtil hash(final byte[] input) throws NoSuchAlgorithmException { return this; } + /** + *

    hash(String)

    + *

    Hashes a string and returns the {@link HashUtil HashUtil pipe}.

    + *

    Example usage:

    + *
    +     *     {@code
    +     *     HashUtil.Result result = HashUtil.getInstance(HashUtil.HashType.SHA256)
    +     *     .hash("Hello World!")
    +     *     .getResult();
    +     *     }
    +     * 
    + * + * @param input string + * @return HashUtil instance + * @throws NoSuchAlgorithmException + */ public HashUtil hash(final String input) throws NoSuchAlgorithmException { return hash(input.getBytes()); } + /** + *

    hash(File)

    + *

    Hashes a file and returns the {@link HashUtil HashUtil pipe}.

    + *

    Example usage:

    + *
    +     *     {@code
    +     *     HashUtil.Result result = HashUtil.getInstance(HashUtil.HashType.SHA256)
    +     *     .hash(new File("./file.txt")
    +     *     .getResult();
    +     *     }
    +     * 
    + * + * @param file file + * @return HashUtil instance + * @throws IOException + * @throws NoSuchAlgorithmException + */ public HashUtil hash(final File file) throws IOException, NoSuchAlgorithmException { return hash(Files.readAllBytes(file.toPath())); } + /** + *

    getResult()

    + *

    Returns the hash result as a {@link Result} object.

    + * + * @return Result object + */ public Result getResult() { return Result.of(hash); } + /** + *

    Result

    + *

    Result object to store the hash result as a string and byte array.

    + */ public record Result(String string, byte[] bytes) { + /** + *

    of(byte[])

    + *

    Factory method to create a new Result object.

    + * + * @param bytes byte array + * @return Result object + */ public static Result of(final byte[] bytes) { final StringBuilder sb = new StringBuilder(); for (byte b : bytes) { @@ -52,6 +157,10 @@ public String toString() { } } + /** + *

    HashType

    + *

    Supported hash algorithms: MD5, SHA-1, SHA-256, SHA-512

    + */ public enum HashType { MD5("MD5"), SHA1("SHA-1"), diff --git a/crypto/src/main/java/de/haevn/utils/crypto/ICryptoUtils.java b/crypto/src/main/java/de/haevn/utils/crypto/ICryptoUtils.java index 02b66c1..dad354c 100644 --- a/crypto/src/main/java/de/haevn/utils/crypto/ICryptoUtils.java +++ b/crypto/src/main/java/de/haevn/utils/crypto/ICryptoUtils.java @@ -5,7 +5,11 @@ import java.nio.file.Files; /** - * This interface provides an abstraction layer for decryption and encryption of data. + *

    ICryptoUtils

    + *
    + *

    This interface provides an abstraction layer for decryption and encryption of data.

    + *

    The data can be a {@link File}, {@link String text} or a byte array.

    + *

    The interface provides a couple default operation which call the main methods {@link ICryptoUtils#encrypt(byte[])} and {@link ICryptoUtils#decrypt(byte[])}

    * * @author haevn * @version 1.1 @@ -14,7 +18,15 @@ public interface ICryptoUtils { /** - * Reads the content of the given file and encrypts it. + *

    encrypt({@link File})

    + *

    Reads the content of the given file and encrypts it using {@link ICryptoUtils#encrypt(String)}.

    + *

    Example:

    + *
    +     *     {@code
    +     *     ICryptoUtils encryptor = new DummyEncryptor();
    +     *     final byte[] encrypted = encryptor.encrypt(new File("./home/test.txt"));
    +     *     }
    +     * 
    * * @param file The file to encrypt * @return The encrypted content of the file @@ -26,7 +38,16 @@ default byte[] encrypt(final File file) throws IOException { } /** - * Encrypts the given text. + *

    encrypt(String)

    + *

    Encrypts the given text.

    + *

    This method converts the given text into a byte array and calls {@link ICryptoUtils#encrypt(byte[])}

    + *

    Example:

    + *
    +     *     {@code
    +     *     ICryptoUtils encryptor = new DummyEncryptor();
    +     *     final byte[] encrypted = encryptor.encrypt("Hello World");
    +     *     }
    +     * 
    * * @param text The text to encrypt * @return The encrypted text @@ -36,7 +57,17 @@ default byte[] encrypt(final String text) { } /** - * Encrypts the given bytes. + *

    encrypt(byte[])

    + *

    Encrypts the given bytes.

    + *

    This method must be implemented and serves as a common base

    + *

    Example:

    + *
    +     *     {@code
    +     *     byte[] data = {...}
    +     *     ICryptoUtils encryptor = new DummyEncryptor();
    +     *     final byte[] encrypted = encryptor.encrypt(data);
    +     *     }
    +     * 
    * * @param bytes The bytes to encrypt * @return The encrypted bytes @@ -45,7 +76,15 @@ default byte[] encrypt(final String text) { /** - * Reads the content of the given file and decrypts it. + *

    decrypt({@link File})

    + *

    Reads the content of the given file and decrypts it using {@link ICryptoUtils#decrypt(String)}.

    + *

    Example:

    + *
    +     *     {@code
    +     *     ICryptoUtils encryptor = new DummyEncryptor();
    +     *     final byte[] decrypted = encryptor.decrypt(new File("./home/test.txt"));
    +     *     }
    +     * 
    * * @param file The file to decrypt * @return The decrypted content of the file @@ -57,7 +96,16 @@ default byte[] decrypt(final File file) throws IOException { } /** - * Decrypts the given text. + *

    decrypt(String)

    + *

    Decrypts the given text.

    + *

    This method converts the given text into a byte array and calls {@link ICryptoUtils#decrypt(byte[])}

    + *

    Example:

    + *
    +     *     {@code
    +     *     ICryptoUtils encryptor = new DummyEncryptor();
    +     *     final byte[] decrypted = encryptor.decrypt("Hello World");
    +     *     }
    +     * 
    * * @param text The text to decrypt * @return The decrypted text @@ -67,7 +115,17 @@ default byte[] decrypt(final String text) { } /** - * Decrypts the given bytes. + *

    decrypt(byte[])

    + *

    Decrypts the given bytes.

    + *

    This method must be implemented and serves as a common base

    + *

    Example:

    + *
    +     *     {@code
    +     *     byte[] data = {...}
    +     *     ICryptoUtils encryptor = new DummyEncryptor();
    +     *     final byte[] decrypted = encryptor.decrypt(data);
    +     *     }
    +     * 
    * * @param bytes The bytes to decrypt * @return The decrypted bytes diff --git a/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java b/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java index 8b8d804..f9bba43 100644 --- a/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java +++ b/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java @@ -1,7 +1,5 @@ package de.haevn.utils.crypto; -import de.haevn.annotations.Draft; - import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import javax.imageio.ImageIO; @@ -16,12 +14,53 @@ import java.security.SecureRandom; import java.time.Instant; -@Draft +/** + *

    OneTimePassword

    + *
    + *
    This class provides methods to generate a One Time Password (OTP) based on the Time-based One Time Password (TOTP) algorithm. + *
    The TOTP algorithm is based on the HMAC-SHA1 algorithm and generates a 6-digit OTP. + *
    The class also provides methods to generate a secret key and a QR code for the secret key. + *
    + *

    Example:

    + *
    + *     {@code
    + *     final String secret = OneTimePassword.generateSecretKey();
    + *     final String otp = OneTimePassword.generateTOTP(secret);
    + *     final String otp = OneTimePassword.generateCode();
    + *     final String otp = OneTimePassword.generateCode(secret);
    + *     final String otp = OneTimePassword.generateCodeAndShow("MyApp");
    + *     final String otp = OneTimePassword.generateCodeAndShow("MyApp", secret);
    + *     }
    + * 
    + */ public final class OneTimePassword { + /** + * The time step in milliseconds. + */ private static final long TIME_STEP = 30_000L; + /** + * The length of the secret key. + */ private static final int SECRET_KEY_LENGTH = 20; + private OneTimePassword() { + } + + /** + *

    generateTOTP(String)

    + *

    Generates a Time-based One Time Password (TOTP) based on the given secret key.

    + *

    Example:

    + *
    +     *     {@code
    +     *     final String secret = OneTimePassword.generateSecretKey();
    +     *     final String otp = OneTimePassword.generateTOTP(secret);
    +     *     }
    +     * 
    + * + * @param secret The secret key + * @return The generated OTP + */ public static String generateTOTP(final String secret) { byte[] key = Base32Util.decode(secret); final long time = (Instant.now().toEpochMilli() / TIME_STEP); @@ -42,6 +81,22 @@ public static String generateTOTP(final String secret) { return String.format("%06d", otp); } + /** + *

    hmacSha1(byte[], byte[])

    + *

    Generates a HMAC-SHA1 hash based on the given key and data.

    + *

    Example:

    + *
    +     *     {@code
    +     *     final byte[] key = {...};
    +     *     final byte[] data = {...};
    +     *     final byte[] hash = OneTimePassword.hmacSha1(key, data);
    +     *     }
    +     * 
    + * + * @param key The key + * @param data The data + * @return The generated hash + */ private static byte[] hmacSha1(final byte[] key, final byte[] data) { try { final SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA1"); @@ -53,6 +108,18 @@ private static byte[] hmacSha1(final byte[] key, final byte[] data) { } } + /** + *

    generateSecretKey()

    + *

    Generates a random secret key for the TOTP algorithm.

    + *

    Example:

    + *
    +     *     {@code
    +     *     final String secret = OneTimePassword.generateSecretKey();
    +     *     }
    +     * 
    + * + * @return The generated secret key + */ public static String generateSecretKey() { final SecureRandom random = new SecureRandom(); byte[] bytes = new byte[SECRET_KEY_LENGTH]; @@ -60,19 +127,79 @@ public static String generateSecretKey() { return Base32Util.encode(bytes); } - + /** + *

    generateCode()

    + *

    Generates a Time-based One Time Password (TOTP) based on a random secret key.

    + *

    Example:

    + *
    +     *     {@code
    +     *     final String otp = OneTimePassword.generateCode();
    +     *     }
    +     * 
    + * + * @return The generated OTP + */ public static String generateCode() { return generateTOTP(generateSecretKey()); } + /** + *

    generateCode(String)

    + *

    Generates a Time-based One Time Password (TOTP) based on the given secret key.

    + *

    Example:

    + *
    +     *     {@code
    +     *     final String secret = OneTimePassword.generateSecretKey();
    +     *     final String otp = OneTimePassword.generateCode(secret);
    +     *     }
    +     * 
    + * + * @param secret The secret key + * @return The generated OTP + */ public static String generateCode(final String secret) { return generateTOTP(secret); } + /** + *

    generateCodeAndShow(String)

    + *

    Generates a Time-based One Time Password (TOTP) based on a random secret key and shows a QR code with + * the secret key.

    + *

    Example:

    + *
    +     *     {@code
    +     *     final String otp = OneTimePassword.generateCodeAndShow("MyApp");
    +     *     }
    +     * 
    + * + * @param name The name of the application + * @return The generated OTP + * @throws IOException If an I/O error occurs + */ public static String generateCodeAndShow(final String name) throws IOException { return generateCodeAndShow(name, generateSecretKey()); } + /** + *

    generateCodeAndShow(String, String)

    + *

    Generates a Time-based One Time Password (TOTP) based on the given secret key and shows a QR code with + * the secret key.

    + *

    The OTP is updated every second.

    + *

    The QR code will be generated by an external service.

    + * https://goqr.me/api/ + *

    Example:

    + *
    +     *     {@code
    +     *     final String secret = OneTimePassword.generateSecretKey();
    +     *     final String otp = OneTimePassword.generateCodeAndShow("MyApp", secret);
    +     *     }
    +     * 
    + * + * @param name The name of the application + * @param secret The secret key + * @return The generated OTP + * @throws IOException If an I/O error occurs + */ public static String generateCodeAndShow(final String name, final String secret) throws IOException { final String totp = generateTOTP(secret); diff --git a/enumeration/src/main/java/de/haevn/utils/enumeration/BinarySize.java b/enumeration/src/main/java/de/haevn/utils/enumeration/BinarySize.java index 1845760..94d875a 100644 --- a/enumeration/src/main/java/de/haevn/utils/enumeration/BinarySize.java +++ b/enumeration/src/main/java/de/haevn/utils/enumeration/BinarySize.java @@ -1,10 +1,25 @@ package de.haevn.utils.enumeration; /** - * A simple enum for binary sizes. + *

    BinarySize

    + *
    + *
    A simple enum for binary sizes, the base size is one Byte. + *
    The enum provides the following sizes: + *
      + *
    • BYTE
    • + *
    • KILOBYTE
    • + *
    • MEGABYTE
    • + *
    • GIGABYTE
    • + *
    • TERABYTE
    • + *
    • PETABYTE
    • + *
    • EXABYTE
    • + *
    • ZETTABYTE
    • + *
    • YOTTABYTE
    • + *
    + * + * @author haevn * @version 1.0 * @since 1.0 - * @author haevn */ public enum BinarySize { BYTE(1), @@ -18,11 +33,12 @@ public enum BinarySize { YOTTABYTE(ZETTABYTE.getValue() * 1024); private final long value; - BinarySize(final long value){ + + BinarySize(final long value) { this.value = value; } - public long getValue(){ + public long getValue() { return value; } } diff --git a/enumeration/src/main/java/de/haevn/utils/enumeration/MicroTimeUnits.java b/enumeration/src/main/java/de/haevn/utils/enumeration/MicroTimeUnits.java index 164b995..2b29e85 100644 --- a/enumeration/src/main/java/de/haevn/utils/enumeration/MicroTimeUnits.java +++ b/enumeration/src/main/java/de/haevn/utils/enumeration/MicroTimeUnits.java @@ -1,10 +1,26 @@ package de.haevn.utils.enumeration; /** - * A simple enum for micro time units. + *

    MicroTimeUnits

    + *
    + *
    A simple enum for micro time units. + *
    The base unit is a microsecond. + *
    The enum provides the following units: + *
      + *
    • MICROSECONDS
    • + *
    • MILLISECONDS
    • + *
    • SECONDS
    • + *
    • MINUTES
    • + *
    • HOURS
    • + *
    • DAYS
    • + *
    • WEEKS
    • + *
    • MONTHS
    • + *
    • YEARS
    • + *
    + * + * @author haevn * @version 1.0 * @since 1.0 - * @author haevn */ public enum MicroTimeUnits { diff --git a/enumeration/src/main/java/de/haevn/utils/enumeration/MillisecondTimeUnits.java b/enumeration/src/main/java/de/haevn/utils/enumeration/MillisecondTimeUnits.java index 87c207b..c1440ca 100644 --- a/enumeration/src/main/java/de/haevn/utils/enumeration/MillisecondTimeUnits.java +++ b/enumeration/src/main/java/de/haevn/utils/enumeration/MillisecondTimeUnits.java @@ -1,10 +1,25 @@ package de.haevn.utils.enumeration; /** - * A simple enum for millisecond time units. + *

    MillisecondTimeUnits

    + *
    + *
    A simple enum for millisecond time units. + *
    The base unit is a millisecond. + *
    The enum provides the following units: + *
      + *
    • MILLISECONDS
    • + *
    • SECONDS
    • + *
    • MINUTES
    • + *
    • HOURS
    • + *
    • DAYS
    • + *
    • WEEKS
    • + *
    • MONTHS
    • + *
    • YEARS
    • + *
    + * + * @author haevn * @version 1.0 * @since 1.0 - * @author haevn */ public enum MillisecondTimeUnits { MILLISECONDS(1), diff --git a/enumeration/src/main/java/de/haevn/utils/enumeration/NanoTimeUnits.java b/enumeration/src/main/java/de/haevn/utils/enumeration/NanoTimeUnits.java index 54f0184..543828b 100644 --- a/enumeration/src/main/java/de/haevn/utils/enumeration/NanoTimeUnits.java +++ b/enumeration/src/main/java/de/haevn/utils/enumeration/NanoTimeUnits.java @@ -1,10 +1,27 @@ package de.haevn.utils.enumeration; /** - * A simple enum for nano time units. + *

    NanoTimeUnits

    + *
    + *
    A simple enum for nano time units. + *
    The base unit is a nanosecond. + *
    The enum provides the following units: + *
      + *
    • NANOSECONDS
    • + *
    • MICROSECONDS
    • + *
    • MILLISECONDS
    • + *
    • SECONDS
    • + *
    • MINUTES
    • + *
    • HOURS
    • + *
    • DAYS
    • + *
    • WEEKS
    • + *
    • MONTHS
    • + *
    • YEARS
    • + *
    + * + * @author haevn * @version 1.0 * @since 1.0 - * @author haevn */ public enum NanoTimeUnits { NANOSECONDS(1), diff --git a/pom.xml b/pom.xml index 55495df..f440bc5 100644 --- a/pom.xml +++ b/pom.xml @@ -185,5 +185,6 @@ network utils swing + tools \ No newline at end of file diff --git a/tools/pom.xml b/tools/pom.xml new file mode 100644 index 0000000..09ed16a --- /dev/null +++ b/tools/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + de.haevn + Utility + 2.1 + + + tools + + + 22 + 22 + UTF-8 + + + \ No newline at end of file diff --git a/tools/src/main/java/de/haevn/utils/DocuHelper.java b/tools/src/main/java/de/haevn/utils/DocuHelper.java new file mode 100644 index 0000000..d1b8477 --- /dev/null +++ b/tools/src/main/java/de/haevn/utils/DocuHelper.java @@ -0,0 +1,54 @@ +package de.haevn.utils; + +import java.util.ArrayList; +import java.util.List; + +public class DocuHelper { + + public static void main(String[] args) { + System.out.println("DocuHelper will generate a documentation for the given class."); + System.out.println("Enter the header (typical name of the class/method/value"); + String header = System.console().readLine(); + System.out.println("Enter the description (!q to finish)"); + List lines = new ArrayList<>(); + String line; + while (!(line = System.console().readLine()).equals("!q")) { + lines.add(line); + } + System.out.println("Enter an example: "); + String example = System.console().readLine(); + System.out.println("Enter the author: "); + String author = System.console().readLine(); + System.out.println("Enter the version: "); + String version = System.console().readLine(); + System.out.println("Enter the since: "); + String since = System.console().readLine(); + System.out.println("Enter the author"); + Documentation documentation = new Documentation(header, lines, example, author, version, since); + System.out.println("Documentation generated: " + documentation); + + } + + private record Documentation(String header, List lines, + String example, String author, String version, String since) { + @Override + public String toString() { + return """ + \n/** + *

    %s

    + *
    %s + *
    + *

    Example

    + *
    +                     * {@code
    +                     * %s
    +                     * }
    +                     * 
    + * @author %s + * @version %s + * @since %s + */ + """.formatted(header, String.join("\n*
    ", lines), example, author, version, since); + } + } +} From 92ac32d2c2669483dcd6e6f27481655d0657a3dc Mon Sep 17 00:00:00 2001 From: Nils M Date: Sun, 30 Jun 2024 01:51:15 +0200 Subject: [PATCH 09/17] Rewrote documentation --- .../de/haevn/annotations/AnnotationUtils.java | 8 +- .../java/de/haevn/utils/crypto/HashUtil.java | 8 +- .../haevn/utils/crypto/OneTimePassword.java | 8 +- .../de/haevn/utils/datastructure/Cache.java | 109 +++++- .../utils/datastructure/NotifiableList.java | 138 ++++++- .../utils/datastructure/ObjectGroup.java | 292 ++++++++++++++- .../haevn/utils/datastructure/Observable.java | 98 +++++ .../utils/datastructure/ReadonlyTripple.java | 30 +- .../utils/datastructure/ReadonlyTuple.java | 28 +- .../utils/datastructure/SearchableList.java | 343 +++++++++++++++++- .../de/haevn/utils/datastructure/Tripple.java | 95 ++++- .../de/haevn/utils/datastructure/Tuple.java | 61 +++- 12 files changed, 1157 insertions(+), 61 deletions(-) diff --git a/annotations/src/main/java/de/haevn/annotations/AnnotationUtils.java b/annotations/src/main/java/de/haevn/annotations/AnnotationUtils.java index 9fda5e9..0f3c509 100644 --- a/annotations/src/main/java/de/haevn/annotations/AnnotationUtils.java +++ b/annotations/src/main/java/de/haevn/annotations/AnnotationUtils.java @@ -95,6 +95,7 @@ public static List findLauncher(final String packageName) { * findAnnotation("de.haevn.annotations", AutoCollect.class); // Returns a list with Example.class * } *
    + * * @param packageName The package to search in * @param annotation The annotation to search for * @return A list of all found {@link Annotation} @@ -124,9 +125,10 @@ public static List findAnnotation(final String packageName * getClass("Example.class", "de.haevn); // Returns Example.class * } *
    - * @param className - * @param packageName - * @return + * + * @param className The name of the class + * @param packageName The package name + * @return The class or null if not found */ private static Class getClass(final String className, final String packageName) { try { diff --git a/crypto/src/main/java/de/haevn/utils/crypto/HashUtil.java b/crypto/src/main/java/de/haevn/utils/crypto/HashUtil.java index 3d902d5..465e347 100644 --- a/crypto/src/main/java/de/haevn/utils/crypto/HashUtil.java +++ b/crypto/src/main/java/de/haevn/utils/crypto/HashUtil.java @@ -70,7 +70,7 @@ public static HashUtil getInstance(final HashType type) { * * @param input byte array * @return HashUtil instance - * @throws NoSuchAlgorithmException + * @throws NoSuchAlgorithmException if the algorithm is not supported */ public HashUtil hash(final byte[] input) throws NoSuchAlgorithmException { final MessageDigest md = MessageDigest.getInstance(type.algorithm); @@ -93,7 +93,7 @@ public HashUtil hash(final byte[] input) throws NoSuchAlgorithmException { * * @param input string * @return HashUtil instance - * @throws NoSuchAlgorithmException + * @throws NoSuchAlgorithmException if the algorithm is not supported */ public HashUtil hash(final String input) throws NoSuchAlgorithmException { return hash(input.getBytes()); @@ -113,8 +113,8 @@ public HashUtil hash(final String input) throws NoSuchAlgorithmException { * * @param file file * @return HashUtil instance - * @throws IOException - * @throws NoSuchAlgorithmException + * @throws IOException if an I/O error occurs + * @throws NoSuchAlgorithmException if the algorithm is not supported */ public HashUtil hash(final File file) throws IOException, NoSuchAlgorithmException { return hash(Files.readAllBytes(file.toPath())); diff --git a/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java b/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java index f9bba43..919ae36 100644 --- a/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java +++ b/crypto/src/main/java/de/haevn/utils/crypto/OneTimePassword.java @@ -1,5 +1,7 @@ package de.haevn.utils.crypto; +import de.haevn.utils.TimeUtils; + import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import javax.imageio.ImageIO; @@ -228,11 +230,7 @@ public static String generateCodeAndShow(final String name, final String secret) Thread.ofVirtual().start(() -> { while (frame.isVisible()) { otp.setText(generateTOTP(secret)); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } + TimeUtils.sleepSecond(1); } }); return totp; diff --git a/datastructures/src/main/java/de/haevn/utils/datastructure/Cache.java b/datastructures/src/main/java/de/haevn/utils/datastructure/Cache.java index a08ce58..f291903 100644 --- a/datastructures/src/main/java/de/haevn/utils/datastructure/Cache.java +++ b/datastructures/src/main/java/de/haevn/utils/datastructure/Cache.java @@ -3,40 +3,145 @@ import de.haevn.utils.enumeration.MillisecondTimeUnits; /** - * This is a simple cache class that can be used to cache values for a certain amount of time.
    - * The default duration is 1 day.
    + *

    Cache

    + *
    + *

    This is a simple cache class that can be used to cache values for a certain amount of time.

    + *

    The default duration is 1 day.

    + *

    It is possible to renew the cache by calling the {@link Cache#renew()} method.

    + * + *

    Example

    + *
    + * {@code
    + *     final Cache cache = new Cache<>("Hello World");
    + *     if(cache.isValid()){
    + *        System.out.println(cache.getValue());
    + *     }
    + *     cache.renew();
    + *     System.out.println(cache.isValid());
    + *     String value = cache.getValue();
    + * }
    + * 
    * @param The type of the cached value. * @version 1.0 * @since 1.0 * @author haevn */ public class Cache { + + /** + * The duration of the cache in milliseconds. + */ private final long duration; + + /** + * The value of the cache. + */ private final T value; + + /** + * The creation time of the cache. + */ private final long creationTime; + /** + *

    Cache(T)

    + *

    Creates a new cache with the given value and a default duration of 1 day.

    + *

    Example:

    + *
    +     *     {@code
    +     *     final Cache cache = new Cache<>("Hello World");
    +     *     }
    +     * 
    + * @param value the value to be cached + */ public Cache(final T value){ this(value, MillisecondTimeUnits.DAYS.getValue()); } + /** + *

    Cache(T, long)

    + *

    Creates a new cache with the given value and duration.

    + *

    Example:

    + *
    +     *     {@code
    +     *     final Cache cache = new Cache<>("Hello World", 1000);
    +     *     }
    +     * 
    + * @param value the value to be cached + * @param duration the duration of the cache + */ public Cache(final T value, long duration){ this.value = value; this.duration = duration; this.creationTime = System.currentTimeMillis(); } + /** + *

    isValid()

    + *

    Checks if the cache is still valid.

    + *

    A cache is valid if the current time is less than the creation time plus the duration.

    + *

    Example:

    + *
    +     *     {@code
    +     *     final Cache cache = new Cache<>("Hello World");
    +     *     if(cache.isValid()){
    +     *        System.out.println(cache.getValue());
    +     *     }
    +     *     }
    +     * 
    + * @return true if the cache is valid, false otherwise + */ public boolean isValid(){ return System.currentTimeMillis() - creationTime < duration; } + /** + *

    isInvalid()

    + *

    Checks if the cache is invalid.

    + *

    A cache is invalid if the current time is greater than the creation time plus the duration.

    + *

    Example:

    + *
    +     *     {@code
    +     *     final Cache cache = new Cache<>("Hello World");
    +     *     if(cache.isInvalid()){
    +     *        System.out.println("Cache is invalid");
    +     *     }
    +     *     }
    +     * 
    + * @return true if the cache is invalid, false otherwise + */ public boolean isInvalid(){ return !isValid(); } + /** + *

    getValue()

    + *

    Returns the value of the cache.

    + *

    Example:

    + *
    +     *     {@code
    +     *     final Cache cache = new Cache<>("Hello World");
    +     *     System.out.println(cache.getValue());
    +     *     }
    +     * 
    + * @return the value of the cache + */ public T getValue() { return value; } + /** + *

    renew()

    + *

    Creates a new cache with the same value and duration.

    + *

    Example:

    + *
    +     *     {@code
    +     *     final Cache cache = new Cache<>("Hello World");
    +     *     cache.renew();
    +     *     }
    +     * 
    + * @return a new cache with the same value and duration + */ public Cache renew(){ return new Cache<>(value, duration); } diff --git a/datastructures/src/main/java/de/haevn/utils/datastructure/NotifiableList.java b/datastructures/src/main/java/de/haevn/utils/datastructure/NotifiableList.java index 553830f..d916f0a 100644 --- a/datastructures/src/main/java/de/haevn/utils/datastructure/NotifiableList.java +++ b/datastructures/src/main/java/de/haevn/utils/datastructure/NotifiableList.java @@ -4,17 +4,73 @@ import java.util.Collection; import java.util.List; +/** + *

    NotifiableList

    + *
    + *

    This class extends the {@link ArrayList} class and provides the {@link IListUpdateConsumer} interface to notify + * consumers about changes in the list.

    + * + *

    Example

    + *
    + * {@code
    + *     final NotifiableList list = new NotifiableList<>();
    + *     list.subscribe((object, added) -> System.out.println("Object " + object + " was " + (added ? "added" : "removed")));
    + *     list.add("Hello World");
    + *     list.remove("Hello World");
    + * }
    + * 
    + * @param + */ public class NotifiableList extends ArrayList { + + /** + * The list of consumers that are subscribed to this list. + */ final List> consumers = new ArrayList<>(); + /** + *

    subscribe(IListUpdateConsumer)

    + *

    Subscribes a consumer to this list.

    + *

    Example:

    + *
    +     *     {@code
    +     *     list.subscribe((object, added) -> System.out.println("Object " + object + " was " + (added ? "added" : "removed")));
    +     *     }
    +     * 
    + * @param consumer the consumer to be subscribed + */ public void subscribe(final IListUpdateConsumer consumer) { consumers.add(consumer); } + /** + *

    unsubscribe(IListUpdateConsumer)

    + *

    Unsubscribes a consumer from this list.

    + *

    Example:

    + *
    +     *     {@code
    +     *     list.unsubscribe(consumer);
    +     *     }
    +     * 
    + * @param consumer the consumer to be unsubscribed + */ public void unsubscribe(final IListUpdateConsumer consumer) { consumers.remove(consumer); } + /** + *

    add(T)

    + *

    Appends the specified element to the end of this list and notifies all subscribed consumers.

    + *

    Example:

    + *
    +     * {@code
    +     *     list.add("Hello World");
    +     * }
    +     * 
    + * @see ArrayList#add(Object) + * @param t element whose presence in this collection is to be ensured + * @return true if this collection changed as a result of the call + */ @Override public boolean add(final T t) { boolean added = super.add(t); @@ -24,6 +80,19 @@ public boolean add(final T t) { return added; } + /** + *

    addAll(Collection)

    + *

    Appends all of the elements in the specified collection to the end of this list, in the order that they are returned by the specified collection's iterator and notifies all subscribed consumers.

    + *

    Example:

    + *
    +     * {@code
    +     *     list.addAll(Arrays.asList("Hello", "World"));
    +     * }
    +     * 
    + * @see ArrayList#addAll(Collection) + * @param list collection containing elements to be added to this list + * @return true if this list changed as a result of the call + */ @Override public boolean addAll(final Collection list) { boolean added = super.addAll(list); @@ -33,6 +102,19 @@ public boolean addAll(final Collection list) { return added; } + /** + *

    remove(Object)

    + *

    Removes the first occurrence of the specified element from this list, if it is present and notifies all subscribed consumers.

    + *

    Example:

    + *
    +     * {@code
    +     *     list.remove("Hello World");
    +     * }
    +     * 
    + * @see ArrayList#remove(Object) + * @param obj object to be removed from this list, if present + * @return true if an element was removed as a result of this call + */ public boolean removeElement(final T obj) { boolean removed = super.remove(obj); if (removed) { @@ -41,6 +123,20 @@ public boolean removeElement(final T obj) { return removed; } + /** + *

    remove(int)

    + *

    Removes the element at the specified position in this list and notifies all subscribed consumers.

    + *

    Example:

    + *
    +     * {@code
    +     *     list.remove(0);
    +     * }
    +     * 
    + * + * @see ArrayList#remove(int) + * @param index the index of the element to be removed + * @return the element that was removed from the list + */ @Override public T remove(final int index) { T removed = super.remove(index); @@ -50,13 +146,53 @@ public T remove(final int index) { return removed; } + /** + *

    clear()

    + *

    Removes all of the elements from this list and notifies all subscribed consumers.

    + * + *

    Example:

    + *
    +     * {@code
    +     *     list.clear();
    +     * }
    +     * 
    + * @see ArrayList#clear() + */ @Override public void clear() { super.forEach(t -> consumers.forEach(consumer -> consumer.changed(t, false))); super.clear(); } - public static interface IListUpdateConsumer { + /** + *

    IListUpdateConsumer

    + *

    Functional interface to consume changes in a list.

    + *

    Example:

    + *
    +     * {@code
    +     *     list.subscribe((object, added) -> System.out.println("Object " + object + " was " + (added ? "added" : "removed")));
    +     * }
    +     * 
    + * @param + */ + public interface IListUpdateConsumer { + /** + *

    changed(T, boolean)

    + *

    Called when an object is added or removed from the list.

    + *

    Example:

    + *
    +         * {@code
    +         *      list.subscribe((object, added) -> System.out.println("Object " + object + " was " + (added ? "added" : "removed")));
    +         *      IListUpdateConsumer consumer = new IListUpdateConsumer() {
    +         *          @Override
    +         *          public void changed(Object object, boolean added) {
    +         *              System.out.println("Object " + object + " was " + (added ? "added" : "removed"));
    +         *          }
    +         *      };
    +         * }
    +         * @param object the object that was added or removed
    +         * @param added true if the object was added, false if it was removed
    +         */
             void changed(final T object, final boolean added);
         }
     }
    diff --git a/datastructures/src/main/java/de/haevn/utils/datastructure/ObjectGroup.java b/datastructures/src/main/java/de/haevn/utils/datastructure/ObjectGroup.java
    index 7a0ebf3..2683f28 100644
    --- a/datastructures/src/main/java/de/haevn/utils/datastructure/ObjectGroup.java
    +++ b/datastructures/src/main/java/de/haevn/utils/datastructure/ObjectGroup.java
    @@ -9,7 +9,32 @@
     
     
     /**
    - * A simple class for grouping objects.
    + * 

    ObjectGroup

    + *
    + *

    This class provides a simple way to group objects together.

    + *

    Following operations are supported:

    + *
      + *
    • Adding elements
    • + *
    • Removing elements
    • + *
    • Clearing the group
    • + *
    • Getting the elements
    • + *
    • Check if an element is in the group
    • + *
    • Filtering for specific elements
    • + *
    • Applying a custom operation to each element
    • + *
    + *

    Note: Most operation are piped and return their instance

    + *

    Example

    + *
    + * {@code
    + *     final ObjectGroup group = new ObjectGroup<>();
    + *     group.add("Hello")
    + *     .add("World")
    + *     .forEach(System.out::println)
    + *     .add("!")
    + *     .forEach(System.out::println)
    + *     .clear();
    + * }
    + * 
    * * @param The type of the object * @author haevn @@ -19,90 +44,355 @@ public class ObjectGroup { private final List elements; + /** + *

    ObjectGroup()

    + *

    Creates a new ObjectGroup with an empty list of elements.

    + */ public ObjectGroup() { this(new ArrayList<>()); } + /** + *

    ObjectGroup(T...)

    + *

    Creates a new ObjectGroup with the given elements.

    + * @param elements The elements to be added to the group + */ @SafeVarargs public ObjectGroup(final T... elements) { this(List.of(elements)); } + /** + *

    ObjectGroup(List)

    + *

    Creates a new ObjectGroup with the given list of elements.

    + * @param elements The list of elements to be added to the group + */ public ObjectGroup(final List elements) { this.elements = elements; } + /** + *

    add(T)

    + *

    Adds an element to the group.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>();
    +     *     group.add("Hello World");
    +     * }
    +     * 
    + * @param element The element to be added + * @return The ObjectGroup instance + */ public ObjectGroup add(final T element) { elements.add(element); return this; } + /** + *

    addAll(T...)

    + *

    Adds multiple elements to the group.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>();
    +     *     group.addAll("Hello", "World");
    +     * }
    +     * 
    + * @param elements The elements to be added + * @return The ObjectGroup instance + */ @SafeVarargs public final ObjectGroup addAll(final T... elements) { this.elements.addAll(List.of(elements)); return this; } + /** + *

    addAll(List)

    + *

    Adds multiple elements to the group.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>();
    +     *     group.addAll(List.of("Hello", "World"));
    +     * }
    +     * 
    + * @param elements The elements to be added + * @return The ObjectGroup instance + */ + public ObjectGroup addAll(final List elements) { + this.elements.addAll(elements); + return this; + } + + /** + *

    remove(T)

    + *

    Removes an element from the group.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>();
    +     *     group.remove(obj);
    +     * }
    +     * 
    +     * @param element The element to be removed
    +     * @return The ObjectGroup instance
    +     */
         public ObjectGroup remove(final T element) {
             elements.remove(element);
             return this;
         }
     
    +    /**
    +     * 

    clear()

    + *

    Removes all elements from the group.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>();
    +     *     group.clear();
    +     * }
    +     * 
    +     * @return The ObjectGroup instance
    +     */
         public ObjectGroup clear() {
             elements.clear();
             return this;
         }
     
    +    /**
    +     * 

    getElements()

    + *

    Returns the list of elements.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>();
    +     *     List elements = group.getElements();
    +     * }
    +     * 
    +     * @return The list of elements
    +     */
         public List getElements() {
             return elements;
         }
     
    +    /**
    +     * 

    size()

    + *

    Returns the number of elements in the group.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>();
    +     *     int size = group.size();
    +     * }
    +     * 
    +     *
    +     * @return The number of elements in the group
    +     */
         public int size() {
             return elements.size();
         }
     
    +    /**
    +     * 

    isEmpty()

    + *

    Checks if the group is empty.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>();
    +     *     boolean isEmpty = group.isEmpty();
    +     * }
    +     * 
    +     * @return true if the group is empty, false otherwise
    +     */
         public boolean isEmpty() {
             return elements.isEmpty();
         }
     
    +    /**
    +     * 

    contains(T)

    + *

    Checks if the group contains a specific element.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>();
    +     *     boolean contains = group.contains(obj);
    +     * }
    +     * 
    +     * @param element The element to be checked
    +     * @return true iff the group contains the element, false otherwise
    +     */
         public boolean contains(final T element) {
             return elements.contains(element);
         }
     
    +    /**
    +     * 

    get(int)

    + *

    Returns the element at the specified position in the group.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>();
    +     *     Object obj = group.get(0);
    +     * }
    +     * 
    +     * @param index The index of the element
    +     * @return The element at the specified position
    +     */
         public T get(final int index) {
             return elements.get(index);
         }
     
    +    /**
    +     * 

    filter(Predicate)

    + *

    Filters the elements of the group based on the given predicate.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>();
    +     *     List filtered = group.filter(obj -> obj instanceof String);
    +     * }
    +     * 
    +     * @param predicate The predicate to be used for filtering
    +     * @return The list of filtered elements
    +     */
         public List filter(final Predicate predicate) {
             return elements.stream().filter(predicate).toList();
         }
     
    +    /**
    +     * 

    findFirst(Predicate)

    + *

    Returns the first element of the group that matches the given predicate.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>("Hello", "World");
    +     *     Optional first = group.findFirst(str -> str.startsWith("H"));
    +     * }
    +     * 
    + * @param predicate The predicate to be used for filtering + * @return The first element that matches the predicate + */ public Optional findFirst(final Predicate predicate) { return elements.stream().filter(predicate).findFirst(); } + /** + *

    findAny(Predicate)

    + *

    Returns any element of the group that matches the given predicate.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>("Hello", "World");
    +     *     Optional any = group.findAny(str -> str.startsWith("H"));
    +     * }
    +     * 
    + * @param predicate The predicate to be used for filtering + * @return Any element that matches the predicate + */ public Optional findAny(final Predicate predicate) { return elements.stream().filter(predicate).findAny(); } + /** + *

    allMatch(Predicate)

    + *

    Checks if all elements of the group match the given predicate.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>("Hello", "World");
    +     *     boolean allMatch = group.allMatch(str -> str.length() > 3);
    +     * }
    +     * 
    + * @param predicate The predicate to be used for matching + * @return true if all elements match the predicate, false otherwise + */ public boolean allMatch(final Predicate predicate) { return elements.stream().allMatch(predicate); } + /** + *

    anyMatch(Predicate)

    + *

    Checks if any element of the group matches the given predicate.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>("Hello", "World");
    +     *     boolean anyMatch = group.anyMatch(str -> str.startsWith("H"));
    +     * }
    +     * 
    + * @param predicate The predicate to be used for matching + * @return true if any element matches the predicate, false otherwise + */ public boolean anyMatch(final Predicate predicate) { return elements.stream().anyMatch(predicate); } + /** + *

    noneMatch(Predicate)

    + *

    Checks if none of the elements of the group match the given predicate.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>("Hello", "World");
    +     *     boolean noneMatch = group.noneMatch(str -> str.length() > 10);
    +     * }
    +     * 
    + * @param predicate The predicate to be used for matching + * @return true if none of the elements match the predicate, false otherwise + */ public boolean noneMatch(Predicate predicate) { return elements.stream().noneMatch(predicate); } + /** + *

    forEach(Consumer)

    + *

    Performs the given action for each element of the group.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>("Hello", "World");
    +     *     group.forEach(System.out::println);
    +     * }
    +     * 
    + * @param action The action to be performed + * @return The ObjectGroup instance + */ public ObjectGroup forEach(final Consumer action) { elements.forEach(action); return this; } + /** + *

    stream()

    + *

    Returns a sequential {@link Stream} with this group as its source.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>("Hello", "World");
    +     *     Stream stream = group.stream();
    +     * }
    +     * 
    + * @return The stream of elements + */ public Stream stream() { return elements.stream(); } + + /** + *

    parallelStream()

    + *

    Returns a possibly parallel {@link Stream} with this group as its source.

    + *

    Example:

    + *
    +     * {@code
    +     *     final ObjectGroup group = new ObjectGroup<>("Hello", "World");
    +     *     Stream stream = group.parallelStream();
    +     * }
    +     * 
    + * @return The parallel stream of elements + */ + public Stream parallelStream() { + return elements.parallelStream(); + } } diff --git a/datastructures/src/main/java/de/haevn/utils/datastructure/Observable.java b/datastructures/src/main/java/de/haevn/utils/datastructure/Observable.java index bbcaf59..3caedb6 100644 --- a/datastructures/src/main/java/de/haevn/utils/datastructure/Observable.java +++ b/datastructures/src/main/java/de/haevn/utils/datastructure/Observable.java @@ -3,18 +3,77 @@ import java.util.ArrayList; import java.util.List; +/** + *

    Observable

    + *
    + *

    This class wraps a value and provides a method to change the corresponding value.

    + *

    If the value changes all subscribed observers will be notified.

    + * + *

    Example

    + *
    + *{@code
    + *     final Observable observable = new Observable<>("Hello World");
    + *     observable.addObserver(value -> System.out.println("Value changed to: " + value));
    + *     observable.set("Hello Universe");
    + *}
    + *
    + * @param The type of the value + * @version 1.0 + * @since 1.0 + * @author haevn + */ public class Observable { + /** + * The value of the observable. + */ private T value; + + /** + * The list of observers that are subscribed to this observable. + */ private final List> observers = new ArrayList<>(); + /** + *

    Observable(T)

    + *

    Creates a new observable with the given value.

    + *

    Example:

    + *
    +     *     {@code
    +     *     final Observable observable = new Observable<>("Hello World");
    +     *     }
    +     * 
    + * @param value the initial value of the observable + */ public Observable(final T value) { this.value = value; } + /** + *

    get()

    + *

    Returns the current value of the observable.

    + *

    Example:

    + *
    +     *     {@code
    +     *     final String value = observable.get();
    +     *     }
    +     * 
    + * @return the current value of the observable + */ public T get() { return value; } + /** + *

    set(T)

    + *

    Sets the value of the observable and notifies all observers.

    + *

    Example:

    + *
    +     *     {@code
    +     *     observable.set("Hello Universe");
    +     *     }
    +     * 
    + * @param value the new value of the observable + */ public void set(final T value) { synchronized (this) { this.value = value; @@ -22,15 +81,54 @@ public void set(final T value) { observers.forEach(observer -> observer.update(value)); } + /** + *

    addObserver(IObserver)

    + *

    Subscribes an observer to this observable.

    + *

    Example:

    + *
    +     *     {@code
    +     *     observable.addObserver(value -> System.out.println("Value changed to: " + value));
    +     *     }
    +     * 
    + * @param observer the observer to be subscribed + */ public void addObserver(final IObserver observer) { observers.add(observer); } + /** + *

    removeObserver(IObserver)

    + *

    Unsubscribes an observer from this observable.

    + *

    Example:

    + *
    +     *     {@code
    +     *     observable.removeObserver(observer);
    +     *     }
    +     * 
    + * @param observer the observer to be unsubscribed + */ public void removeObserver(final IObserver observer) { observers.remove(observer); } + /** + *

    IObserver

    + *
    + *

    This interface is used to observe changes in an {@link Observable}.

    + * @param The type of the value + */ public interface IObserver { + /** + *

    update(T)

    + *

    Is called when the value of the observable changes.

    + *

    Example:

    + *
    +         *     {@code
    +         *     observable.addObserver(value -> System.out.println("Value changed to: " + value));
    +         *     }
    +         * 
    + * @param value the new value of the observable + */ void update(T value); } } diff --git a/datastructures/src/main/java/de/haevn/utils/datastructure/ReadonlyTripple.java b/datastructures/src/main/java/de/haevn/utils/datastructure/ReadonlyTripple.java index 743e653..8475faf 100644 --- a/datastructures/src/main/java/de/haevn/utils/datastructure/ReadonlyTripple.java +++ b/datastructures/src/main/java/de/haevn/utils/datastructure/ReadonlyTripple.java @@ -1,8 +1,20 @@ package de.haevn.utils.datastructure; /** - * A simple Tripple class. + *

    ReadonlyTripple

    + *
    + *

    This class provides a read-only version of the {@link Tripple} class.

    + *

    It overrides the setter methods to ensure read-only access.

    * + *

    Example

    + *
    + * {@code
    + *     final ReadonlyTripple tripple = new ReadonlyTripple<>("Hello", 42, true);
    + *     System.out.println(tripple.getFirst());
    + *     System.out.println(tripple.getSecond());
    + *     System.out.println(tripple.getThird());
    + * }
    + * 
    * @param The type of the first element. * @param The type of the second element. * @param The type of the third element. @@ -13,8 +25,8 @@ public class ReadonlyTripple extends Tripple { /** - * Creates a new tuple. - * + *

    ReadonlyTripple(K, V, T)

    + *

    Creates a new read-only tripple with the given elements.

    * @param first The first element. * @param second The second element. * @param third The third element. @@ -24,8 +36,8 @@ public ReadonlyTripple(final K first, final V second, final T third) { } /** - * Does nothing - * + *

    setFirst(K)

    + *

    Does nothing

    * @param value ignored */ @Override @@ -34,8 +46,8 @@ public void setFirst(final K value) { } /** - * Does nothing - * + *

    setSecond(V)

    + *

    Does nothing

    * @param value ignored */ @Override @@ -44,8 +56,8 @@ public void setSecond(final V value) { } /** - * Does nothing - * + *

    setThird(T)

    + *

    Does nothing

    * @param value ignored */ @Override diff --git a/datastructures/src/main/java/de/haevn/utils/datastructure/ReadonlyTuple.java b/datastructures/src/main/java/de/haevn/utils/datastructure/ReadonlyTuple.java index e98fc60..52c491e 100644 --- a/datastructures/src/main/java/de/haevn/utils/datastructure/ReadonlyTuple.java +++ b/datastructures/src/main/java/de/haevn/utils/datastructure/ReadonlyTuple.java @@ -1,7 +1,18 @@ package de.haevn.utils.datastructure; /** - * A simple tuple class. + *

    ReadonlyTuple

    + *
    + *

    This class provides a read-only version of the {@link Tuple} class.

    + *

    It overrides the setter methods to ensure read-only access.

    + *

    Example

    + *
    + * {@code
    + *     final ReadonlyTuple tuple = new ReadonlyTuple<>("Hello", 42);
    + *     System.out.println(tuple.getFirst());
    + *     System.out.println(tuple.getSecond());
    + * }
    + * 
    * * @param The type of the first element. * @param The type of the second element. @@ -12,18 +23,19 @@ public class ReadonlyTuple extends Tuple { /** - * Creates a new tuple. + *

    ReadonlyTuple(K, V)

    + *

    Creates a new read-only tuple with the given elements.

    * - * @param key The first element. - * @param value The second element. + * @param key The key. + * @param value The value. */ public ReadonlyTuple(final K key, final V value) { super(key, value); } /** - * Does nothing. - * + *

    setFirst(K)

    + *

    Does nothing

    * @param key ignored */ @Override @@ -32,8 +44,8 @@ public void setFirst(final K key) { } /** - * Does nothing. - * + *

    setSecond(V)

    + *

    Does nothing

    * @param value ignored */ @Override diff --git a/datastructures/src/main/java/de/haevn/utils/datastructure/SearchableList.java b/datastructures/src/main/java/de/haevn/utils/datastructure/SearchableList.java index 5117d6a..0a55a85 100644 --- a/datastructures/src/main/java/de/haevn/utils/datastructure/SearchableList.java +++ b/datastructures/src/main/java/de/haevn/utils/datastructure/SearchableList.java @@ -4,57 +4,382 @@ import java.util.List; import java.util.function.Predicate; +/** + *

    SearchableList

    + *
    + *

    This class extends the {@link ArrayList} class and provides a simple way to search for elements in the list.

    + *

    It provides a simple way to search for elements in the list using a {@link Predicate} or a {@link SearchBuilder}.

    + *

    Example

    + *
    + * {@code
    + *     final SearchableList list = new SearchableList<>();
    + *     list.add("Hello");
    + *     list.add("World");
    + *     list.add("Universe");
    + *     final List result = list.search(s -> s.startsWith("W"));
    + *     System.out.println(result);
    + * }
    + * 
    + * @param The type of the elements in the list. + */ public class SearchableList extends ArrayList { + + /** + *

    search({@link Predicate})

    + *

    Searches for elements in the list that match the given predicate.

    + *

    Example:

    + *
    +     * {@code
    +     *     final List result = list.search(s -> s.startsWith("W"));
    +     * }
    +     * 
    + * @param query the predicate to search for + * @return a list of elements that match the predicate + */ public List search(final Predicate query) { return this.stream().filter(query).toList(); } + /** + *

    searchParallel({@link Predicate})

    + *

    Searches for elements in the list that match the given predicate in parallel.

    + *

    Example:

    + *
    +     * {@code
    +     *     final List result = list.searchParallel(s -> s.startsWith("W"));
    +     * }
    +     * 
    + * @param query the predicate to search for + * @return a list of elements that match the predicate + */ public List searchParallel(final Predicate query) { return this.parallelStream().filter(query).toList(); } + /** + *

    search({@link Predicate}, int)

    + *

    Searches for elements in the list that match the given predicate and limits the result to the given amount.

    + *

    Example:

    + *
    +     * {@code
    +     *     final List result = list.search(s -> s.startsWith("W"), 5);
    +     * }
    +     * 
    + * @param query the predicate to search for + * @param max the maximum amount of elements to return + * @return a list of elements that match the predicate + */ public List search(final Predicate query, int max) { return this.stream().filter(query).limit(max).toList(); } + /** + *

    searchParallel({@link Predicate}, int)

    + *

    Searches for elements in the list that match the given predicate in parallel and limits the result to the given amount.

    + *

    Example:

    + *
    +     * {@code
    +     *     final List result = list.searchParallel(s -> s.startsWith("W"), 5);
    +     * }
    +     * 
    + * @param query the predicate to search for + * @param max the maximum amount of elements to return + * @return a list of elements that match the predicate + */ public List searchParallel(final Predicate query, int max) { return this.parallelStream().filter(query).limit(max).toList(); } + /** + *

    search({@link SearchBuilder})

    + *

    Searches for elements in the list that match the given search builder.

    + * + *

    Example:

    + *
    +     * {@code
    +     *     final List result = list.search(list.searchBuilder().add(s -> s.startsWith("W")));
    +     * }
    +     * 
    + * @param searchBuilder the search builder to use for the search + * @return a list of elements that match the search builder query + */ public List search(final SearchBuilder searchBuilder){ return search(searchBuilder.build()); } + /** + *

    searchParallel({@link SearchBuilder})

    + *

    Searches for elements in the list that match the given search builder in parallel.

    + * + *

    Example:

    + *
    +     * {@code
    +     *     final List result = list.searchParallel(list.searchBuilder().add(s -> s.startsWith("W")));
    +     * }
    +     * 
    + * @param searchBuilder the search builder to use for the search + * @return a list of elements that match the search builder query + */ public List searchParallel(final SearchBuilder searchBuilder){ return searchParallel(searchBuilder.build()); } + /** + *

    search({@link SearchBuilder}, int)

    + *

    Searches for elements in the list that match the given search builder and limits the result to the given amount.

    + *

    Example:

    + *
    +     * {@code
    +     *     final List result = list.search(list.searchBuilder().add(s -> s.startsWith("W")), 5);
    +     * }
    +     * 
    + * @param searchBuilder the search builder to use for the search + * @param max the maximum amount of elements to return + * @return a list of elements that match the search builder query + */ public List search(final SearchBuilder searchBuilder, int max){ return search(searchBuilder.build(), max); } + /** + *

    searchParallel({@link SearchBuilder}, int)

    + *

    Searches for elements in the list that match the given search builder in parallel and limits the result to the given amount.

    + *

    Example:

    + *
    +     * {@code
    +     *     final List result = list.searchParallel(list.searchBuilder().add(s -> s.startsWith("W")), 5);
    +     * }
    +     * 
    + * @param searchBuilder the search builder to use for the search + * @param max the maximum amount of elements to return + * @return a list of elements that match the search builder query + */ public List searchParallel(final SearchBuilder searchBuilder, int max){ return searchParallel(searchBuilder.build(), max); } - - - public SearchBuilder searchBuilder(){ - return new SearchBuilder<>(); + /** + *

    searchBuilder()

    + *

    Creates a new {@link SearchBuilder}.

    + *

    Example:

    + *
    +     * {@code
    +     *     final SearchBuilder searchBuilder = list.searchBuilder();
    +     * }
    +     * 
    + * @return a new search builder + */ + public SearchBuilder searchBuilder(final Predicate predicate){ + return new SearchBuilder<>(predicate); } + /** + *

    SearchBuilder

    + *
    + *

    This class provides a simple way to build a search query for a {@link SearchableList}.

    + *

    Example

    + *
    +     * {@code
    +     *     final SearchBuilder searchBuilder = list.searchBuilder();
    +     *     searchBuilder.add(s -> s.startsWith("W")).add(s->s.length() > 5);
    +     *     final List result = list.search(searchBuilder);
    +     * }
    +     * 
    + * @param The type of the elements in the list. + */ public static class SearchBuilder{ + /** + * The list of predicates to build the search query. + */ + private Predicate predicate; - List> predicates = new ArrayList<>(); + /** + *

    SearchBuilder({@link Predicate})

    + *

    Creates a new search builder with given {@link Predicate}.

    + *

    Example:

    + *
    +         * {@code
    +         *     final SearchBuilder searchBuilder = list.searchBuilder(_ -> true);
    +         * }
    +         * 
    + */ + public SearchBuilder(final Predicate predicate){ + this.predicate = predicate; + } - public SearchBuilder add(Predicate predicate){ - predicates.add(predicate); - return this; + /** + *

    add({@link Predicate})

    + *

    Adds a predicate to the search query using the {@link SearchBuilder#and(Predicate)} operation.

    + *

    Example:

    + *
    +         * {@code
    +         *     searchBuilder.add(s -> s.startsWith("W")).add(s->s.length() > 5);
    +         * }
    +         * 
    + * @param predicate the predicate to add + * @return the search builder + */ + public SearchBuilder add(final Predicate predicate){ + return and(predicate); } + /** + *

    build()

    + *

    Builds the search query.

    + *

    Example:

    + *
    +         * {@code
    +         *     final List result = list.search(searchBuilder.build());
    +         * }
    +         * 
    + * @return the search query + */ public Predicate build(){ - return predicates.stream().reduce(Predicate::and).orElse(_ -> true); + return predicate; + } + + /** + *

    not()

    + *

    Negates the current predicate.

    + *

    Example:

    + *
    +         * {@code
    +         *     searchBuilder.not();
    +         * }
    +         * 
    + * @return the search builder + */ + public SearchBuilder not(){ + this.predicate = this.predicate.negate(); + return this; + } + + /** + *

    or({@link Predicate})

    + *

    Combines the current predicate with the given predicate using the OR operator.

    + *

    Example:

    + *
    +         * {@code
    +         *     SearchBuilder searchBuilder = list.searchBuilder(s -> s.length() > 5);
    +         *     searchBuilder.or(s -> s.startsWith("W"));
    +         * }
    +         * 
    + * @param predicate the {@link Predicate} to combine with + * @return the search builder + */ + public SearchBuilder or(final Predicate predicate){ + this.predicate = this.predicate.or(predicate); + return this; + } + + /** + *

    and({@link Predicate})

    + *

    Combines the current predicate with the given predicate using the AND operator.

    + *

    Example:

    + *
    +         * {@code
    +         *     SearchBuilder searchBuilder = list.searchBuilder(s -> s.length() > 5);
    +         *     searchBuilder.and(s -> s.startsWith("W"));
    +         * }
    +         * 
    + * @param predicate the {@link Predicate} to combine with + * @return the search builder + */ + public SearchBuilder and(final Predicate predicate){ + this.predicate = this.predicate.and(predicate); + return this; + } + + /** + *

    xor({@link Predicate})

    + *

    Combines the current predicate with the given predicate using the XOR operator.

    + *

    Example:

    + *
    +         * {@code
    +         *     SearchBuilder searchBuilder = list.searchBuilder(s -> s.length() > 5);
    +         *     searchBuilder.xor(s -> s.startsWith("W"));
    +         * }
    +         * 
    + * @param predicate the {@link Predicate} to combine with + * @return the search builder + */ + public SearchBuilder xor(final Predicate predicate){ + this.predicate = this.predicate.or(predicate).and(this.predicate.negate().or(predicate.negate())); + return this; + } + + /** + *

    nan({@link Predicate})

    + *

    Combines the current predicate with the given predicate using the NAND operator.

    + *

    Example:

    + *
    +         * {@code
    +         *     SearchBuilder searchBuilder = list.searchBuilder(s -> s.length() > 5);
    +         *     searchBuilder.nan(s -> s.startsWith("W"));
    +         * }
    +         * 
    + * @param predicate the {@link Predicate} to combine with + * @return the search builder + */ + public SearchBuilder nand(final Predicate predicate){ + this.predicate = this.predicate.and(predicate.negate()); + return this; + } + + /** + *

    nor({@link Predicate})

    + *

    Combines the current predicate with the given predicate using the NOR operator.

    + *

    Example:

    + *
    +         * {@code
    +         *     SearchBuilder searchBuilder = list.searchBuilder(s -> s.length() > 5);
    +         *     searchBuilder.nor(s -> s.startsWith("W"));
    +         * }
    +         * 
    + * + * @param predicate the {@link Predicate} to combine with + * @return the search builder + */ + public SearchBuilder nor(final Predicate predicate){ + this.predicate = this.predicate.or(predicate.negate()); + return this; + } + + /** + *

    xnor({@link Predicate})

    + *

    Combines the current predicate with the given predicate using the XNOR operator.

    + *

    Example:

    + *
    +         * {@code
    +         *     SearchBuilder searchBuilder = list.searchBuilder(s -> s.length() > 5);
    +         *     searchBuilder.xnor(s -> s.startsWith("W"));
    +         * }
    +         * 
    + * @param predicate the {@link Predicate} to negate + * @return the search builder + */ + public SearchBuilder xnor(final Predicate predicate){ + this.predicate = this.predicate.and(predicate).or(this.predicate.negate().and(predicate.negate())); + return this; + } + + /** + *

    implies({@link Predicate})

    + *

    Combines the current predicate with the given predicate using the IMPLIES operator.

    + *

    Example:

    + *
    +         * {@code
    +         *     SearchBuilder searchBuilder = list.searchBuilder(s -> s.length() > 5);
    +         *     searchBuilder.implies(s -> s.startsWith("W"));
    +         * }
    +         * 
    + * @param predicate the {@link Predicate} to combine with + * @return the search builder + */ + public SearchBuilder implies(final Predicate predicate){ + this.predicate = this.predicate.negate().or(predicate); + return this; } } diff --git a/datastructures/src/main/java/de/haevn/utils/datastructure/Tripple.java b/datastructures/src/main/java/de/haevn/utils/datastructure/Tripple.java index 067bce0..b27f526 100644 --- a/datastructures/src/main/java/de/haevn/utils/datastructure/Tripple.java +++ b/datastructures/src/main/java/de/haevn/utils/datastructure/Tripple.java @@ -1,7 +1,22 @@ package de.haevn.utils.datastructure; /** - * A simple Tripple class. + *

    Tripple

    + *
    + *

    This class provides a simple tripple class that can be used to store three elements.

    + *

    It extends the {@link Tuple} class.

    + *

    Example

    + *
    + * {@code
    + *     final Tripple tripple = new Tripple<>("Hello", 42, true);
    + *     System.out.println(tripple.getFirst());
    + *     System.out.println(tripple.getSecond());
    + *     System.out.println(tripple.getThird());
    + *     tripple.setFirst("World");
    + *     tripple.setSecond(24);
    + *     tripple.setThird(false);
    + * }
    + * 
    * * @param The type of the first element. * @param The type of the second element. @@ -11,12 +26,26 @@ * @since 1.0 */ public class Tripple extends Tuple{ + + /** + * An empty Tripple. + */ public static final Tripple EMPTY = new Tripple<>(null, null, null); + + /** + * The third element. + */ private T third; /** - * Creates a new tuple. - * + *

    Tripple(K, V, T)

    + *

    Creates a new tripple with the given elements.

    + *

    Example:

    + *
    +     * {@code
    +     *     final Tripple tripple = new Tripple<>("Hello", 42, true);
    +     * }
    +     * 
    * @param first The first element. * @param second The second element. * @param third The third element. @@ -27,28 +56,76 @@ public Tripple(final K first, final V second, final T third) { } /** - * Returns the third element. - * - * @return The third element. + *

    getThird()

    + *

    Returns the third element.

    + *

    Example:

    + *
    +     * {@code
    +     *     final Boolean value = tripple.getThird();
    +     * }
    +     * 
    + * @return the third element */ public T getThird() { return third; } /** - * Sets the third element. - * - * @param value The new third element. + *

    setThird(T)

    + *

    Sets the third element.

    + *

    Example:

    + *
    +     * {@code
    +     *     tripple.setThird(false);
    +     * }
    +     * 
    + * @param value the new value of the third element */ public void setThird(final T value) { this.third = value; } + /** + *

    isEmpty()

    + *

    Checks if the tripple is empty.

    + *

    Example:

    + *
    +     * {@code
    +     *   if(tripple.isEmpty()){
    +     *      System.out.println("Tripple is empty");
    +     *   }
    +     * }
    +     * 
    + * @return true iff the tripple is empty, false otherwise + */ @Override public boolean isEmpty() { return this.equals(EMPTY); } + /** + *

    equals(Object)

    + *

    Compares this tripple to another object.

    + *

    Example:

    + *
    +     * {@code
    +     *     final Tripple tripple = new Tripple<>("Hello", 42, true);
    +     *     final Tripple otherTripple = new Tripple<>("Hello", 42, true);
    +     *     if(tripple.equals(otherTripple)){
    +     *         System.out.println("Tripples are equal");
    +     *     }
    +     * }
    +     * 
    + *

    It does the following checks

    + *
      + *
    • Check if the object is the same as this tripple
    • + *
    • Check if the object is null or not an instance of Tripple
    • + *
    • Check if the first, second and third elements are equal
    • + *
    • Return true if all checks pass, false otherwise
    • + *
    + * @param obj the object to compare this tripple to + * @return true iff the objects are equal, false otherwise + */ @Override public boolean equals(final Object obj) { if (this == obj) { diff --git a/datastructures/src/main/java/de/haevn/utils/datastructure/Tuple.java b/datastructures/src/main/java/de/haevn/utils/datastructure/Tuple.java index 1767880..f68669e 100644 --- a/datastructures/src/main/java/de/haevn/utils/datastructure/Tuple.java +++ b/datastructures/src/main/java/de/haevn/utils/datastructure/Tuple.java @@ -1,7 +1,19 @@ package de.haevn.utils.datastructure; /** - * A simple tuple class. + *

    Tuple

    + *
    + *

    This class provides a simple tuple class that can be used to store two elements.

    + *

    Example

    + *
    + * {@code
    + *     final Tuple tuple = new Tuple<>("Hello", 42);
    + *     System.out.println(tuple.getFirst());
    + *     System.out.println(tuple.getSecond());
    + *     tuple.setFirst("World");
    + *     tuple.setSecond(24);
    + * }
    + * 
    * * @param The type of the first element. * @param The type of the second element. @@ -10,12 +22,23 @@ * @since 1.0 */ public class Tuple { + /** + * An empty Tuple. + */ public static final Tuple EMPTY = new Tuple<>(null, null); + /** + * The first element. + */ private K key; + + /** + * The second element. + */ private V value; /** - * Creates a new tuple. + *

    Tuple(K, V)

    + *

    Creates a new tuple with the given elements.

    * * @param key The first element. * @param value The second element. @@ -26,8 +49,8 @@ public Tuple(final K key,final V value) { } /** - * Returns the first element. - * + *

    getFirst()

    + *

    Returns the first element.

    * @return The first element. */ public K getFirst() { @@ -35,8 +58,8 @@ public K getFirst() { } /** - * Sets the first element. - * + *

    setFirst(K)

    + *

    Sets the first element.

    * @param key The new first element. */ public void setFirst(final K key) { @@ -44,8 +67,8 @@ public void setFirst(final K key) { } /** - * Returns the second element. - * + *

    getSecond()

    + *

    Returns the second element.

    * @return The second element. */ public V getSecond() { @@ -53,18 +76,36 @@ public V getSecond() { } /** - * Sets the second element. - * + *

    setSecond(V)

    + *

    Sets the second element.

    * @param value The new second element. */ public void setSecond(final V value) { this.value = value; } + /** + *

    isEmpty()

    + *

    Checks if the tuple is empty.

    + * @return true iff the tuple is empty, false otherwise + */ public boolean isEmpty() { return this.equals(EMPTY); } + /** + *

    equals(Object)

    + *

    Compares this tuple to another object.

    +

    It does the following checks

    + *
      + *
    • Check if the object is the same as this tripple
    • + *
    • Check if the object is null or not an instance of Tripple
    • + *
    • Check if the first, second and third elements are equal
    • + *
    • Return true if all checks pass, false otherwise
    • + *
    + * @param obj The object to compare to. + * @return true iff the objects are equal, false otherwise + */ @Override public boolean equals(final Object obj) { if (this == obj) { From f53a7413269c0a89b310ce226f354939ecfb1148 Mon Sep 17 00:00:00 2001 From: Nils M Date: Sun, 30 Jun 2024 13:39:58 +0200 Subject: [PATCH 10/17] Rewrote documentation and SerializationUtils --- .../java/de/haevn/utils/debug/DebugTool.java | 16 + .../de/haevn/utils/debug/MethodTools.java | 133 ++++- .../de/haevn/utils/debug/ThreadTools.java | 91 ++- .../utils/debug/TimeMeasurementTools.java | 89 ++- .../exceptions/ApplicationException.java | 56 +- .../de/haevn/utils/exceptions/ErrorCode.java | 85 ++- .../utils/exceptions/ExceptionUtils.java | 22 +- .../utils/exceptions/FileMergeException.java | 36 +- .../exceptions/InvalidCastException.java | 26 +- .../exceptions/MethodNotAllowedError.java | 25 +- .../utils/exceptions/NetworkException.java | 67 ++- .../NotYetImplementedException.java | 40 +- .../exceptions/ValidationFailedException.java | 9 +- .../java/de/haevn/utils/io/FileReader.java | 87 ++- .../java/de/haevn/utils/io/FileUtils.java | 154 ++++- .../java/de/haevn/utils/io/FileWatcher.java | 65 ++- .../java/de/haevn/utils/io/FileWriter.java | 95 ++- .../de/haevn/utils/io/PropertyHandler.java | 223 ++++++- io/src/main/java/de/haevn/utils/io/USB.java | 3 +- .../main/java/de/haevn/utils/io/ZipUtils.java | 35 +- .../utils/io/merge/AbstractFileMerging.java | 66 ++- .../de/haevn/utils/io/merge/IFileMerging.java | 41 +- .../de/haevn/utils/io/merge/PdfMerge.java | 26 +- .../utils/io/merge/SimpleFileMerging.java | 17 +- .../java/de/haevn/utils/logging/Level.java | 5 +- .../java/de/haevn/utils/logging/LogEntry.java | 69 ++- .../java/de/haevn/utils/logging/Logger.java | 242 ++++++-- .../de/haevn/utils/logging/LoggerConfig.java | 98 +++- .../de/haevn/utils/logging/LoggerHandler.java | 28 + .../utils/logging/SanitizedLogEntry.java | 24 + .../webhook/discord/DiscordWebhook.java | 4 +- pom.xml | 1 - .../main/java/de/haevn/utils/system/CPU.java | 42 +- .../main/java/de/haevn/utils/system/GPU.java | 13 +- .../main/java/de/haevn/utils/system/Java.java | 165 +++++- .../java/de/haevn/utils/system/Memory.java | 283 ++++++++- .../main/java/de/haevn/utils/system/OS.java | 82 ++- .../main/java/de/haevn/utils/system/User.java | 36 +- tools/pom.xml | 20 - .../main/java/de/haevn/utils/DocuHelper.java | 54 -- .../main/java/de/haevn/utils/ArrayUtils.java | 11 +- .../main/java/de/haevn/utils/ColorUtils.java | 225 +++++--- .../java/de/haevn/utils/ListOperation.java | 15 +- .../main/java/de/haevn/utils/NumberUtils.java | 537 ++++++++++++++--- .../main/java/de/haevn/utils/RecordUtils.java | 19 +- .../de/haevn/utils/SerializationUtils.java | 184 +++--- .../de/haevn/utils/SerializationUtilsV2.java | 543 ++++++++++++++++++ .../main/java/de/haevn/utils/StringUtils.java | 76 ++- .../src/main/java/de/haevn/utils/System.java | 30 - .../main/java/de/haevn/utils/TimeUtils.java | 43 +- 50 files changed, 3717 insertions(+), 639 deletions(-) delete mode 100644 tools/pom.xml delete mode 100644 tools/src/main/java/de/haevn/utils/DocuHelper.java create mode 100644 utils/src/main/java/de/haevn/utils/SerializationUtilsV2.java delete mode 100644 utils/src/main/java/de/haevn/utils/System.java diff --git a/debug/src/main/java/de/haevn/utils/debug/DebugTool.java b/debug/src/main/java/de/haevn/utils/debug/DebugTool.java index a847225..f49583c 100644 --- a/debug/src/main/java/de/haevn/utils/debug/DebugTool.java +++ b/debug/src/main/java/de/haevn/utils/debug/DebugTool.java @@ -3,6 +3,22 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +/** + *

    DebugTool

    + *
    + *

    This annotation can be used to mark classes that provide debugging tools.

    + *

    It provides information about the name, description and authors of the tool.

    + *

    Example

    + *
    + * {@code
    + *     @DebugTool(name = "MyTool", description = "This is a simple tool", authors = {"haevn"})
    + *     public class MyTool {...}
    + * }
    + * 
    + * @version 1.0 + * @since 1.0 + * @author haevn + */ @Retention(RetentionPolicy.RUNTIME) public @interface DebugTool { String name(); diff --git a/debug/src/main/java/de/haevn/utils/debug/MethodTools.java b/debug/src/main/java/de/haevn/utils/debug/MethodTools.java index eb721f5..a66fe04 100644 --- a/debug/src/main/java/de/haevn/utils/debug/MethodTools.java +++ b/debug/src/main/java/de/haevn/utils/debug/MethodTools.java @@ -4,7 +4,22 @@ import java.util.Optional; /** - * This class provides some useful methods for lists. + *

    MethodTools

    + *
    + *

    This class provides some useful methods for methods.

    + *

    It can be used to get information about the method that called this method.

    + *

    Example

    + *
    + * {@code
    + *     final Optional method = MethodTools.getMethod();
    + *     if (method.isPresent()) {
    + *        System.out.println(method.get().getClassName());
    + *        System.out.println(method.get().getMethodName());
    + *        System.out.println(method.get().getLineNumber());
    + *        System.out.println(method.get().getFileName());
    + *     }
    + * }
    + * 
    * * @author haevn * @version 1.0 @@ -14,13 +29,37 @@ public class MethodTools { private final MethodDetails methodDetails; + /** + * Creates a new MethodTools object with the given frame. + * @param frame The frame of the method. + */ private MethodTools(final StackWalker.StackFrame frame) { this.methodDetails = new MethodDetails(frame.getClassName(), frame.getMethodName(), frame.getLineNumber(), frame.getFileName()); } /** - * Returns the method that called this method. - * + *

    getMethod()

    + *

    Returns the last called method.

    + *

    The stackframe contains this call and the original call, therefore it skips 2 methods.

    + *
    +     *     +---------------------+
    +     *     | getMethod()         | <-- Top of the stackframe (skip = 0)
    +     *     +---------------------+
    +     *     | getMethod(int skip) | <-- Internal call (skip = 1)
    +     *     +---------------------+
    +     *     | methodOne()         | <-- Second call and targeted method  (skip = 2)
    +     *     +---------------------+
    +     *     | methodTwo()         | <-- First method call (skip = 3)
    +     *     +---------------------+
    +     *     | main()              | <-- Bottom of the stackframe (skip = 4)
    +     *     +---------------------+
    +     * 
    + *

    Example:

    + *
    +     * {@code
    +     *     final Optional method = MethodTools.getMethod();
    +     * }
    +     * 
    * @return The method that called this method. */ public static Optional getMethod() { @@ -28,7 +67,24 @@ public static Optional getMethod() { } /** - * Returns the method that is skip methods above this method. + *

    getMethod(int skip)

    + *

    Returns the method that is skip methods above this method.

    + *
    +     *     +---------------------+
    +     *     | getMethod(int skip) | <-- getMethod(2) (skip = 0)
    +     *     +---------------------+
    +     *     | methodOne()         | <-- previous call (skip = 1)
    +     *     +---------------------+
    +     *     | main()              | <-- main call (skip = 2)
    +     *     +---------------------+
    +     * 
    + * + *

    Example:

    + *
    +     * {@code
    +     *     final Optional method = MethodTools.getMethod(2);
    +     * }
    +     * 
    * * @param skip The amount of methods to skip. * @return The method that is skip methods above this method. @@ -42,8 +98,17 @@ public static Optional getMethod(final int skip) { } /** - * Returns the name of the file. - * + *

    getFileName()

    + *

    Returns the filename where the method is located.

    + *

    Example:

    + *
    +     * {@code
    +     *     final Optional method = MethodTools.getMethod();
    +     *     if (method.isPresent()) {
    +     *         System.out.println(method.get().getFileName());
    +     *     }
    +     * }
    +     * 
    * @return The name of the file. */ public String getFileName() { @@ -51,7 +116,17 @@ public String getFileName() { } /** - * Returns the name of the class. + *

    getClassName()

    + *

    Returns the name of the class.

    + *

    Example:

    + *
    +     * {@code
    +     *     final Optional method = MethodTools.getMethod();
    +     *     if (method.isPresent()) {
    +     *         System.out.println(method.get().getClassName());
    +     *     }
    +     * }
    +     * 
    * * @return The name of the class. */ @@ -60,7 +135,17 @@ public String getClassName() { } /** - * Returns the line number of the method. + *

    getLineNumber()

    + *

    Returns the line number of the method.

    + *

    Example:

    + *
    +     * {@code
    +     *     final Optional method = MethodTools.getMethod();
    +     *     if (method.isPresent()) {
    +     *         System.out.println(method.get().getLineNumber());
    +     *     }
    +     * }
    +     * 
    * * @return The line number of the method. */ @@ -69,7 +154,17 @@ public int getLineNumber() { } /** - * Returns the name of the method. + *

    getMethodName()

    + *

    Returns the name of the method.

    + *

    Example:

    + *
    +     * {@code
    +     *     final Optional method = MethodTools.getMethod();
    +     *     if (method.isPresent()) {
    +     *         System.out.println(method.get().getName());
    +     *     }
    +     * }
    +     * 
    * * @return The name of the method. */ @@ -77,11 +172,31 @@ public String getMethodName() { return methodDetails.methodName; } + /** + *

    toString()

    + *

    Returns a string representation of the method.

    + *

    Example:

    + *
    +     * {@code
    +     *     final Optional method = MethodTools.getMethod();
    +     *     if (method.isPresent()) {
    +     *         System.out.println(method.get());
    +     *     }
    +     * }
    +     * 
    + * + * @return A string representation of the method. + */ @Override public String toString() { return "\"" + methodDetails.className + "#" + methodDetails.methodName + ":" + methodDetails.lineNumber + "\" in \"" + methodDetails.fileName + "\""; } + /** + *

    MethodDetails

    + *

    This record represents the details of a method.

    + *

    It contains the class name, the method name, the line number and the file name.

    + */ private record MethodDetails(String className, String methodName, int lineNumber, String fileName) { } } diff --git a/debug/src/main/java/de/haevn/utils/debug/ThreadTools.java b/debug/src/main/java/de/haevn/utils/debug/ThreadTools.java index 6971094..f7a8123 100644 --- a/debug/src/main/java/de/haevn/utils/debug/ThreadTools.java +++ b/debug/src/main/java/de/haevn/utils/debug/ThreadTools.java @@ -6,8 +6,20 @@ import java.util.function.Predicate; /** - * This class provides some useful methods for threads. - * + *

    ThreadTools

    + *
    + *

    This class provides some useful methods for threads.

    + *

    It can be used to get information about the threads that are currently running.

    + *

    Example

    + *
    + * {@code
    + *     final List threads = ThreadTools.getThreads();
    + *     final List runningThreads = ThreadTools.getRunningThreads();
    + *     final List waitingThreads = ThreadTools.getThreads(Thread.State.WAITING);
    + *     final List runningThreadNames = ThreadTools.getRunningThreadNames();
    + * }
    + * 
    + * More features will be added in the future. * @author haevn * @version 1.0 * @since 1.0 @@ -16,27 +28,98 @@ public class ThreadTools { private ThreadTools() {} + /** + *

    getThreads()

    + *

    Returns a list of all threads that are currently running.

    + *

    Example:

    + *
    +     * {@code
    +     *     final List threads = ThreadTools.getThreads();
    +     * }
    +     * 
    + * @return A list of all threads that are currently running. + */ public static List getThreads() { final var threads = Thread.getAllStackTraces().keySet(); return new ArrayList<>(threads); } + /** + *

    getThreadsBy({@link Predicate Predicate})

    + *

    Returns a list of all threads that match the given predicate.

    + *

    Example:

    + *
    +     * {@code
    +     *     final List threads = ThreadTools.getThreadsBy(thread -> thread.getName().startsWith("Thread"));
    +     * }
    +     * 
    + * @param predicate The predicate to filter the threads. + * @return A list of all threads that match the given predicate. + */ public static List getThreadsBy(final Predicate predicate) { return getThreads().stream().filter(predicate).toList(); } + /** + *

    getRunningThreads()

    + *

    Returns a list of all threads that are currently running.

    + *

    Example:

    + *
    +     * {@code
    +     *     final List runningThreads = ThreadTools.getRunningThreads();
    +     * }
    +     * 
    + * @return A list of all threads that are currently running. + */ public static List getRunningThreads() { return getThreadsBy(Thread::isAlive); } + /** + *

    getThreads({@link Thread.State})

    + *

    Returns a list of all threads that are in the given state.

    + *

    Example:

    + *
    +     * {@code
    +     *     final List waitingThreads = ThreadTools.getThreads(Thread.State.WAITING);
    +     * }
    +     * 
    + * @param state The state of the threads. + * @return A list of all threads that are in the given state. + */ public static List getThreads(final Thread.State state){ return getThreadsBy(thread -> thread.getState() == state); } + /** + *

    getRunningThreadNames()

    + *

    Returns a list of the names of all threads that are currently running.

    + *

    Example:

    + *
    +     * {@code
    +     *     final List runningThreadNames = ThreadTools.getRunningThreadNames();
    +     * }
    +     * 
    + * @return A list of the names of all threads that are currently running. + */ public static List getRunningThreadNames() { return getThreads().stream().map(Thread::getName).toList(); } + /** + *

    waitFor({@link AtomicBoolean})

    + *

    Waits until the given condition is true.

    + *

    A new virtual thread is started that waits until the condition is true.

    + *

    It wraps the {@link InterruptedException} to avoid unnecessary try-catch blocks.

    + *

    Example:

    + *
    +     * {@code
    +     *     final AtomicBoolean condition = new AtomicBoolean(false);
    +     *     ThreadTools.waitFor(condition);
    +     * }
    +     * 
    + * @param condition The condition to wait for. + */ public static void waitFor(final AtomicBoolean condition) { try { Thread.ofVirtual().start(() -> { @@ -44,8 +127,6 @@ public static void waitFor(final AtomicBoolean condition) { Thread.onSpinWait(); } }).join(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } + } catch (InterruptedException ignored) {} } } diff --git a/debug/src/main/java/de/haevn/utils/debug/TimeMeasurementTools.java b/debug/src/main/java/de/haevn/utils/debug/TimeMeasurementTools.java index e732dbf..66898bb 100644 --- a/debug/src/main/java/de/haevn/utils/debug/TimeMeasurementTools.java +++ b/debug/src/main/java/de/haevn/utils/debug/TimeMeasurementTools.java @@ -8,7 +8,9 @@ import java.util.concurrent.Callable; /** - * This class can be used to measure the time of a code. + *

    TimeMeasurementTools

    + *
    + *

    This class can be used to measure the time of a code.

    *
    * Example 1 *
    @@ -41,25 +43,42 @@ public class TimeMeasurementTools implements AutoCloseable {
         private static final List RUN_TIME_STACK = new ArrayList<>();
         private final PrintStream out;
     
    +
         /**
    -     * Create a new TimeMeasurement with {@link System#out} as default output stream.
    +     * 

    TimeMeasurementTools()

    + *

    Create a new TimeMeasurement with the default output stream ({@link System#out}).

    */ public TimeMeasurementTools() { this(System.out); } /** - * Create a new TimeMeasurement with the given output stream. - * - * @param out The output stream where the result should be printed. + *

    TimeMeasurementTools({@link PrintStream})

    + *

    Create a new TimeMeasurement with the given output stream.

    + * @param out The {@link PrintStream} to print the results. */ public TimeMeasurementTools(final PrintStream out) { this.out = out; } /** - * Measure the time of the given code. - * + *

    TimeMeasurementTools({@link Runnable}, {@link Class}, {@link String}, {@link String}})

    + *

    Create a new TimeMeasurement with the given code, class, method name and description.

    + *

    It will measure the time of the provided {@link Runnable}.

    + *

    Example 1:

    + *
    +     * {@code
    +     * new TimeMeasurement(() -> {
    +     *     // Code to measure
    +     *     }, this.getClass(), "methodName", "description");
    +     * }
    +     * 
    + *

    Example 2:

    + *
    +     *     {@code
    +     *     new TimeMeasurement(this::methodToMeasure, this.getClass(), "methodName", "description");
    +     *     }
    +     * 
    * @param code The code to measure. * @param cl The class of the code. * @param methodName The method name of the code. @@ -73,7 +92,23 @@ public void time(final Runnable code, final Class cl, final String methodName } /** - * Measure the time of the given code. + *

    TimeMeasurementTools({@link Callable}, {@link Class}, {@link String}, {@link String})

    + *

    Create a new TimeMeasurement with the given code, class, method name and description.

    + *

    It will measure the time of the provided {@link Callable} and returns the result of the code.

    + *

    Example 1:

    + *
    +     * {@code
    +     *     var result = new TimeMeasurement(() -> {
    +     *     // Code to measure
    +     *     }, this.getClass(), "methodName", "description");
    +     * }
    +     * 
    + *

    Example 2:

    + *
    +     * {@code
    +     *     var result = new TimeMeasurement(this::methodToMeasure, this.getClass(), "methodName", "description");
    +     * }
    +     * 
    * * @param code The code to measure. * @param cl The class of the code. @@ -102,7 +137,8 @@ public T time(final Callable code, final Class cl, final String method } /** - * Stop the time measurement and print the result. + *

    stop()

    + *

    Stop the time measurement and print the results to the specified {@link java.io.PrintWriter} .

    *
      *
    • result[0]: Class.Method
    • *
    • result[1]: Execution time
    • @@ -127,6 +163,14 @@ public List stop() { return result; } + /** + *

      close()

      + *

      This method invokes {@link TimeMeasurementTools#stop()}

      + * {@see TimeMeasurementTools#stop()} + * {@see AutoCloseable#close()} + * + * @throws Exception If an error occurs. + */ @Override public void close() throws Exception { stop(); @@ -139,7 +183,17 @@ public void close() throws Exception { /** - * Measure the time of the given code. + *

      measure({@link Runnable})

      + *

      This method can be used to measure the time of a code.

      + *

      This is a static version of the {@link TimeMeasurementTools#time(Runnable, Class, String, String)} method. + * and does not require an instance of the {@link TimeMeasurementTools} class.

      + *

      It will return the execution time in milliseconds.

      + *

      Example:

      + *
      +     * {@code
      +     *     long time = TimeMeasurementTools.measure(() -> {...});
      +     * }
      +     * 
      * * @param code The code to measure. * @return The execution time in milliseconds. @@ -151,7 +205,20 @@ public static long measure(final Runnable code) { } /** - * Measure the time of the given code. + *

      measure({@link Callable})

      + *

      This method can be used to measure the time of a code.

      + *

      This is a static version of the {@link TimeMeasurementTools#time(Callable, Class, String, String)} method. + * and does not require an instance of the {@link TimeMeasurementTools} class.

      + *

      It will return a {@link de.haevn.utils.datastructure.Tuple} containing the result and the + * execution time in milliseconds.

      + *

      Example:

      + *
      +     * {@code
      +     *     var result = TimeMeasurementTools.measure(() -> {...});
      +     *     System.out.println("Result: " + result.getFirst());
      +     *     System.out.println("Execution time: " + result.getSecond());
      +     * }
      +     * 
      * * @param code The code to measure. * @param The type of the result. diff --git a/exceptions/src/main/java/de/haevn/utils/exceptions/ApplicationException.java b/exceptions/src/main/java/de/haevn/utils/exceptions/ApplicationException.java index 2c9ac34..649d35f 100644 --- a/exceptions/src/main/java/de/haevn/utils/exceptions/ApplicationException.java +++ b/exceptions/src/main/java/de/haevn/utils/exceptions/ApplicationException.java @@ -1,34 +1,82 @@ package de.haevn.utils.exceptions; /** - * A simple exception class for application exceptions. + *

      ApplicationException

      + *
      + *

      This class provides a simple exception class that can be used to throw exceptions in the application.

      + *

      It provides an error code that can be used to identify the error.

      + *

      Example

      + *
      + * {@code
      + *     try {
      + *         throw new ApplicationException("An error occurred");
      + *     } catch (ApplicationException e) {
      + *         System.out.println("Error: " + e.getMessage());
      + *     }
      + * }
      + * 
      + * + * @author haevn * @version 1.0 - * @since 1.0 * @see RuntimeException - * @author haevn + * @since 1.0 */ public class ApplicationException extends RuntimeException { private final long errorCode; + + /** + *

      ApplicationException({@link Throwable})

      + *

      Creates a new ApplicationException based on another {@link Throwable}.

      + * + * @param other + */ public ApplicationException(final Throwable other) { this(other.getMessage(), other); } + /** + *

      ApplicationException({@link String})

      + *

      Creates a new ApplicationException with the given message.

      + * + * @param message The message of the exception. + */ public ApplicationException(final String message) { super(message); errorCode = ErrorCode.UNKNOWN; } + /** + *

      ApplicationException({@link String}, {@link Throwable})

      + *

      Creates a new ApplicationException based on another {@link Throwable} with the given message.

      + * + * @param message The message of the exception. + * @param other The other {@link Throwable}. + */ public ApplicationException(final String message, final Throwable other) { this(message, other, ErrorCode.UNKNOWN); } + /** + *

      ApplicationException({@link String}, {@link Throwable}, long)

      + *

      Creates a new ApplicationException based on another {@link Throwable} with the given message and error code.

      + * + * @param message The message of the exception. + * @param other The other {@link Throwable}. + * @param errorCode The error code of the exception. + */ public ApplicationException(final String message, final Throwable other, final long errorCode) { super(message, other); this.errorCode = errorCode; } + /** + *

      getErrorCode

      + *

      Returns the error code of the exception.

      + * + * @return The error code of the exception. + */ public long getErrorCode() { return errorCode; } - + } diff --git a/exceptions/src/main/java/de/haevn/utils/exceptions/ErrorCode.java b/exceptions/src/main/java/de/haevn/utils/exceptions/ErrorCode.java index b61ae81..ef2be3a 100644 --- a/exceptions/src/main/java/de/haevn/utils/exceptions/ErrorCode.java +++ b/exceptions/src/main/java/de/haevn/utils/exceptions/ErrorCode.java @@ -1,9 +1,12 @@ package de.haevn.utils.exceptions; /** - * This class contains codes and method for every used error code + *

      ErrorCode

      *
      - * Structure + *

      This class provides an error code system that can be used to identify errors in the application.

      + *

      It provides a way to create error codes based on the project, module and error.

      + *

      It also provides a way to check if an error code is an unknown error or an error from a specific project or module.

      + *

      Structure

      * * * @@ -47,8 +50,11 @@ private ErrorCode() { /** - * Contains all projects. - * Add new projects here, not that the value 0 to 9 are reserved for the framework. + *

      Project

      + *
      + *

      This enum provides the projects that can be used to create error codes.

      + *

      It provides a way to identify the project of an error code.

      + *

      Adding new projects requires a new entry in this enum therefore a new issue should be created.

      * * @version 1.1 * @since 1.1 @@ -73,48 +79,76 @@ public int getValue() { } } + /** + *

      isProject(long, {@link Project})

      + *

      Check if the given error code is from the given project.

      + *

      Example:

      + *
      +     * {@code
      +     *     if(ErrorCode.isProject(errorCode, Project.UTILS)){...}
      +     * }
      +     * 
      + * + * @param errorCode The error code + * @param project The project to check + * @return True iff the given error code is from the given project + */ public static boolean isProject(final long errorCode, final Project project) { return getProject(errorCode) == project.value; } - + /** + * Prject mask + */ private static final long PROJECT = 0xFF00_0000L; + + /** + * Module mask + */ private static final long MODULE = 0x00FF_0000L; + + /** + * Actual Error mask + */ private static final long ERROR = 0x0000_FFFFL; /** - * Check if the given error code is an unknown error. + *

      isUnknownError(long)

      + *

      Check if the given error code is an unknown error.

      * * @param errorCode The error code - * @return True if the given error code is an unknown error + * @return True iff the given error code is an unknown error */ public static boolean isUnknownError(final long errorCode) { return getProject(errorCode) == Project.UNKNOWN.value; } /** - * Check if the given error code is a JavaUtils error. + *

      isJavaUtilsModuleError(long)

      + *

      Check if the given error code is associated with the JavaUtils module.

      * * @param errorCode The error code - * @return True if the given error code is a JavaUtils error + * @return True iff the given error code is a JavaUtils error */ public static boolean isJavaUtilsModuleError(final long errorCode) { return getProject(errorCode) == Project.UTILS.value; } /** - * Check if the given error code is a JavaFXUtils error. + *

      isJavaFXUtilsError(long)

      + *

      Check if the given error code is associated with the JavaFXUtils module.

      * * @param errorCode The error code - * @return True if the given error code is a JavaFXUtils error + * @return True iff the given error code is a JavaFXUtils error */ public static boolean isJavaFXUtilsError(final long errorCode) { return getProject(errorCode) == Project.JFX_UTILS.value; } /** - * Get the project from the given error code. + *

      getProject(long)

      + *

      Get the project from the given error code.

      * * @param errorCode The error code * @return The project @@ -124,7 +158,8 @@ public static int getProject(final long errorCode) { } /** - * Get the module from the given error code. + *

      getModule(long)

      + *

      Get the module from the given error code.

      * * @param errorCode The error code * @return The module @@ -134,7 +169,8 @@ public static int getModule(final long errorCode) { } /** - * Get the error code from the given error code. + *

      getError(long)

      + *

      Get the error from the given error code.

      * * @param errorCode The error code * @return The error code @@ -144,7 +180,8 @@ public static int getError(final long errorCode) { } /** - * Create an error code from the given parts. + *

      getErrorCode(long, long, long)

      + *

      Construct an error code from the given project, module and error.

      * * @param project The project * @param module The module @@ -156,7 +193,19 @@ public static long getErrorCode(final long project, final long module, final lon } /** - * Extract the parts of an error code. + *

      extract(long)

      + *

      Extract the parts of the given error code.

      + *

      It returns a record with the project, module and error.

      + *

      Example:

      + *
      +     * {@code
      +     *     final long errorCode = ErrorCode.getErrorCode(ErrorCode.Projects.UTILS, ErrorCode.Modules.IO, ErrorCode.IO.FILE_NOT_FOUND);
      +     *     final ErrorTypes error = ErrorCode.extract(errorCode);
      +     *     System.out.println("Project: " + error.project());
      +     *     System.out.println("Module: " + error.module());
      +     *     System.out.println("Error: " + error.errorCode());
      +     * }
      +     * 
      * * @param errorCode The error code * @return The parts of the error code @@ -167,7 +216,9 @@ public static ErrorTypes extract(final long errorCode) { /** - * A record for the parts of an error code. + *

      ErrorTypes

      + *
      + *

      This record represents the parts of an error code.

      * * @param project The project * @param module The module diff --git a/exceptions/src/main/java/de/haevn/utils/exceptions/ExceptionUtils.java b/exceptions/src/main/java/de/haevn/utils/exceptions/ExceptionUtils.java index efe7e57..29ed75e 100644 --- a/exceptions/src/main/java/de/haevn/utils/exceptions/ExceptionUtils.java +++ b/exceptions/src/main/java/de/haevn/utils/exceptions/ExceptionUtils.java @@ -4,7 +4,11 @@ import java.io.StringWriter; /** - * A simple ExceptionUtils class. + *

      ExceptionUtils

      + *
      + *

      This class provides utility methods for exceptions.

      + * + *

      New features will be added in the future.

      * * @author Haevn * @version 1.0 @@ -15,13 +19,25 @@ private ExceptionUtils() { } /** - * Returns the stack trace of the given {@link Throwable} as a string. + *

      getStackTrace({@link Throwable})

      + *

      Returns the stack trace of the given {@link Throwable} as a string.

      + *

      Example:

      + *
      +     * {@code
      +     *     try {
      +     *         throw new ApplicationException("An error occurred");
      +     *     } catch (ApplicationException e) {
      +     *         System.out.println("Error: " + e.getMessage());
      +     *         System.out.println(ExceptionUtils.getStackTrace(e));
      +     *     }
      +     * }
      +     * 
      * * @param throwable The throwable. * @return The stack trace of the given {@link Throwable} as a string. */ public static String getStackTrace(final Throwable throwable) { - if(null == throwable){ + if (null == throwable) { return ""; } final StringWriter sw = new StringWriter(); diff --git a/exceptions/src/main/java/de/haevn/utils/exceptions/FileMergeException.java b/exceptions/src/main/java/de/haevn/utils/exceptions/FileMergeException.java index c5071d1..ea8dc15 100644 --- a/exceptions/src/main/java/de/haevn/utils/exceptions/FileMergeException.java +++ b/exceptions/src/main/java/de/haevn/utils/exceptions/FileMergeException.java @@ -3,16 +3,46 @@ import java.io.File; import java.util.List; -public class FileMergeException extends Exception{ -public FileMergeException(final File output, List files) { +/** + *

      FileMergeException

      + *
      + *

      This exception is thrown when an error occurs while merging files.

      + *

      It provides information about the output file and the files that should be merged.

      + */ +public class FileMergeException extends Exception { + + /** + *

      FileMergeException({@link File}, {@link List})

      + *

      Creates a new FileMergeException with the given output file and files.

      + * + * @param output The output file. + * @param files The files that should be merged. + */ + public FileMergeException(final File output, List files) { super(buildMessage(output, files)); } + /** + *

      FileMergeException({@link File}, {@link List}, {@link Throwable})

      + *

      Creates a new FileMergeException with the given output file, files and cause.

      + * + * @param output The output file. + * @param files The files that should be merged. + * @param cause The cause of the exception. + */ public FileMergeException(final File output, List files, Throwable cause) { super(buildMessage(output, files), cause); } - private static String buildMessage(final File output, final List files){ + /** + *

      buildMessage({@link File}, {@link List})

      + *

      This is an internal method to build the message for the exception.

      + * + * @param output The output file. + * @param files The files that should be merged. + * @return The message for the exception. + */ + private static String buildMessage(final File output, final List files) { return String.format("Error while creating file: %s based on %s", output.getName(), files.stream().map(File::getName).reduce((a, b) -> a + ", " + b).orElse("")); } } diff --git a/exceptions/src/main/java/de/haevn/utils/exceptions/InvalidCastException.java b/exceptions/src/main/java/de/haevn/utils/exceptions/InvalidCastException.java index 0f905d3..10772ad 100644 --- a/exceptions/src/main/java/de/haevn/utils/exceptions/InvalidCastException.java +++ b/exceptions/src/main/java/de/haevn/utils/exceptions/InvalidCastException.java @@ -1,20 +1,38 @@ package de.haevn.utils.exceptions; /** - * A simple exception class for invalid casts. + *

      InvalidCastException

      + *
      + *

      This exception is thrown when an invalid cast is performed.

      + * + * @author haevn * @version 1.0 - * @since 1.0 * @see ApplicationException * @see RuntimeException - * @author haevn + * @since 1.0 */ public class InvalidCastException extends ApplicationException { + + /** + *

      InvalidCastException({@link Class}, {@link Class})

      + *

      Creates a new InvalidCastException with the provided and required class.

      + * + * @param provided The provided class. + * @param required The required class. + */ public InvalidCastException(final Class provided, final Class required) { this(provided, required, "Invalid cast"); } + /** + *

      InvalidCastException({@link Class}, {@link Class}, {@link String})

      + *

      Creates a new InvalidCastException with the provided and required class and a message.

      + * + * @param provided The provided class. + * @param required The required class. + * @param message The message. + */ public InvalidCastException(final Class provided, final Class required, final String message) { - super("Provided class: " + provided.getCanonicalName() + "\nProvided class: " + required.getCanonicalName() + "\n" + message); diff --git a/exceptions/src/main/java/de/haevn/utils/exceptions/MethodNotAllowedError.java b/exceptions/src/main/java/de/haevn/utils/exceptions/MethodNotAllowedError.java index 6309b76..0844e55 100644 --- a/exceptions/src/main/java/de/haevn/utils/exceptions/MethodNotAllowedError.java +++ b/exceptions/src/main/java/de/haevn/utils/exceptions/MethodNotAllowedError.java @@ -3,7 +3,10 @@ import de.haevn.utils.debug.MethodTools; /** - * Indicates that the method is not yet implemented. + *

      MethodNotAllowedError

      + *
      + *

      This error is thrown when a method is not allowed.

      + *

      It provides a message that can be used to identify the error.

      * * @author haevn * @version 1.0 @@ -12,6 +15,13 @@ public class MethodNotAllowedError extends Error { private final String message; + /** + *

      MethodNotAllowedError()

      + *

      Creates a new MethodNotAllowedError with a default message.

      + *

      The default message is "Method is not yet allowed."

      + *

      The method that caused the error is determined by the {@link MethodTools} class.

      + *

      If the method cannot be determined, the message is "Method is not yet allowed."

      + */ public MethodNotAllowedError() { final var method = MethodTools.getMethod(2); if (method.isPresent()) { @@ -21,11 +31,22 @@ public MethodNotAllowedError() { } } + /** + *

      MethodNotAllowedError({@link String})

      + *

      Creates a new MethodNotAllowedError with the given message.

      + * + * @param message The message of the error. + */ public MethodNotAllowedError(final String message) { this.message = message; } - + /** + *

      getMessage()

      + *

      Returns the message of the error.

      + * + * @return The message of the error. + */ @Override public String getMessage() { return message; diff --git a/exceptions/src/main/java/de/haevn/utils/exceptions/NetworkException.java b/exceptions/src/main/java/de/haevn/utils/exceptions/NetworkException.java index 4d0d7ce..d6add7c 100644 --- a/exceptions/src/main/java/de/haevn/utils/exceptions/NetworkException.java +++ b/exceptions/src/main/java/de/haevn/utils/exceptions/NetworkException.java @@ -3,19 +3,38 @@ import java.net.http.HttpResponse; /** - * A simple exception class for network exceptions. + *

      NetworkException

      + *
      + *

      This exception is thrown when a network error occurs.

      + *

      It provides information about the status code, the content and the URL that caused the error.

      * + * @author haevn * @version 1.0 - * @since 1.0 * @see ApplicationException * @see RuntimeException - * @author haevn + * @since 1.0 */ public class NetworkException extends ApplicationException { private final String url; private final int statusCode; private final String content; + /** + *

      NetworkException({@link Throwable})

      + *

      Creates a new NetworkException based on another {@link Throwable}.

      + *

      Example

      + *
      +     * {@code
      +     *     try {
      +     *         throw new NetworkException(new IOException("An error occurred"));
      +     *     } catch (NetworkException e) {
      +     *         System.out.println("Error: " + e.getMessage());
      +     *     }
      +     * }
      +     * 
      + * + * @param other The other {@link Throwable}. + */ public NetworkException(final Throwable other) { super(other); this.url = ""; @@ -23,10 +42,37 @@ public NetworkException(final Throwable other) { this.content = ""; } + /** + *

      NetworkException({@link HttpResponse})

      + *

      Creates a new NetworkException based on a {@link HttpResponse}.

      + *

      Example

      + *
      +     * {@code
      +     *     var response = HttpClient.newHttpClient().send(HttpRequest.newBuilder().uri(URI.create("https://example.com")).build(), HttpResponse.BodyHandlers.ofString());
      +     *     NetworkException exception = new NetworkException(response);
      +     * }
      +     * 
      + * + * @param response The response that caused the exception. + */ public NetworkException(final HttpResponse response) { this(response.statusCode(), response.body().toString(), response.uri().toString()); } + /** + *

      NetworkException({@link String}, int, {@link String})

      + *

      Creates a new NetworkException with the given status code, content and URL.

      + *

      Example

      + *
      +     * {@code
      +     *     throw new NetworkException(404, "Not found", "https://example.com");
      +     * }
      +     * 
      + * + * @param statusCode The status code. + * @param content The content. + * @param url + */ public NetworkException(final int statusCode, final String content, final String url) { super(String.format("NetworkException was thrown with status (%s) from \"%s\" with content \"%s\"", statusCode, url, content)); this.url = url; @@ -34,14 +80,29 @@ public NetworkException(final int statusCode, final String content, final String this.content = content; } + /** + *

      getStatusCode()

      + * + * @return The status code. + */ public int getStatusCode() { return statusCode; } + /** + *

      getContent()

      + * + * @return The content. + */ public String getContent() { return content; } + /** + *

      getUrl()

      + * + * @return The URL. + */ public String getUrl() { return url; } diff --git a/exceptions/src/main/java/de/haevn/utils/exceptions/NotYetImplementedException.java b/exceptions/src/main/java/de/haevn/utils/exceptions/NotYetImplementedException.java index 8cb3de3..ad4c2ba 100644 --- a/exceptions/src/main/java/de/haevn/utils/exceptions/NotYetImplementedException.java +++ b/exceptions/src/main/java/de/haevn/utils/exceptions/NotYetImplementedException.java @@ -3,29 +3,49 @@ import de.haevn.utils.debug.MethodTools; /** - * Indicates that the method is not yet implemented. + *

      NotYetImplementedException

      + *
      + *

      This exception is thrown when a method is not yet implemented.

      + *

      The method can be used to identify the method that is not yet implemented.

      + *

      The application can recover instead of crashing.

      + *

      Example

      + *
      + * {@code
      + *     void doSomething() {
      + *         throw new NotYetImplementedException();
      + *     }
      + * }
      + * 
      + * + * @author haevn * @version 1.0 * @since 1.0 - * @author haevn */ public class NotYetImplementedException extends Error { private final String message; + /** + *

      NotYetImplementedException()

      + */ public NotYetImplementedException() { - final var method = MethodTools.getMethod(2); - if(method.isPresent()) { - this.message = "Method \"" + method + "\" is not yet implemented."; - }else { - this.message = "Method is not yet implemented."; - } + final var method = MethodTools.getMethod(2); + if (method.isPresent()) { + this.message = "Method \"" + method + "\" is not yet implemented."; + } else { + this.message = "Method is not yet implemented."; + } } + /** + *

      NotYetImplementedException({@link String})

      + *

      Creates a new NotYetImplementedException with the given message.

      + * + * @param message The message of the exception. + */ public NotYetImplementedException(final String message) { this.message = message; } - - @Override public String getMessage() { return message; diff --git a/exceptions/src/main/java/de/haevn/utils/exceptions/ValidationFailedException.java b/exceptions/src/main/java/de/haevn/utils/exceptions/ValidationFailedException.java index 3854318..9683705 100644 --- a/exceptions/src/main/java/de/haevn/utils/exceptions/ValidationFailedException.java +++ b/exceptions/src/main/java/de/haevn/utils/exceptions/ValidationFailedException.java @@ -1,10 +1,15 @@ package de.haevn.utils.exceptions; /** - * A simple exception class for validation exceptions. + *

      ValidationFailedException

      + *
      + *

      This exception is thrown when a validation fails.

      + *

      It provides a message that can be used to identify the error.

      + * + * @author haevn * @version 1.1 + * @see Exception * @since 1.1 - * @author haevn */ public class ValidationFailedException extends Exception { public ValidationFailedException(final String message) { diff --git a/io/src/main/java/de/haevn/utils/io/FileReader.java b/io/src/main/java/de/haevn/utils/io/FileReader.java index 54b4032..c640a8e 100644 --- a/io/src/main/java/de/haevn/utils/io/FileReader.java +++ b/io/src/main/java/de/haevn/utils/io/FileReader.java @@ -9,16 +9,49 @@ import java.util.Base64; import java.util.function.Function; +/** + *

      FileReader

      + *

      The FileReader class provides methods to read files from the file system

      + *

      It provides methods to read files as string, byte array, base64 encoded string or to map the content to an object

      + *

      The FileReader can be accessed via two static methods:

      + *
        + *
      • getFileReader(String rootFile): Returns a FileReader instance for the given directory
      • + *
      • getApplicationFileReader(): Returns a FileReader instance for the application directory
      • + *
      + * + *

      Example 1:

      + *
      {@code
      + * FileReader fileReader = FileReader.getFileReader("path/to/directory");
      + * String content = fileReader.read("file.txt");
      + * }
      + * + *

      Example 2:

      + *
      {@code
      + * FileReader fileReader = FileReader.getApplicationFileReader();
      + * String content = fileReader.read("file.txt");
      + * }
      + * + * @author Haevn + * @version 1.0 + * @since 2.1 + */ public class FileReader { private final Logger logger = new Logger(FileReader.class); private final File rootFile; + /** + *

      FileReader

      + *

      Private constructor to create a FileReader instance

      + * + * @param rootFile the directory to read from + */ private FileReader(final File rootFile) { this.rootFile = rootFile; } /** - * Returns a FileReader instance for the given directory + *

      getFileReader(String)

      + *

      Returns a FileReader instance for the given directory

      * * @param rootFile the directory to read from * @return a FileReader instance @@ -28,7 +61,8 @@ public static FileReader getFileReader(final String rootFile) { } /** - * Returns a FileReader instance for the application directory + *

      getApplicationFileReader()

      + *

      Returns a FileReader instance for the application directory specified by {@link LauncherUtils#getLauncher()#rootFile}

      * * @return a FileReader instance */ @@ -38,14 +72,21 @@ public static FileReader getApplicationFileReader() { /** - * Reads the content of the file with the given name + *

      read(String)

      + *

      Reads the content of the file with the given name

      + *

      It returns the content of the file as string

      + *

      If an error occurs, an error message is logged and an empty string is returned

      + *

      Example:

      + *
      {@code
      +     * final FileReader fileReader = FileReader.getFileReader("path/to/directory");
      +     * String content = fileReader.read("file.txt");
      +     * }
      * * @param fileName the name of the file to read * @return the content of the file */ public String read(final String fileName) { try { - return Files.readString(new File(rootFile, fileName).toPath()); } catch (IOException e) { logger.atError() @@ -57,7 +98,14 @@ public String read(final String fileName) { } /** - * Reads the content of the file with the given name as byte array + *

      readBytes(String)

      + *

      Reads the content of the file with the given name as byte array

      + *

      Example:

      + *
      {@code
      +     * final FileReader fileReader = FileReader.getFileReader("path/to/directory");
      +     * byte[] content = fileReader.readBytes("file.txt");
      +     * }
      + *

      If an error occurs, an error message is logged and an empty byte array is returned

      * * @param fileName the name of the file to read * @return the content of the file as byte array @@ -76,7 +124,15 @@ public byte[] readBytes(final String fileName) { /** - * Reads the content of the file with the given name as base64 encoded string + *

      readBase64(String)

      + *

      Reads the content of the file with the given name as base64 encoded string

      + *

      Example:

      + *
      {@code
      +     * final FileReader fileReader = FileReader.getFileReader("path/to/directory");
      +     * byte[] content = fileReader.readBase64("file.txt");
      +     * }
      + *

      If an error occurs, an error message is logged and an empty byte array is returned

      + * * @param fileName the name of the file to read * @return the content of the file as base64 encoded string */ @@ -86,7 +142,15 @@ public byte[] readBase64(final String fileName) { } /** - * Reads the content of the file with the given name as base64 encoded string + *

      readBase64String(String)

      + *

      Reads the content of the file with the given name as base64 encoded string

      + *

      Example:

      + *
      {@code
      +     * final FileReader fileReader = FileReader.getFileReader("path/to/directory");
      +     * String content = fileReader.readBase64String("file.txt");
      +     * }
      + *

      If an error occurs, an error message is logged and an empty string is returned

      + * * @param fileName the name of the file to read * @return the content of the file as base64 encoded string */ @@ -95,7 +159,14 @@ public String readBase64String(final String fileName) { } /** - * Reads the content of the file with the given name and maps it to an object + *

      readObject(String, {@link Function})

      + *

      Reads the content of the file with the given name and maps it to an object using the given function

      + *

      Example:

      + *
      {@code
      +     * final FileReader fileReader = FileReader.getFileReader("path/to/directory");
      +     * MyObject object = fileReader.readObject("file.txt", MyObject::new);
      +     * }
      + *

      If an error occurs, an error message is logged and null is returned

      * * @param fileName the name of the file to read * @param mapper the function to map the content to an object diff --git a/io/src/main/java/de/haevn/utils/io/FileUtils.java b/io/src/main/java/de/haevn/utils/io/FileUtils.java index cd7db25..18c000b 100644 --- a/io/src/main/java/de/haevn/utils/io/FileUtils.java +++ b/io/src/main/java/de/haevn/utils/io/FileUtils.java @@ -13,43 +13,123 @@ import java.nio.file.attribute.FileTime; import java.time.LocalDateTime; +/** + *

      FileUtils

      + *

      The FileUtils class provides methods to work with files and directories

      + *

      It provides methods to get information about files, create files and directories, open files with the default application and get the root path of the application

      + *

      The FileUtils can be accessed via static methods

      + * + *

      Example 1:

      + *
      {@code
      + * String fileName = FileUtils.getFileName("path/to/file.txt");
      + * }
      + * + *

      Example 2:

      + *
      {@code
      + * FileUtils.createFileIfNotExists("path/to/file.txt");
      + * }
      + * + * @author Haevn + * @version 1.0 + * @since 2.1 + */ public class FileUtils { private FileUtils() { } - + /** + *

      getFileName(String)

      + *

      Returns the file name of the given path

      + * + * @param path Path to the file + * @return File name + */ public static String getFileName(final String path) { return path.substring(path.lastIndexOf("\\") + 1); } + /** + *

      getFileNameWithoutExtension(String)

      + *

      Returns the file name without extension of the given path

      + * + * @param path Path to the file + * @return File name without extension + */ public static String getFileNameWithoutExtension(final String path) { return getFileName(path).substring(0, getFileName(path).lastIndexOf(".")); } + /** + *

      getExtension(String)

      + *

      Returns the extension of the given path

      + * + * @param path Path to the file + * @return Extension + */ public static String getExtension(final String path) { return getFileName(path).substring(getFileName(path).lastIndexOf(".") + 1); } + /** + *

      getDirectory(String)

      + *

      Returns the directory of the given path

      + * + * @param path Path to the file + * @return Directory + */ public static String getDirectory(final String path) { return path.substring(0, path.lastIndexOf("\\")); } + /** + *

      getUserHome()

      + *

      Returns the user home directory

      + * + * @return User home directory + */ public static String getUserHome() { return System.getProperty("user.home"); } + /** + *

      getUserHomeWithSeparator()

      + *

      Returns the user home directory with separator

      + * + * @return User home directory with separator + */ public static String getUserHomeWithSeparator() { return getUserHome() + File.separator; } + /** + *

      getInfo(String)

      + *

      Returns the file {@link BasicFileAttributes attributes} of the given file

      + * + * @param file Path to the file + * @return Basic file attributes + */ public static BasicFileAttributes getInfo(final String file) { return getInfo(new File(file)); } + /** + *

      getInfo([{@link File})

      + *

      Returns the file {@link BasicFileAttributes attributes} of the given file

      + * + * @param file File + * @return Basic file attributes + */ public static BasicFileAttributes getInfo(final File file) { return getInfo(file.toPath()); } + /** + *

      getInfo({@link Path})

      + *

      Returns the file {@link BasicFileAttributes attributes} of the given file

      + * + * @param file Path + * @return Basic file attributes + */ public static BasicFileAttributes getInfo(final Path file) { try { return Files.readAttributes(file, BasicFileAttributes.class); @@ -58,19 +138,43 @@ public static BasicFileAttributes getInfo(final Path file) { } } + /** + *

      convertTime({@link FileTime})

      + *

      Converts a {@link FileTime} to a {@link LocalDateTime}

      + * + * @param time File time + * @return Local date time + */ public static LocalDateTime convertTime(final FileTime time) { return LocalDateTime.ofInstant(time.toInstant(), java.time.ZoneId.systemDefault()); } - + /** + *

      createFileIfNotExists(String)

      + *

      Creates a file if it does not exist

      + * + * @param file Path to the file + */ public static void createFileIfNotExists(final String file) { createFileIfNotExists(new File(file)); } + /** + *

      createFileIfNotExists({@link Path})

      + *

      Creates a file if it does not exist

      + * + * @param file Path to the file + */ public static void createFileIfNotExists(final Path file) { createFileIfNotExists(file.toFile()); } + /** + *

      createFileIfNotExists({@link File})

      + *

      Creates a file if it does not exist

      + * + * @param file File + */ public static void createFileIfNotExists(final File file) { if (file.exists()) { return; @@ -82,6 +186,12 @@ public static void createFileIfNotExists(final File file) { } } + /** + *

      createDirectoryIfNotExists(String)

      + *

      Creates a directory if it does not exist

      + * + * @param directory Path to the directory + */ public static void createDirectoryIfNotExists(final File directory) { if (directory.exists()) { return; @@ -89,16 +199,32 @@ public static void createDirectoryIfNotExists(final File directory) { directory.mkdirs(); } - + /** + *

      getRootPath()

      + *

      Returns the root path of the application

      + * + * @return Root path + */ public static String getRootPath() { return LauncherUtils.getLauncher().getRootPath(); } - + /** + *

      getRootPathWithSeparator()

      + *

      Returns the root path of the application with separator

      + * + * @return Root path with separator + */ public static String getRootPathWithSeparator() { return getRootPath() + File.separator; } + /** + *

      openDefaultApplication(String)

      + *

      Opens the file with the default application

      + * + * @param file Path to the file + */ public static void openDefaultApplication(final File file) { try { Desktop.getDesktop().open(file); @@ -106,11 +232,23 @@ public static void openDefaultApplication(final File file) { } } - + /** + *

      openDefaultApplication(String)

      + *

      Opens the file with the default application

      + * + * @param path Path to the file + */ public static URL getURI(final String path) { return getURL(new File(path)); } + /** + *

      getURL({@link File})

      + *

      Returns the URL of the given file

      + * + * @param file File + * @return URL + */ public static URL getURL(final File file) { try { return file.toURI().toURL(); @@ -120,6 +258,12 @@ public static URL getURL(final File file) { } + /** + *

      emptyAttribute

      + *

      Empty file attributes

      + *

      Used if an error occurs while reading the file attributes

      + *

      It is used by several methods in the FileUtils class to prevent null pointer exceptions

      + */ private static final BasicFileAttributes emptyAttribute = new BasicFileAttributes() { @Override public FileTime lastModifiedTime() { diff --git a/io/src/main/java/de/haevn/utils/io/FileWatcher.java b/io/src/main/java/de/haevn/utils/io/FileWatcher.java index efc1845..2737bd3 100644 --- a/io/src/main/java/de/haevn/utils/io/FileWatcher.java +++ b/io/src/main/java/de/haevn/utils/io/FileWatcher.java @@ -8,26 +8,82 @@ import java.util.concurrent.atomic.AtomicLong; +/** + *

      FileWatcher

      + *

      The FileWatcher class provides methods to watch files for changes

      + *

      It provides methods to watch files for changes and execute a callback when a file has changed

      + *

      The FileWatcher can be accessed via static methods

      + * + *

      Example:

      + *
      {@code
      + * FileWatcher watcher = FileWatcher.getInstance();
      + * watcher.watch("path/to/file.txt", 1, TimeUnit.SECONDS, () -> System.out.println("File has changed"));
      + * }
      + * + * @author Haevn + * @version 1.0 + * @since 2.1 + */ public class FileWatcher implements AutoCloseable { private static final Logger LOGGER = new Logger(FileWatcher.class); - private final AtomicLong watchingFiles = new AtomicLong(0); - private final AtomicLong maxFiles = new AtomicLong(5); private static final FileWatcher INSTANCE = new FileWatcher(); private final BackgroundWorker backgroundWorker = BackgroundWorker.getInstance(); + /** + * This attribute stores the number of files that are currently being watched + */ + private final AtomicLong watchingFiles = new AtomicLong(0); + + /** + * This attribute stores the maximum number of files that can be watched + */ + private final AtomicLong maxFiles = new AtomicLong(5); + + /** + *

      getInstance()

      + *

      Returns the FileWatcher instance

      + * + * @return the FileWatcher instance + */ public static synchronized FileWatcher getInstance() { return INSTANCE; } + /** + *

      setLimit(int)

      + *

      Sets the maximum number of files that can be watched

      + * + * @param limit the maximum number of files + */ public static synchronized void setLimit(final int limit) { INSTANCE.maxFiles.set(limit); } + /** + *

      stop()

      + *

      Stops the FileWatcher

      + */ public void stop() { backgroundWorker.shutdown(); } + /** + *

      watch(String, int, {@link TimeUnit}, {@link Runnable})

      + *

      The submitted file will be checked every interval for changes. If the file has changed, the callback will be executed

      + *

      When the maximum number of files is reached, the method will return without watching the file

      + *

      The change of the file is determined by the last modified date of the file

      * + *

      Example:

      + *
      {@code
      +     * FileWatcher watcher = FileWatcher.getInstance();
      +     * watcher.watch("path/to/file.txt", 1, TimeUnit.SECONDS, () -> System.out.println("File has changed"));
      +     * }
      + * + * @param path the path to the file + * @param interval the interval to check for changes + * @param unit the time unit of the interval + * @param callback the callback to execute when the file has changed + */ public void watch(final String path, final int interval, TimeUnit unit, final Runnable callback) { if (maxFiles.get() < watchingFiles.get()) { LOGGER.atError().forEnclosingMethod().withMessage("Max files reached, current limit is %s/%s", watchingFiles.get(), maxFiles).log(); @@ -49,7 +105,10 @@ public void watch(final String path, final int interval, TimeUnit unit, final Ru LOGGER.atInfo().forEnclosingMethod().withMessage("Finished watching").log(); } - + /** + *

      close()

      + *

      Invokes the {@link #stop()} method

      + */ @Override public void close() throws Exception { stop(); diff --git a/io/src/main/java/de/haevn/utils/io/FileWriter.java b/io/src/main/java/de/haevn/utils/io/FileWriter.java index 5fa63ae..65aca9c 100644 --- a/io/src/main/java/de/haevn/utils/io/FileWriter.java +++ b/io/src/main/java/de/haevn/utils/io/FileWriter.java @@ -10,16 +10,47 @@ import java.nio.file.StandardOpenOption; import java.util.Base64; +/** + *

      FileWriter

      + *

      The FileWriter class provides methods to write files to the file system

      + *

      It provides methods to write files as string, byte array or base64 encoded string

      + *

      The FileWriter can be accessed via two static methods:

      + *
        + *
      • getFileWriter(String rootFile): Returns a FileWriter instance for the given directory
      • + *
      • getApplicationFileWriter(): Returns a FileWriter instance for the application directory
      • + *
      + *

      Example 1:

      + *
      {@code
      + * FileWriter fileWriter = FileWriter.getFileWriter("path/to/directory");
      + * fileWriter.write("file.txt", "Hello World");
      + * }
      + *

      Example 2:

      + *
      {@code
      + * FileWriter fileWriter = FileWriter.getApplicationFileWriter();
      + * fileWriter.write("file.txt", "Hello World");
      + * }
      + * + * @author Haevn + * @version 1.0 + * @since 2.1 + */ public class FileWriter { final Logger logger = new Logger(FileWriter.class); private final File rootFile; + /** + *

      FileWriter

      + *

      Private constructor to create a FileWriter instance

      + * + * @param rootFile + */ private FileWriter(final File rootFile) { this.rootFile = rootFile; } /** - * Returns a FileReader instance for the given directory + *

      getFileWriter(String)

      + *

      Returns a FileReader instance for the given directory

      * * @param rootFile the directory to read from * @return a FileReader instance @@ -29,16 +60,23 @@ public static FileWriter getFileWriter(final String rootFile) { } /** - * Returns a FileReader instance for the application directory + *

      getApplicationFileWriter()

      + *

      Returns a FileWriter instance for the application directory specified by {@link LauncherUtils#getLauncher()#rootFile}

      * - * @return a FileReader instance + * @return a FileWriter instance */ public static FileWriter getApplicationFileWriter() { return new FileWriter(new File(LauncherUtils.getLauncher().getRootPath())); } /** - * Writes the given content to the file with the given name + *

      write(String, String)

      + *

      Writes the given content to the file with the given name

      + *

      Example:

      + *
      {@code
      +     * final FileWriter fileWriter = FileWriter.getFileWriter("path/to/directory");
      +     * fileWriter.write("file.txt", "Hello World");
      +     * }
      * * @param fileName the name of the file to write to * @param content the content to write @@ -57,7 +95,14 @@ public void write(final String fileName, final String content) { } /** - * Writes the given content to the file with the given name + *

      write(String, byte[])

      + *

      Writes the given content to the file with the given name

      + *

      Example:

      + *
      {@code
      +     * final FileWriter fileWriter = FileWriter.getFileWriter("path/to/directory");
      +     * final byte[] data = {...}
      +     * fileWriter.write("file.txt", data);
      +     * }
      * * @param fileName the name of the file to write to * @param content the content to write @@ -76,9 +121,17 @@ public void write(final String fileName, final byte[] content) { } /** - * Writes the given content as base64 to the file with the given name + *

      writeBase64(String, byte[])

      + *

      Writes the given content as base64 to the file with the given name

      + *

      Example:

      + *
      {@code
      +     * final FileWriter fileWriter = FileWriter.getFileWriter("path/to/directory");
      +     * final byte[] data = {...}
      +     * fileWriter.writeBase64("file.txt", data);
      +     * }
      + * * @param fileName the name of the file to write to - * @param data the content to write + * @param data the content to write */ public void writeBase64(final String fileName, final byte[] data) { Base64.Encoder base64 = Base64.getEncoder(); @@ -87,16 +140,29 @@ public void writeBase64(final String fileName, final byte[] data) { /** - * Writes the given content as base64 to the file with the given name + *

      writeBase64String(String, String)

      + *

      Writes the given content as base64 to the file with the given name

      + *

      Example:

      + *
      {@code
      +     * final FileWriter fileWriter = FileWriter.getFileWriter("path/to/directory");
      +     * fileWriter.writeBase64String("file.txt", "Hello World");
      +     * }
      + * * @param fileName the name of the file to write to - * @param data the content to write + * @param data the content to write */ public void writeBase64String(final String fileName, final String data) { writeBase64(fileName, data.getBytes(StandardCharsets.UTF_8)); } /** - * Appends the given content to the file with the given name + *

      append(String, String)

      + *

      Appends the given content to the file with the given name

      + *

      Example:

      + *
      {@code
      +     * final FileWriter fileWriter = FileWriter.getFileWriter("path/to/directory");
      +     * fileWriter.append("file.txt", "Hello World");
      +     * }
      * * @param fileName the name of the file to append to * @param content the content to append @@ -115,7 +181,14 @@ public void append(final String fileName, final String content) { } /** - * Appends the given content to the file with the given name + *

      append(String, byte[])

      + *

      Appends the given content to the file with the given name

      + *

      Example:

      + *
      {@code
      +     * final FileWriter fileWriter = FileWriter.getFileWriter("path/to/directory");
      +     * final byte[] data = {...}
      +     * fileWriter.append("file.txt", data);
      +     * }
      * * @param fileName the name of the file to append to * @param content the content to append diff --git a/io/src/main/java/de/haevn/utils/io/PropertyHandler.java b/io/src/main/java/de/haevn/utils/io/PropertyHandler.java index e791d84..c19f247 100644 --- a/io/src/main/java/de/haevn/utils/io/PropertyHandler.java +++ b/io/src/main/java/de/haevn/utils/io/PropertyHandler.java @@ -8,6 +8,28 @@ import java.util.Map; import java.util.Properties; +/** + *

      PropertyHandler

      + *

      The PropertyHandler class provides methods to read and write properties files

      + *

      It provides methods to read and write properties as string, boolean, int, long or double

      + *

      The PropertyHandler can be accessed via two static methods:

      + *
        + *
      • getInstance(String name): Returns a PropertyHandler instance for the given property file
      • + *
      • getAllHandler(): Returns a list of all PropertyHandler instances
      • + *
      + *

      A static method reloadAll() is provided to reload all property files

      + *

      Example 1:

      + *
      {@code
      + * PropertyHandler propertyHandler = PropertyHandler.getInstance("Dummy");
      + * String value = propertyHandler.get("key");
      + * }
      + *

      Example 2:

      + *
      {@code
      + * PropertyHandler propertyHandler = PropertyHandler.getInstance("Dummy");
      + * propertyHandler.set("key", "value");
      + * propertyHandler.store();
      + * }
      + */ public final class PropertyHandler { private static final Logger LOGGER = new Logger(PropertyHandler.class); private static final String EXTENSION = ".property"; @@ -17,6 +39,12 @@ public final class PropertyHandler { private final File configFile; + /** + *

      PropertyHandler

      + *

      Private constructor to create a PropertyHandler instance

      + * + * @param propertyName the name of the property file + */ private PropertyHandler(final String propertyName) { properties = new Properties(); this.name = propertyName; @@ -25,6 +53,15 @@ private PropertyHandler(final String propertyName) { load(); } + /** + *

      getInstance(String)

      + *

      If a PropertyHandler instance for the given property file already exists, it will be returned, + * otherwise a new PropertyHandler instance will be created

      + *

      If a new PropertyHandler instance is created, it will be stored in a map for later access

      + * + * @param name the name of the property file + * @return a PropertyHandler instance + */ public static PropertyHandler getInstance(final String name) { if (STRING_PROPERTY_HANDLER_HASH_MAP.containsKey(name.toUpperCase())) { return STRING_PROPERTY_HANDLER_HASH_MAP.get(name.toUpperCase()); @@ -35,18 +72,36 @@ public static PropertyHandler getInstance(final String name) { return handler; } + /** + *

      getAllHandler()

      + *

      Returns a list of all PropertyHandler instances

      + * + * @return a list of all PropertyHandler instances + */ public static List getAllHandler() { return STRING_PROPERTY_HANDLER_HASH_MAP.keySet().stream().toList(); } + /** + *

      reloadAll()

      + *

      Reloads all property files

      + */ public static void reloadAll() { STRING_PROPERTY_HANDLER_HASH_MAP.values().forEach(PropertyHandler::reload); } + /** + *

      reload()

      + *

      Reloads the property file

      + */ public void reload() { load(); } + /** + *

      load()

      + *

      Loads the property file

      + */ public void load() { try (final InputStream inputStream = new FileInputStream(configFile)) { properties.load(inputStream); @@ -63,10 +118,26 @@ public void load() { // Getter //---------------------------------------------------------------------------------------------------------------------- + /** + *

      get(String)

      + *

      Returns the value of the given key as string

      + * + * @param key the key to get the value for + * @return the value of the key as string + */ public String get(final String key) { return get(key, ""); } + /** + *

      get(String, String)

      + *

      Returns the value of the given key as string

      + *

      If the key does not exist, the default value is returned

      + * + * @param key the key to get the value for + * @param defaultValue the default value to return if the key does not exist + * @return the value of the key as string + */ public String get(final String key, String defaultValue) { if (!properties.containsKey(key)) { properties.setProperty(key, defaultValue); @@ -74,54 +145,190 @@ public String get(final String key, String defaultValue) { return properties.getProperty(key, defaultValue); } + /** + *

      getBoolean(String)

      + *

      Returns the value of the given key as boolean

      + * + * @param key the key to get the value for + * @return the value of the key as boolean + */ public boolean getBoolean(final String key) { return Boolean.parseBoolean(get(key, "false")); } + /** + *

      getBoolean(String, boolean)

      + *

      Returns the value of the given key as boolean

      + *

      If the key does not exist, the default value is returned

      + * + * @param key the key to get the value for + * @param defaultValue the default value to return if the key does not exist + * @return the value of the key as boolean + */ public boolean getBoolean(final String key, boolean defaultValue) { return Boolean.parseBoolean(get(key, String.valueOf(defaultValue))); } + /** + *

      getInt(String)

      + *

      Returns the value of the given key as int

      + * + * @param key the key to get the value for + * @return the value of the key as int + */ public int getInt(final String key) { return Integer.parseInt(get(key, "0")); } + /** + *

      getInt(String, int)

      + *

      Returns the value of the given key as int

      + *

      If the key does not exist, the default value is returned

      + * + * @param key the key to get the value for + * @param defaultValue the default value to return if the key does not exist + * @return the value of the key as int + */ public int getInt(final String key, int defaultValue) { return Integer.parseInt(get(key, String.valueOf(defaultValue))); } + /** + *

      getLong(String)

      + *

      Returns the value of the given key as long

      + * + * @param key the key to get the value for + * @return the value of the key as long + */ public long getLong(final String key) { return Long.parseLong(get(key, "0")); } + /** + *

      getLong(String, long)

      + *

      Returns the value of the given key as long

      + *

      If the key does not exist, the default value is returned

      + * + * @param key the key to get the value for + * @param defaultValue the default value to return if the key does not exist + * @return the value of the key as long + */ public long getLong(final String key, long defaultValue) { return Long.parseLong(get(key, String.valueOf(defaultValue))); } + /** + *

      getDouble(String)

      + *

      Returns the value of the given key as double

      + * + * @param key the key to get the value for + * @return the value of the key as double + */ public double getDouble(final String key) { return Double.parseDouble(get(key, "0.0")); } + /** + *

      getDouble(String, double)

      + *

      Returns the value of the given key as double

      + *

      If the key does not exist, the default value is returned

      + * + * @param key the key to get the value for + * @param defaultValue the default value to return if the key does not exist + * @return the value of the key as double + */ public double getDouble(final String key, double defaultValue) { return Double.parseDouble(get(key, String.valueOf(defaultValue))); } + /** + *

      getAllProperties()

      + *

      Returns a list of all keys in the property file

      + * + * @return a list of all keys in the property file + */ public List getAllProperties() { return properties.keySet().stream().map(Object::toString).toList(); } - + /** + *

      set(String, String)

      + *

      Sets the value of the given key to the given value

      + *

      The property file will be saved

      + * + * @param k the key to set the value for + * @param value the value to set + */ public void set(final String k, final String value) { properties.setProperty(k, value); - try (final OutputStream os = new FileOutputStream(configFile)) { - properties.store(os, "Updated " + k + " to " + value); - } catch (IOException e) { - LOGGER.atError().forEnclosingMethod() - .withException(e) - .withMessage("Could not save property file: %s", name).log(); - } + store(); + } + + /** + *

      set(String, boolean)

      + *

      Sets the value of the given key to the given value

      + *

      The property file will be saved

      + * + * @param k the key to set the value for + * @param value the value to set + */ + public void set(final String k, final boolean value) { + set(k, String.valueOf(value)); + } + + /** + *

      set(String, int)

      + *

      Sets the value of the given key to the given value

      + *

      The property file will be saved

      + * + * @param k the key to set the value for + * @param value the value to set + */ + public void set(final String k, final int value) { + set(k, String.valueOf(value)); + } + + /** + *

      set(String, long)

      + *

      Sets the value of the given key to the given value

      + *

      The property file will be saved

      + * + * @param k the key to set the value for + * @param value the value to set + */ + public void set(final String k, final long value) { + set(k, String.valueOf(value)); + } + + /** + *

      set(String, double)

      + *

      Sets the value of the given key to the given value

      + *

      The property file will be saved

      + * + * @param k the key to set the value for + * @param value the value to set + */ + public void set(final String k, final double value) { + set(k, String.valueOf(value)); + } + + /** + *

      remove(String)

      + *

      Removes the given key from the property file

      + *

      The property file will be saved

      + * + * @param k the key to remove + */ + public void remove(final String k) { + properties.remove(k); + store(); } + /** + *

      store()

      + *

      Stores the property file

      + *

      If an error occurs, an error message is logged

      + */ public void store() { FileUtils.createFileIfNotExists(configFile); try (final OutputStream os = new FileOutputStream(configFile)) { diff --git a/io/src/main/java/de/haevn/utils/io/USB.java b/io/src/main/java/de/haevn/utils/io/USB.java index 201e4b4..6a40923 100644 --- a/io/src/main/java/de/haevn/utils/io/USB.java +++ b/io/src/main/java/de/haevn/utils/io/USB.java @@ -5,6 +5,7 @@ import java.util.List; /** + *

      USB

      *

      This class provides an interface to find and interact with USB devices.

      * THIS FEATURE WILL BE IMPLEMENTED WITH VERSION 1.2 * @@ -40,7 +41,7 @@ private USB() { private void shutdown() { - + // This method is called when the application is closed } public interface Device { diff --git a/io/src/main/java/de/haevn/utils/io/ZipUtils.java b/io/src/main/java/de/haevn/utils/io/ZipUtils.java index ee271c9..51908de 100644 --- a/io/src/main/java/de/haevn/utils/io/ZipUtils.java +++ b/io/src/main/java/de/haevn/utils/io/ZipUtils.java @@ -1,25 +1,50 @@ package de.haevn.utils.io; +import de.haevn.utils.exceptions.ApplicationException; import net.lingala.zip4j.ZipFile; import net.lingala.zip4j.exception.ZipException; import java.io.File; import java.io.IOException; +/** + *

      ZipUtils

      + *

      The ZipUtils class provides methods to zip files and directories

      + *

      It provides a method to zip files and directories

      + *

      The ZipUtils can be accessed via static methods

      + * + *

      Example:

      + *
      {@code
      + * ZipUtils.zip(new File("output.zip"), new File("path/to/file1"), new File("path/to/file2"));
      + * }
      + * + * @author Haevn + * @version 1.0 + * @since 2.1 + */ public class ZipUtils { - private ZipUtils() {} + private ZipUtils() { + } + /** + *

      zip({@link File}, {@link File}...)

      + *

      Zips the given files and directories into the output file

      + *

      It uses the zip4j library to zip the files and directories

      + * + * @param outputFile the output file + * @param input the files and directories to zip + */ public static void zip(final File outputFile, final File... input) { - try(final ZipFile zip = new ZipFile(outputFile)) { + try (final ZipFile zip = new ZipFile(outputFile)) { for (File file : input) { try { zip.addFolder(file); - } catch (ZipException e) { - e.printStackTrace(); + } catch (ZipException ex) { + throw new ApplicationException(ex); } } - }catch (IOException ignored){ + } catch (IOException ignored) { // The throw should be ignored } } diff --git a/io/src/main/java/de/haevn/utils/io/merge/AbstractFileMerging.java b/io/src/main/java/de/haevn/utils/io/merge/AbstractFileMerging.java index 1e23124..ba15319 100644 --- a/io/src/main/java/de/haevn/utils/io/merge/AbstractFileMerging.java +++ b/io/src/main/java/de/haevn/utils/io/merge/AbstractFileMerging.java @@ -13,13 +13,35 @@ /** - * This class provides methods to merge files. + *

      AbstractFileMerging

      + *
      + *

      This abstract class implements {@link IFileMerging} and implements some methods of the interface.

      + *
      + *

      It provides the following methods:

      + *
        + *
      • {@link #mergeFiles(File, String...)}: Merges the given files into the output file.
      • + *
      • {@link #mergeFiles(File, File...)}: Merges the given files into the output file.
      • + *
      • {@link #readFile(File)}: Reads a file into memory.
      • + *
      • {@link #storeFile(File, byte[])}: Stores the given bytes into the given file.
      • + *
      • {@link #storeFile(File, byte[], boolean)}: Stores the given bytes into the given file.
      • + *
      + *
      + *

      It also provides a logger for logging messages.

      + *
      + *

      It is recommended to extend this class when implementing a file merging class.

      */ public abstract class AbstractFileMerging implements IFileMerging { private static final Logger LOGGER = new Logger(AbstractFileMerging.class); /** - * Merges the given files into the output file. + *

      mergeFiles({@link File}, String...)

      + *
      + *

      Merges the given files into the output file.

      + *

      Example:

      + *
      {@code
      +     *  final FileMerging fileMerging = new FileMerging();
      +     *  fileMerging.mergeFiles(new File("output.txt"), "input1.txt", "input2.txt");
      +     * }
      * * @param output the output file * @param input the input files @@ -30,7 +52,15 @@ public void mergeFiles(final File output, final String... input) throws FileMerg } /** - * Merges the given files into the output file. + *

      mergeFiles({@link File}, {@link File}...)

      + *
      + *

      Merges the given files into the output file.

      + *

      Example:

      + *
      {@code
      +     * final FileMerging fileMerging = new FileMerging();
      +     * fileMerging.mergeFiles(new File("output.txt"), new File("input1.txt"), new File("input2.txt"));
      +     * }
      + *
      * * @param output the output file * @param input the input files @@ -42,7 +72,15 @@ public void mergeFiles(final File output, final File... input) throws FileMergeE /** - * Reads a file into memory + *

      readFile({@link File})

      + *
      + *

      This method reads the content of the given file into a byte array and returns it.

      + *

      Example:

      + *
      {@code
      +     * final FileMerging fileMerging = new FileMerging();
      +     * final byte[] bytes = fileMerging.readFile(new File("input.txt"));
      +     * }
      + *
      * * @param file the file to read * @return the content of the file as a byte array @@ -59,7 +97,15 @@ protected byte[] readFile(final File file) { } /** - * Stores the given bytes into the given file + *

      storeFile({@link File}, byte[])

      + *
      + *

      This method stores the given bytes into the given file.

      + *

      Example:

      + *
      {@code
      +     * final FileMerging fileMerging = new FileMerging();
      +     * final byte[] data = {...}
      +     * fileMerging.storeFile(new File("output.txt"), data);
      +     * }
      * * @param file the file to store the bytes in * @param bytes the bytes to store @@ -70,7 +116,15 @@ protected void storeFile(final File file, final byte[] bytes) throws IOException } /** - * Stores the given bytes into the given file + *

      storeFile({@link File}, byte[], boolean)

      + *
      + *

      This method stores the given bytes into the given file.

      + *

      Example:

      + *
      {@code
      +     * final FileMerging fileMerging = new FileMerging();
      +     * final byte[] data = {...}
      +     * fileMerging.storeFile(new File("output.txt"), data, true);
      +     * }
      * * @param file the file to store the bytes in * @param bytes the bytes to store diff --git a/io/src/main/java/de/haevn/utils/io/merge/IFileMerging.java b/io/src/main/java/de/haevn/utils/io/merge/IFileMerging.java index 8741591..a2db818 100644 --- a/io/src/main/java/de/haevn/utils/io/merge/IFileMerging.java +++ b/io/src/main/java/de/haevn/utils/io/merge/IFileMerging.java @@ -7,13 +7,32 @@ import java.util.List; /** - * This is a skeleton class for file merging. + *

      IFileMerging

      + *
      + *

      This interface provides a method signatures for merging files.

      + *
      + *

      It provides the following methods:

      + *
        + *
      • {@link #mergeFiles(File, List)}: Merges the given files into the output file.
      • + *
      • {@link #mergeFiles(File, String...)}: Merges the given files into the output file.
      • + *
      • {@link #mergeFiles(File, File...)}: Merges the given files into the output file.
      • + *
      + *
      + *

      It is recommended to extend the {@link AbstractFileMerging} class when implementing a file merging class.

      + *
      */ public interface IFileMerging { /** - * Merges the given files into the output file. + *

      mergeFiles({@link File}, {@link List})

      + *
      + *

      Merges the given files into the output file.

      + *

      Example:

      + *
      {@code
      +     * final IFileMerging fileMerging = ...;
      +     * fileMerging.mergeFiles(new File("output.txt"), List.of(new File("input1.txt"), new File("input2.txt")));
      +     * }
      * * @param output the output file * @param input the input files @@ -22,7 +41,14 @@ public interface IFileMerging { void mergeFiles(final File output, final List input) throws FileMergeException; /** - * Merges the given files into the output file. + *

      mergeFiles({@link File}, String...)

      + *
      + *

      This method merges the given files into the output file.

      + *

      Example:

      + *
      {@code
      +     * final IFileMerging fileMerging = ...;
      +     * fileMerging.mergeFiles(new File("output.txt"), "input1.txt", "input2.txt");
      +     * }
      * * @param output the output file * @param input the input files @@ -31,7 +57,14 @@ public interface IFileMerging { void mergeFiles(final File output, final String... input) throws FileMergeException; /** - * Merges the given files into the output file. + *

      mergeFiles({@link File}, {@link File}...)

      + *
      + *

      This method merges the given files into the output file.

      + *

      Example:

      + *
      {@code
      +     * final IFileMerging fileMerging = ...;
      +     * fileMerging.mergeFiles(new File("output.txt"), new File("input1.txt"), new File("input2.txt"));
      +     * }
      * * @param output the output file * @param input the input files diff --git a/io/src/main/java/de/haevn/utils/io/merge/PdfMerge.java b/io/src/main/java/de/haevn/utils/io/merge/PdfMerge.java index 7ccd5c6..0f80572 100644 --- a/io/src/main/java/de/haevn/utils/io/merge/PdfMerge.java +++ b/io/src/main/java/de/haevn/utils/io/merge/PdfMerge.java @@ -8,13 +8,35 @@ import java.io.IOException; import java.util.List; - +/** + *

      PdfMerge

      + *
      + *

      This class extends {@link AbstractFileMerging} and provides a method to merge PDF files.

      + *
      + *

      It uses the {@link PDFMergerUtility} from the Apache PDFBox library to merge the files.

      + * + * @author Haevn + * @version 1.0 + * @since 1.0 + */ public class PdfMerge extends AbstractFileMerging { private static final Logger LOGGER = new Logger(PdfMerge.class); /** - * Merges the given files into the output file. + *

      mergeFiles({@link File}, {@link List})

      + *
      + *

      Merges the given files into the output file.

      + *

      Example:

      + *
      {@code
      +     * final PdfMerge pdfMerge = new PdfMerge();
      +     * pdfMerge.mergeFiles(new File("output.pdf"), List.of(new File("input1.pdf"), new File("input2.pdf")));
      +     * }
      + * + *

      When the input is empty, the method will log a message and return.

      + *

      Next it will create a new {@link PDFMergerUtility} and set the destination file to the output file.

      + *

      Then it will add all input files to the merger and merge the documents.

      + *

      If an {@link IOException} occurs, the method will log an error message and throw a {@link FileMergeException}.

      * * @param output the output file * @param input the input files diff --git a/io/src/main/java/de/haevn/utils/io/merge/SimpleFileMerging.java b/io/src/main/java/de/haevn/utils/io/merge/SimpleFileMerging.java index ba6eec6..83d56c7 100644 --- a/io/src/main/java/de/haevn/utils/io/merge/SimpleFileMerging.java +++ b/io/src/main/java/de/haevn/utils/io/merge/SimpleFileMerging.java @@ -10,7 +10,9 @@ /** - * This class provides methods to merge basic files. Extends {@link AbstractFileMerging} + *

      SimpleFileMerging

      + *
      + *

      This class extends {@link AbstractFileMerging} and provides methods to merge files.

      * * @author haevn * @version 1.0 @@ -21,7 +23,18 @@ public final class SimpleFileMerging extends AbstractFileMerging { /** - * Merges the given files into the output file. + *

      mergeFiles({@link File}, {@link List})

      + *
      + *

      Merges the given files into the output file.

      + *

      Example:

      + *
      {@code
      +     * final SimpleFileMerging simpleFileMerging = new SimpleFileMerging();
      +     * simpleFileMerging.mergeFiles(new File("output.txt"), List.of(new File("input1.txt"), new File("input2.txt")));
      +     * }
      + *
      + *

      When the input is empty, the method will log a message and return.

      + *

      Next it will create a new {@link FileOutputStream} and write the content of each input file to the output file.

      + *

      If an {@link IOException} occurs, the method will log an error message and throw a {@link FileMergeException}.

      * * @param output the output file * @param input the input files diff --git a/logger/src/main/java/de/haevn/utils/logging/Level.java b/logger/src/main/java/de/haevn/utils/logging/Level.java index 5651c98..9041610 100644 --- a/logger/src/main/java/de/haevn/utils/logging/Level.java +++ b/logger/src/main/java/de/haevn/utils/logging/Level.java @@ -1,7 +1,8 @@ package de.haevn.utils.logging; /** - * Defines the log levels. + *

      Level

      + *

      This enum represents the different levels of logging that can be used in the logger.

      *