diff --git a/src/main/java/org/fuin/utils4j/Utils4J.java b/src/main/java/org/fuin/utils4j/Utils4J.java index f623105..7ae59e4 100644 --- a/src/main/java/org/fuin/utils4j/Utils4J.java +++ b/src/main/java/org/fuin/utils4j/Utils4J.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2015 Michael Schnell. All rights reserved. + * Copyright (C) 2015 Michael Schnell. All rights reserved. * http://www.fuin.org/ * * This library is free software; you can redistribute it and/or modify it under @@ -22,7 +22,25 @@ import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; -import java.io.*; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.RandomAccessFile; +import java.io.Reader; +import java.io.Writer; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -36,7 +54,16 @@ import java.security.GeneralSecurityException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.Semaphore; +import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Stream; import java.util.zip.ZipEntry; @@ -72,7 +99,7 @@ public final class Utils4J { /** * Used building output as Hex. */ - private static final char[] DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; /** * Private default constructor. @@ -83,10 +110,8 @@ private Utils4J() { /** * Returns the package path of a class. - * - * @param clasz - * Class to determine the path for - Cannot be null. - * + * + * @param clasz Class to determine the path for - Cannot be null. * @return Package path for the class. */ public static String getPackagePath(final Class clasz) { @@ -96,12 +121,9 @@ public static String getPackagePath(final Class clasz) { /** * Get the path to a resource located in the same package as a given class. - * - * @param clasz - * Class with the same package where the resource is located - Cannot be null. - * @param name - * Filename of the resource - Cannot be null. - * + * + * @param clasz Class with the same package where the resource is located - Cannot be null. + * @param name Filename of the resource - Cannot be null. * @return Resource URL. */ public static URL getResource(final Class clasz, final String name) { @@ -113,9 +135,8 @@ public static URL getResource(final Class clasz, final String name) { /** * Check if the argument is an existing file. If the check fails an IllegalArgumentException is thrown. - * - * @param file - * File to check - Cannot be null. + * + * @param file File to check - Cannot be null. */ public static void checkValidFile(final File file) { checkNotNull("file", file); @@ -129,9 +150,8 @@ public static void checkValidFile(final File file) { /** * Check if the argument is an existing directory. If the check fails an IllegalArgumentException is thrown. - * - * @param dir - * Directory to check - Cannot be null. + * + * @param dir Directory to check - Cannot be null. */ public static void checkValidDir(final File dir) { checkNotNull("dir", dir); @@ -145,10 +165,8 @@ public static void checkValidDir(final File dir) { /** * Create an instance with Class.forName(..) and wrap all exceptions into RuntimeExceptions. The class loader of this class is used. - * - * @param className - * Full qualified class name - Cannot be null. - * + * + * @param className Full qualified class name - Cannot be null. * @return New instance of the class. */ public static Object createInstance(final String className) { @@ -157,12 +175,9 @@ public static Object createInstance(final String className) { /** * Create an instance with Class.forName(..) and wrap all exceptions into RuntimeExceptions. - * - * @param className - * Full qualified class name - Cannot be null. - * @param classLoader - * Dedicated class loader to use - Cannot be NULL. - * + * + * @param className Full qualified class name - Cannot be null. + * @param classLoader Dedicated class loader to use - Cannot be NULL. * @return New instance of the class. */ public static Object createInstance(final String className, final ClassLoader classLoader) { @@ -190,12 +205,9 @@ public static Object createInstance(final String className, final ClassLoader cl /** * Checks if the array or URLs contains the given URL. - * - * @param urls - * Array of URLs - Cannot be null. - * @param url - * URL to find - Cannot be null. - * + * + * @param urls Array of URLs - Cannot be null. + * @param url URL to find - Cannot be null. * @return If the URL is in the array TRUE else FALSE. */ public static boolean containsURL(final URL[] urls, final URL url) { @@ -214,10 +226,8 @@ public static boolean containsURL(final URL[] urls, final URL url) { /** * Creates an MD5 hash from a file. - * - * @param file - * File to create an hash for - Cannot be null. - * + * + * @param file File to create an hash for - Cannot be null. * @return Hash as text. */ public static String createHashMD5(final File file) { @@ -226,12 +236,9 @@ public static String createHashMD5(final File file) { /** * Creates a HEX encoded hash from a file. - * - * @param file - * File to create a hash for - Cannot be null. - * @param algorithm - * Hash algorithm like "MD5" or "SHA" - Cannot be null. - * + * + * @param file File to create a hash for - Cannot be null. + * @param algorithm Hash algorithm like "MD5" or "SHA" - Cannot be null. * @return HEX encoded hash. */ public static String createHash(final File file, final String algorithm) { @@ -248,12 +255,9 @@ public static String createHash(final File file, final String algorithm) { /** * Creates a HEX encoded hash from a stream. - * - * @param inputStream - * Stream to create a hash for - Cannot be null. - * @param algorithm - * Hash algorithm like "MD5" or "SHA" - Cannot be null. - * + * + * @param inputStream Stream to create a hash for - Cannot be null. + * @param algorithm Hash algorithm like "MD5" or "SHA" - Cannot be null. * @return HEX encoded hash. */ public static String createHash(final InputStream inputStream, final String algorithm) { @@ -276,22 +280,14 @@ public static String createHash(final InputStream inputStream, final String algo /** * Creates a cipher for encryption or decryption. - * - * @param algorithm - * PBE algorithm like "PBEWithMD5AndDES" or "PBEWithMD5AndTripleDES". - * @param mode - * Encyrption or decyrption. - * @param password - * Password. - * @param salt - * Salt usable with algorithm. - * @param count - * Iterations. - * + * + * @param algorithm PBE algorithm like "PBEWithMD5AndDES" or "PBEWithMD5AndTripleDES". + * @param mode Encyrption or decyrption. + * @param password Password. + * @param salt Salt usable with algorithm. + * @param count Iterations. * @return Ready initialized cipher. - * - * @throws GeneralSecurityException - * Error creating the cipher. + * @throws GeneralSecurityException Error creating the cipher. */ private static Cipher createCipher(final String algorithm, final int mode, final char[] password, final byte[] salt, final int count) throws GeneralSecurityException { @@ -308,22 +304,16 @@ private static Cipher createCipher(final String algorithm, final int mode, final /** * Encrypts some data based on a password. - * - * @param algorithm - * PBE algorithm like "PBEWithMD5AndDES" or "PBEWithMD5AndTripleDES" - Cannot be null. - * @param data - * Data to encrypt - Cannot be null. - * @param password - * Password - Cannot be null. - * @param salt - * Salt usable with algorithm - Cannot be null. - * @param count - * Iterations. - * + * + * @param algorithm PBE algorithm like "PBEWithMD5AndDES" or "PBEWithMD5AndTripleDES" - Cannot be null. + * @param data Data to encrypt - Cannot be null. + * @param password Password - Cannot be null. + * @param salt Salt usable with algorithm - Cannot be null. + * @param count Iterations. * @return Encrypted data. */ public static byte[] encryptPasswordBased(final String algorithm, final byte[] data, final char[] password, final byte[] salt, - final int count) { + final int count) { checkNotNull("algorithm", algorithm); checkNotNull("data", data); @@ -340,22 +330,16 @@ public static byte[] encryptPasswordBased(final String algorithm, final byte[] d /** * Decrypts some data based on a password. - * - * @param algorithm - * PBE algorithm like "PBEWithMD5AndDES" or "PBEWithMD5AndTripleDES" - Cannot be null. - * @param encryptedData - * Data to decrypt - Cannot be null. - * @param password - * Password - Cannot be null. - * @param salt - * Salt usable with algorithm - Cannot be null. - * @param count - * Iterations. - * + * + * @param algorithm PBE algorithm like "PBEWithMD5AndDES" or "PBEWithMD5AndTripleDES" - Cannot be null. + * @param encryptedData Data to decrypt - Cannot be null. + * @param password Password - Cannot be null. + * @param salt Salt usable with algorithm - Cannot be null. + * @param count Iterations. * @return Encrypted data. */ public static byte[] decryptPasswordBased(final String algorithm, final byte[] encryptedData, final char[] password, final byte[] salt, - final int count) { + final int count) { checkNotNull("algorithm", algorithm); checkNotNull("encryptedData", encryptedData); @@ -372,15 +356,11 @@ public static byte[] decryptPasswordBased(final String algorithm, final byte[] e /** * Creates an URL based on a directory a relative path and a filename. - * - * @param baseUrl - * Directory URL with or without slash ("/") at the end of the string - Cannot be null. - * @param path - * Relative path inside the base URL (with or without slash ("/") at the end of the string) - Can be null or an - * empty string. - * @param filename - * Filename without path - Cannot be null. - * + * + * @param baseUrl Directory URL with or without slash ("/") at the end of the string - Cannot be null. + * @param path Relative path inside the base URL (with or without slash ("/") at the end of the string) - Can be null or an + * empty string. + * @param filename Filename without path - Cannot be null. * @return URL. */ public static URL createUrl(final URL baseUrl, final String path, final String filename) { @@ -410,12 +390,9 @@ public static URL createUrl(final URL baseUrl, final String path, final String f /** * Returns a relative path based on a base directory. If the dir is not inside baseDir an * IllegalArgumentException is thrown. - * - * @param baseDir - * Base directory the path is relative to - Cannot be null. - * @param dir - * Directory inside the base directory - Cannot be null. - * + * + * @param baseDir Base directory the path is relative to - Cannot be null. + * @param dir Directory inside the base directory - Cannot be null. * @return Path of dir relative to baseDir. If both are equal an empty string is returned. */ public static String getRelativePath(final File baseDir, final File dir) { @@ -435,12 +412,9 @@ public static String getRelativePath(final File baseDir, final File dir) { /** * Checks if a given file is inside the given directory. - * - * @param dir - * Base directory - Cannot be null. - * @param file - * File - Cannot be null. - * + * + * @param dir Base directory - Cannot be null. + * @param file File - Cannot be null. * @return If the file is inside the directory TRUE, else FALSE. */ public static boolean fileInsideDirectory(final File dir, final File file) { @@ -455,10 +429,8 @@ public static boolean fileInsideDirectory(final File dir, final File file) { /** * Returns the canonical path for the file without throwing a checked exception. A potential {@link IOException} is converted into a * {@link RuntimeException} - * - * @param file - * File to return the canonical path for or null. - * + * + * @param file File to return the canonical path for or null. * @return Canonical path for the given argument or null if the input was null. */ public static String getCanonicalPath(final File file) { @@ -475,10 +447,8 @@ public static String getCanonicalPath(final File file) { /** * Returns the canonical file for the file without throwing a checked exception. A potential {@link IOException} is converted into a * {@link RuntimeException} - * - * @param file - * File to return the canonical file for or null. - * + * + * @param file File to return the canonical file for or null. * @return Canonical file for the given argument or null if the input was null. */ public static File getCanonicalFile(final File file) { @@ -499,12 +469,9 @@ public static File getCanonicalFile(final File file) { * "a/b/c" => "../../.."
* "my-dir" => ".."
* "my-dir/other/" => "../../".
- * - * @param relativePath - * Relative path to convert - Expected to be a directory and NOT a file - Cannot be NULL. - * @param fileSeparatorChar - * See {@link File#separatorChar}. - * + * + * @param relativePath Relative path to convert - Expected to be a directory and NOT a file - Cannot be NULL. + * @param fileSeparatorChar See {@link File#separatorChar}. * @return Relative path with ".." (dot dot) */ public static String getBackToRootPath(final String relativePath, final char fileSeparatorChar) { @@ -528,11 +495,9 @@ public static String getBackToRootPath(final String relativePath, final char fil /** * Checks if a variable is not null and throws an IllegalNullArgumentException if this rule is violated. - * - * @param name - * Name of the variable to be displayed in an error message. - * @param value - * Value to check for null. + * + * @param name Name of the variable to be displayed in an error message. + * @param value Value to check for null. */ public static void checkNotNull(final String name, final Object value) { if (value == null) { @@ -543,11 +508,9 @@ public static void checkNotNull(final String name, final Object value) { /** * Checks if a variable is not empty and throws an IllegalNullArgumentException if this rule is violated. A * String with spaces is NOT considered empty! - * - * @param name - * Name of the variable to be displayed in an error message. - * @param value - * Value to check for an empty String - Cannot be null. + * + * @param name Name of the variable to be displayed in an error message. + * @param value Value to check for an empty String - Cannot be null. */ public static void checkNotEmpty(final String name, final String value) { if (value.length() == 0) { @@ -557,14 +520,10 @@ public static void checkNotEmpty(final String name, final String value) { /** * Creates a textual representation of the method. - * - * @param returnType - * Return type of the method - Can be null. - * @param methodName - * Name of the method - Cannot be null. - * @param argTypes - * The list of parameters - Can be null. - * + * + * @param returnType Return type of the method - Can be null. + * @param methodName Name of the method - Cannot be null. + * @param argTypes The list of parameters - Can be null. * @return Textual signature of the method. */ private static String getMethodSignature(final String returnType, final String methodName, final Class[] argTypes) { @@ -589,20 +548,13 @@ private static String getMethodSignature(final String returnType, final String m /** * Calls a method with reflection and maps all errors into one exception. - * - * @param obj - * The object the underlying method is invoked from - Cannot be null. - * @param methodName - * Name of the Method - Cannot be null. - * @param argTypes - * The list of parameters - May be null. - * @param args - * Arguments the arguments used for the method call - May be null if "argTypes" is also null. - * + * + * @param obj The object the underlying method is invoked from - Cannot be null. + * @param methodName Name of the Method - Cannot be null. + * @param argTypes The list of parameters - May be null. + * @param args Arguments the arguments used for the method call - May be null if "argTypes" is also null. * @return The result of dispatching the method represented by this object on obj with parameters args. - * - * @throws InvokeMethodFailedException - * Invoking the method failed for some reason. + * @throws InvokeMethodFailedException Invoking the method failed for some reason. */ public static Object invoke(final Object obj, final String methodName, final Class[] argTypes, final Object[] args) throws InvokeMethodFailedException { @@ -613,11 +565,11 @@ public static Object invoke(final Object obj, final String methodName, final Cla final Class[] argTypesIntern; final Object[] argsIntern; if (argTypes == null) { - argTypesIntern = new Class[] {}; + argTypesIntern = new Class[]{}; if (args != null) { throw new IllegalArgumentException("The argument 'argTypes' is null but " + "'args' containes values!"); } - argsIntern = new Object[] {}; + argsIntern = new Object[]{}; } else { argTypesIntern = argTypes; if (args == null) { @@ -664,14 +616,10 @@ private static void checkSameLength(final Class[] argTypes, final Object[] ar /** * Unzips a file into a given directory. WARNING: Only relative path entries are allowed inside the archive! - * - * @param zipFile - * Source ZIP file - Cannot be null and must be a valid ZIP file. - * @param destDir - * Destination directory - Cannot be null and must exist. - * - * @throws IOException - * Error unzipping the file. + * + * @param zipFile Source ZIP file - Cannot be null and must be a valid ZIP file. + * @param destDir Destination directory - Cannot be null and must exist. + * @throws IOException Error unzipping the file. */ public static void unzip(final File zipFile, final File destDir) throws IOException { unzip(zipFile, destDir, null, null); @@ -679,19 +627,13 @@ public static void unzip(final File zipFile, final File destDir) throws IOExcept /** * Unzips a file into a given directory. WARNING: Only relative path entries are allowed inside the archive! - * - * @param zipFile - * Source ZIP file - Cannot be null and must be a valid ZIP file. - * @param destDir - * Destination directory - Cannot be null and must exist. - * @param wrapper - * Callback interface to give the caller the chance to wrap the ZIP input stream into another one. This is useful for example - * to display a progress bar - Can be null if no wrapping is required. - * @param cancelable - * Signals if the unzip should be canceled - Can be null if no cancel option is required. - * - * @throws IOException - * Error unzipping the file. + * + * @param zipFile Source ZIP file - Cannot be null and must be a valid ZIP file. + * @param destDir Destination directory - Cannot be null and must exist. + * @param wrapper Callback interface to give the caller the chance to wrap the ZIP input stream into another one. This is useful for example + * to display a progress bar - Can be null if no wrapping is required. + * @param cancelable Signals if the unzip should be canceled - Can be null if no cancel option is required. + * @throws IOException Error unzipping the file. */ public static void unzip(final File zipFile, final File destDir, final UnzipInputStreamWrapper wrapper, final Cancelable cancelable) throws IOException { @@ -741,7 +683,7 @@ private static void createIfNecessary(final File dir) throws IOException { /** * Returns the user home directory and checks if it is valid and exists. If not a IllegalStateException is thrown. - * + * * @return Directory. */ public static File getUserHomeDir() { @@ -765,7 +707,7 @@ public static File getUserHomeDir() { /** * Returns the temporary directory and checks if it is valid and exists. If not a IllegalStateException is thrown. - * + * * @return Directory. */ public static File getTempDir() { @@ -788,12 +730,9 @@ public static File getTempDir() { /** * Replaces all variables inside a string with values from a map. - * - * @param str - * Text with variables (Format: ${key} ) - May be null or empty. - * @param vars - * Map with key/values (both of type String - May be null. - * + * + * @param str Text with variables (Format: ${key} ) - May be null or empty. + * @param vars Map with key/values (both of type String - May be null. * @return String with replaced variables. Unknown variables will remain unchanged. */ public static String replaceVars(final String str, final Map vars) { @@ -837,9 +776,8 @@ public static String replaceVars(final String str, final Map var * Converts Date into a Windows FILETIME. The Windows FILETIME structure holds a date and time associated with a file. The structure * identifies a 64-bit integer specifying the number of 100-nanosecond intervals which have passed since January 1, 1601. This code is * copied from the org.apache.poi.hpsf.Util class. - * - * @param date - * The date to be converted - Cannot be null. + * + * @param date The date to be converted - Cannot be null. * @return The file time */ public static long dateToFileTime(final Date date) { @@ -852,43 +790,31 @@ public static long dateToFileTime(final Date date) { /** * Creates an URL Link on the Windows Desktop. This is done by creating a file (URL File Format) with an ".url" extension. For a * description see http://www.cyanwerks.com/file-format-url.html . - * - * @param baseUrl - * Base URL for the link - Cannot be null or empty. - * @param url - * Target URL - Cannot be null or empty. - * @param workingDir - * It's the "working folder" that your URL file uses. The working folder is possibly the folder to be set as the current - * folder for the application that would open the file. However Internet Explorer does not seem to be affected by this field - * - Can be null. - * @param showCommand - * Normal=null, Minimized=7, Maximized=3 - * @param iconIndex - * The Icon Index within the icon library specified by IconFile. In an icon library, which can be generally be either a ICO, - * DLL or EXE file, the icons are indexed with numbers. The first icon index starts at 0 - Can be null if the - * file is not indexed. - * @param iconFile - * Specifies the path of the icon library file. Generally the icon library can be an ICO, DLL or EXE file. The default icon - * library used tends to be the URL.DLL library on the system's Windows\System directory - Can be null if no - * icon is required. - * @param hotKey - * The HotKey field specifies what is the shortcut key used to automatically launch the Internet shortcut. The field uses a - * number to specify what hotkey is used. To get the appropriate code simply create a shortcut with MSIE and examine the - * file's content. - * @param linkFilenameWithoutExtension - * Name for the link file (displayed as text) - Cannot be null or empty. - * @param overwrite - * Overwrite an existing ".url" file. - * @param modified - * Timestamp. - * - * @throws IOException - * Error writing the file. + * + * @param baseUrl Base URL for the link - Cannot be null or empty. + * @param url Target URL - Cannot be null or empty. + * @param workingDir It's the "working folder" that your URL file uses. The working folder is possibly the folder to be set as the current + * folder for the application that would open the file. However Internet Explorer does not seem to be affected by this field + * - Can be null. + * @param showCommand Normal=null, Minimized=7, Maximized=3 + * @param iconIndex The Icon Index within the icon library specified by IconFile. In an icon library, which can be generally be either a ICO, + * DLL or EXE file, the icons are indexed with numbers. The first icon index starts at 0 - Can be null if the + * file is not indexed. + * @param iconFile Specifies the path of the icon library file. Generally the icon library can be an ICO, DLL or EXE file. The default icon + * library used tends to be the URL.DLL library on the system's Windows\System directory - Can be null if no + * icon is required. + * @param hotKey The HotKey field specifies what is the shortcut key used to automatically launch the Internet shortcut. The field uses a + * number to specify what hotkey is used. To get the appropriate code simply create a shortcut with MSIE and examine the + * file's content. + * @param linkFilenameWithoutExtension Name for the link file (displayed as text) - Cannot be null or empty. + * @param overwrite Overwrite an existing ".url" file. + * @param modified Timestamp. + * @throws IOException Error writing the file. */ // CHECKSTYLE:OFF Maximum Parameters public static void createWindowsDesktopUrlLink(final String baseUrl, final String url, final File workingDir, final Integer showCommand, - final Integer iconIndex, final File iconFile, final Integer hotKey, final String linkFilenameWithoutExtension, - final boolean overwrite, final Date modified) throws IOException { + final Integer iconIndex, final File iconFile, final Integer hotKey, final String linkFilenameWithoutExtension, + final boolean overwrite, final Date modified) throws IOException { // CHECKSTYLE:ON checkNotNull("baseUrl", baseUrl); @@ -916,37 +842,28 @@ public static void createWindowsDesktopUrlLink(final String baseUrl, final Strin /** * Creates the content of an URL Link file (.url) on the Windows Desktop. For a description see * http://www.cyanwerks.com/file-format-url.html . - * - * @param baseUrl - * Base URL for the link - Cannot be null or empty. - * @param url - * Target URL - Cannot be null or empty. - * @param workingDir - * It's the "working folder" that your URL file uses. The working folder is possibly the folder to be set as the current - * folder for the application that would open the file. However Internet Explorer does not seem to be affected by this field - * - Can be null. - * @param showCommand - * Normal=null, Minimized=7, Maximized=3 - * @param iconIndex - * The Icon Index within the icon library specified by IconFile. In an icon library, which can be generally be either a ICO, - * DLL or EXE file, the icons are indexed with numbers. The first icon index starts at 0 - Can be null if the - * file is not indexed. - * @param iconFile - * Specifies the path of the icon library file. Generally the icon library can be an ICO, DLL or EXE file. The default icon - * library used tends to be the URL.DLL library on the system's Windows\System directory - Can be null if no - * icon is required. - * @param hotKey - * The HotKey field specifies what is the shortcut key used to automatically launch the Internet shortcut. The field uses a - * number to specify what hotkey is used. To get the appropriate code simply create a shortcut with MSIE and examine the - * file's content. - * @param modified - * Timestamp. - * + * + * @param baseUrl Base URL for the link - Cannot be null or empty. + * @param url Target URL - Cannot be null or empty. + * @param workingDir It's the "working folder" that your URL file uses. The working folder is possibly the folder to be set as the current + * folder for the application that would open the file. However Internet Explorer does not seem to be affected by this field + * - Can be null. + * @param showCommand Normal=null, Minimized=7, Maximized=3 + * @param iconIndex The Icon Index within the icon library specified by IconFile. In an icon library, which can be generally be either a ICO, + * DLL or EXE file, the icons are indexed with numbers. The first icon index starts at 0 - Can be null if the + * file is not indexed. + * @param iconFile Specifies the path of the icon library file. Generally the icon library can be an ICO, DLL or EXE file. The default icon + * library used tends to be the URL.DLL library on the system's Windows\System directory - Can be null if no + * icon is required. + * @param hotKey The HotKey field specifies what is the shortcut key used to automatically launch the Internet shortcut. The field uses a + * number to specify what hotkey is used. To get the appropriate code simply create a shortcut with MSIE and examine the + * file's content. + * @param modified Timestamp. * @return INI file text. */ // CHECKSTYLE:OFF public static String createWindowsDesktopUrlLinkContent(final String baseUrl, final String url, final File workingDir, - final Integer showCommand, final Integer iconIndex, final File iconFile, final Integer hotKey, final Date modified) { + final Integer showCommand, final Integer iconIndex, final File iconFile, final Integer hotKey, final Date modified) { // CHECKSTYLE:ON checkNotNull("baseUrl", baseUrl); @@ -983,14 +900,10 @@ public static String createWindowsDesktopUrlLinkContent(final String baseUrl, fi /** * Concatenate a path and a filename taking null and empty string values into account. - * - * @param path - * Path - Can be null or an empty string. - * @param filename - * Filename - Cannot be null. - * @param separator - * Separator for directories - Can be null or an empty string. - * + * + * @param path Path - Can be null or an empty string. + * @param filename Filename - Cannot be null. + * @param separator Separator for directories - Can be null or an empty string. * @return Path and filename divided by the separator. */ public static String concatPathAndFilename(final String path, final String filename, final String separator) { @@ -1017,12 +930,10 @@ public static String concatPathAndFilename(final String path, final String filen /** * Converts an array of bytes into an array of characters representing the hexidecimal values of each byte in order. The returned array * will be double the length of the passed array, as it takes two characters to represent any given byte. - * + *

* Author: Apache Software Foundation See: org.apache.commons.codec.binary.Hex - * - * @param data - * A byte[] to convert to Hex characters - Cannot be null. - * + * + * @param data A byte[] to convert to Hex characters - Cannot be null. * @return A string containing hexidecimal characters */ // CHECKSTYLE:OFF Orginal Apache code @@ -1047,13 +958,11 @@ public static String encodeHex(final byte[] data) { * Converts an array of characters representing hexidecimal values into an array of bytes of those same values. The returned array will * be half the length of the passed array, as it takes two characters to represent any given byte. An exception is thrown if the passed * char array has an odd number of elements. - * - * @param data - * An array of characters containing hexidecimal digits - Cannot be null. - * + * + * @param data An array of characters containing hexidecimal digits - Cannot be null. * @return A byte array containing binary data decoded from the supplied char array. - * - * Author: Apache Software Foundation See: org.apache.commons.codec.binary.Hex + *

+ * Author: Apache Software Foundation See: org.apache.commons.codec.binary.Hex */ // CHECKSTYLE:OFF Orginal Apache code public static byte[] decodeHex(final String data) { @@ -1084,13 +993,10 @@ public static byte[] decodeHex(final String data) { /** * Converts a hexadecimal character to an integer. - * - * @param ch - * A character to convert to an integer digit - * @param index - * The index of the character in the source + * + * @param ch A character to convert to an integer digit + * @param index The index of the character in the source * @return An integer - * * @author Apache Software Foundation * @see org.apache.commons.codec.binary.Hex */ @@ -1104,18 +1010,12 @@ private static int toDigit(final char ch, final int index) { /** * Lock the file. - * - * @param file - * File to lock - Cannot be null. - * @param tryLockMax - * Number of tries to lock before throwing an exception. - * @param tryWaitMillis - * Milliseconds to sleep between retries. - * + * + * @param file File to lock - Cannot be null. + * @param tryLockMax Number of tries to lock before throwing an exception. + * @param tryWaitMillis Milliseconds to sleep between retries. * @return FileLock. - * - * @throws LockingFailedException - * Locking the file failed. + * @throws LockingFailedException Locking the file failed. */ public static FileLock lockRandomAccessFile(final RandomAccessFile file, final int tryLockMax, final long tryWaitMillis) throws LockingFailedException { @@ -1153,16 +1053,11 @@ private static void ignore() { /** * Adds a file to a ZIP output stream. - * - * @param srcFile - * File to add - Cannot be null. - * @param destPath - * Path to use for the file - May be null or empty. - * @param out - * Destination stream - Cannot be null. - * - * @throws IOException - * Error writing to the output stream. + * + * @param srcFile File to add - Cannot be null. + * @param destPath Path to use for the file - May be null or empty. + * @param out Destination stream - Cannot be null. + * @throws IOException Error writing to the output stream. */ private static void zipFile(final File srcFile, final String destPath, final ZipOutputStream out) throws IOException { @@ -1181,12 +1076,9 @@ private static void zipFile(final File srcFile, final String destPath, final Zip /** * List all files for a directory. - * - * @param srcDir - * Directory to list the files for - Cannot be null and must be a valid directory. - * @param filter - * Filter or null for all files. - * + * + * @param srcDir Directory to list the files for - Cannot be null and must be a valid directory. + * @param filter Filter or null for all files. * @return List of child entries of the directory. */ private static File[] listFiles(final File srcDir, final FileFilter filter) { @@ -1203,18 +1095,12 @@ private static File[] listFiles(final File srcDir, final FileFilter filter) { /** * Add a directory to a ZIP output stream. - * - * @param srcDir - * Directory to add - Cannot be null and must be a valid directory. - * @param filter - * Filter or null for all files. - * @param destPath - * Path to use for the ZIP archive - May be null or an empyt string. - * @param out - * Destination stream - Cannot be null. - * - * @throws IOException - * Error writing to the output stream. + * + * @param srcDir Directory to add - Cannot be null and must be a valid directory. + * @param filter Filter or null for all files. + * @param destPath Path to use for the ZIP archive - May be null or an empyt string. + * @param out Destination stream - Cannot be null. + * @throws IOException Error writing to the output stream. */ private static void zipDir(final File srcDir, final FileFilter filter, final String destPath, final ZipOutputStream out) throws IOException { @@ -1233,18 +1119,12 @@ private static void zipDir(final File srcDir, final FileFilter filter, final Str /** * Creates a ZIP file and adds all files in a directory and all it's sub directories to the archive. Only entries are added that comply * to the file filter. - * - * @param srcDir - * Directory to add - Cannot be null and must be a valid directory. - * @param filter - * Filter or null for all files/directories. - * @param destPath - * Path to use for the ZIP archive - May be null or an empyt string. - * @param destFile - * Target ZIP file - Cannot be null. - * - * @throws IOException - * Error writing to the output stream. + * + * @param srcDir Directory to add - Cannot be null and must be a valid directory. + * @param filter Filter or null for all files/directories. + * @param destPath Path to use for the ZIP archive - May be null or an empyt string. + * @param destFile Target ZIP file - Cannot be null. + * @throws IOException Error writing to the output stream. */ public static void zipDir(final File srcDir, final FileFilter filter, final String destPath, final File destFile) throws IOException { @@ -1260,16 +1140,11 @@ public static void zipDir(final File srcDir, final FileFilter filter, final Stri /** * Creates a ZIP file and adds all files in a directory and all it's sub directories to the archive. - * - * @param srcDir - * Directory to add - Cannot be null and must be a valid directory. - * @param destPath - * Path to use for the ZIP archive - May be null or an empyt string. - * @param destFile - * Target ZIP file - Cannot be null. - * - * @throws IOException - * Error writing to the output stream. + * + * @param srcDir Directory to add - Cannot be null and must be a valid directory. + * @param destPath Path to use for the ZIP archive - May be null or an empyt string. + * @param destFile Target ZIP file - Cannot be null. + * @throws IOException Error writing to the output stream. */ public static void zipDir(final File srcDir, final String destPath, final File destFile) throws IOException { @@ -1279,10 +1154,8 @@ public static void zipDir(final File srcDir, final String destPath, final File d /** * Serializes the given object. A null argument returns null. - * - * @param obj - * Object to serialize or null. - * + * + * @param obj Object to serialize or null. * @return Serialized object or null. */ public static byte[] serialize(final Object obj) { @@ -1300,14 +1173,10 @@ public static byte[] serialize(final Object obj) { /** * Deserializes a byte array to an object. A null argument returns null. - * - * @param data - * Byte array to deserialize or null. - * + * + * @param data Byte array to deserialize or null. + * @param Type of returned data. * @return Object created from data or null. - * - * @param - * Type of returned data. */ @SuppressWarnings("unchecked") public static T deserialize(final byte[] data) { @@ -1324,14 +1193,10 @@ public static T deserialize(final byte[] data) { /** * Reads a given URL and returns the content as String. - * - * @param url - * URL to read. - * @param encoding - * Encoding (like 'utf-8'). - * @param bufSize - * Size of the buffer to use. - * + * + * @param url URL to read. + * @param encoding Encoding (like 'utf-8'). + * @param bufSize Size of the buffer to use. * @return File content as String. */ public static String readAsString(final URL url, final String encoding, final int bufSize) { @@ -1350,10 +1215,8 @@ public static String readAsString(final URL url, final String encoding, final in /** * Returns a given string as URL and supports "classpath:" scheme. A null argument returns null. - * - * @param url - * String to convert into an URL or null. - * + * + * @param url String to convert into an URL or null. * @return URL or null */ public static URL url(final String url) { @@ -1372,10 +1235,8 @@ public static URL url(final String url) { /** * Replaces the strings "\r", "\n" and "\t" with "carriage return", "new line" and "tab" character. - * - * @param str - * String to replace or null. - * + * + * @param str String to replace or null. * @return Replaced string or null. */ public static String replaceCrLfTab(final String str) { @@ -1411,9 +1272,8 @@ public static String replaceCrLfTab(final String str) { * Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the * precision and accuracy of system timers and schedulers. The thread does not lose ownership of any monitors. The * {@link InterruptedException} is wrapped into a {@link RuntimeException}. - * - * @param millis - * The length of time to sleep in milliseconds. + * + * @param millis The length of time to sleep in milliseconds. */ public static void sleep(final long millis) { try { @@ -1425,12 +1285,9 @@ public static void sleep(final long millis) { /** * Verifies if the cause of an exception is of a given type. - * - * @param actualException - * Actual exception that was caused by something else - Cannot be null. - * @param expectedExceptions - * Expected exceptions - May be null if any cause is expected. - * + * + * @param actualException Actual exception that was caused by something else - Cannot be null. + * @param expectedExceptions Expected exceptions - May be null if any cause is expected. * @return TRUE if the actual exception is one of the expected exceptions. */ public static boolean expectedCause(final Exception actualException, final Collection> expectedExceptions) { @@ -1454,16 +1311,13 @@ public static boolean expectedCause(final Exception actualException, final Colle /** * Verifies if an exception is of a given type. - * - * @param actualException - * Actual exception - Cannot be null. - * @param expectedExceptions - * Expected exceptions - May be null if any exception is expected. - * + * + * @param actualException Actual exception - Cannot be null. + * @param expectedExceptions Expected exceptions - May be null if any exception is expected. * @return TRUE if the actual exception is one of the expected exceptions. */ public static boolean expectedException(final Exception actualException, - final Collection> expectedExceptions) { + final Collection> expectedExceptions) { checkNotNull("actualException", actualException); @@ -1484,10 +1338,8 @@ public static boolean expectedException(final Exception actualException, /** * Determines if the file is a file from the Java runtime and exists. - * - * @param file - * File to test. - * + * + * @param file File to test. * @return TRUE if the file is in the 'java.home' directory. */ public static boolean jreFile(final File file) { @@ -1501,10 +1353,8 @@ public static boolean jreFile(final File file) { /** * Determines if the file is a class file. - * - * @param file - * File to test. - * + * + * @param file File to test. * @return TRUE if the file ends with '.class'. */ public static boolean classFile(final File file) { @@ -1513,10 +1363,8 @@ public static boolean classFile(final File file) { /** * Determines if the file is a JAR file. - * - * @param file - * File to test. - * + * + * @param file File to test. * @return TRUE if the file ends with '.jar'. */ public static boolean jarFile(final File file) { @@ -1525,10 +1373,8 @@ public static boolean jarFile(final File file) { /** * Determines if the file is a JAR file not located in the JRE directory. - * - * @param file - * File to test. - * + * + * @param file File to test. * @return TRUE if the file ends with '.jar' and is not located in the 'java.home' directory. */ public static boolean nonJreJarFile(final File file) { @@ -1537,10 +1383,8 @@ public static boolean nonJreJarFile(final File file) { /** * Determines if the file is a JAR file located in the JRE directory. - * - * @param file - * File to test. - * + * + * @param file File to test. * @return TRUE if the file ends with '.jar' and is located in the 'java.home' directory. */ public static boolean jreJarFile(final File file) { @@ -1549,10 +1393,8 @@ public static boolean jreJarFile(final File file) { /** * Returns a list of filtered files from the classpath including content of directories and sub directories. - * - * @param predicate - * Condition that returns files from the classpath. - * + * + * @param predicate Condition that returns files from the classpath. * @return List of files in the classpath (from property "java.class.path"). */ public static List classpathFiles(final Predicate predicate) { @@ -1562,7 +1404,7 @@ public static List classpathFiles(final Predicate predicate) { /** * Returns a list of all files from the classpath. Only returns the files itself and no files in directories. - * + * * @return List of files in the classpath (from property "java.class.path"). */ public static List classpathFiles() { @@ -1577,11 +1419,8 @@ public static List classpathFiles() { /** * Returns a list of files from all given paths. * - * @param paths - * Paths to search (Paths separated by {@link File#pathSeparator}. - * @param predicate - * Condition for files to return. - * + * @param paths Paths to search (Paths separated by {@link File#pathSeparator}. + * @param predicate Condition for files to return. * @return List of files in the given paths. */ public static List pathsFiles(final String paths, final Predicate predicate) { @@ -1610,14 +1449,10 @@ public static interface UnzipInputStreamWrapper { /** * Wraps the input stream into another one. - * - * @param in - * Stream to create a wrapping stream for. - * @param entry - * Zip entry the input stream is reading. - * @param destFile - * Destination file. - * + * + * @param in Stream to create a wrapping stream for. + * @param entry Zip entry the input stream is reading. + * @param destFile Destination file. * @return Wrapped input stream. */ public InputStream wrapInputStream(InputStream in, ZipEntry entry, File destFile); @@ -1628,7 +1463,6 @@ public static interface UnzipInputStreamWrapper { * Loads the class using the current thread's context class loader. * * @param name Name of the class to load. - * * @return Loaded class. */ public static Class loadClass(String name) { @@ -1642,12 +1476,9 @@ public static Class loadClass(String name) { /** * Sets a private field in an object by using reflection. * - * @param obj - * Object with the attribute to set. - * @param name - * Name of the attribute to set. - * @param value - * Value to set for the attribute. + * @param obj Object with the attribute to set. + * @param name Name of the attribute to set. + * @param value Value to set for the attribute. */ public static void setPrivateField(final Object obj, final String name, final Object value) { try { @@ -1659,4 +1490,49 @@ public static void setPrivateField(final Object obj, final String name, final Ob } } + /** + * Tries to acquire a lock and runs the code. If no lock can be acquired, the method + * terminates immediately without executing anything. + * + * @param lock Semaphore to use. Must be a {@literal null} value. + * @param code Code to run. Must be a {@literal null} value. + */ + public static void tryLocked(final Semaphore lock, final Runnable code) { + Objects.requireNonNull(lock, "lock==null"); + Objects.requireNonNull(code, "code==null"); + if (lock.tryAcquire()) { + try { + code.run(); + } finally { + lock.release(); + } + } + } + + /** + * Waits until a lock is available and executes the code after it was acquired. + * + * @param lock Semaphore to use. Must be a {@literal null} value. + * @param code Code to run. Must be a {@literal null} value. + * @param failedToLockListener Gets informed in case it was not possible to get a lock. May be {@literal null}. + */ + public static void runLocked(final Semaphore lock, + final Runnable code, + final Consumer failedToLockListener) { + Objects.requireNonNull(lock, "lock==null"); + Objects.requireNonNull(code, "code==null"); + try { + lock.acquire(); + try { + code.run(); + } finally { + lock.release(); + } + } catch (final InterruptedException ex) { // NOSONAR + if (failedToLockListener != null) { + failedToLockListener.accept(ex); + } + } + } + } diff --git a/src/test/java/org/fuin/utils4j/Utils4JTest.java b/src/test/java/org/fuin/utils4j/Utils4JTest.java index 85ac80c..fbb1714 100644 --- a/src/test/java/org/fuin/utils4j/Utils4JTest.java +++ b/src/test/java/org/fuin/utils4j/Utils4JTest.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2015 Michael Schnell. All rights reserved. + * Copyright (C) 2015 Michael Schnell. All rights reserved. * http://www.fuin.org/ * * This library is free software; you can redistribute it and/or modify it under @@ -11,7 +11,7 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see http://www.gnu.org/licenses/. */ @@ -29,10 +29,21 @@ import java.net.MalformedURLException; import java.net.URL; import java.nio.channels.FileLock; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; +import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.AssertionsKt.fail; /** * Tests for Utils4J. @@ -211,7 +222,7 @@ public final void testCreateInstanceIllegalAccess() { @Test public final void testContainsURL() throws IOException { - final URL[] urls = new URL[] { new URL("http://www.google.com"), new URL("http://www.yahoo.com"), new URL("file:/foobar.txt") }; + final URL[] urls = new URL[]{new URL("http://www.google.com"), new URL("http://www.yahoo.com"), new URL("file:/foobar.txt")}; assertThat(Utils4J.containsURL(urls, new URL("http://www.google.com"))).isTrue(); assertThat(Utils4J.containsURL(urls, new URL("http://www.google.com/"))).isFalse(); assertThat(Utils4J.containsURL(urls, new URL("http://www.abc.com"))).isFalse(); @@ -298,14 +309,14 @@ public final void testCheckNotEmptyFail() { @Test public final void testInvokeOK() throws InvokeMethodFailedException { - assertThat(Utils4J.invoke(new IllegalNullArgumentException("abc"), "getArgument", new Class[] {}, new Object[] {})) + assertThat(Utils4J.invoke(new IllegalNullArgumentException("abc"), "getArgument", new Class[]{}, new Object[]{})) .isEqualTo("abc"); } @Test public final void testInvokeFail() throws InvokeMethodFailedException { assertThatThrownBy(() -> { - Utils4J.invoke(new IllegalNullArgumentException("abc"), "getArgument", new Class[] { String.class }, new Object[] { "" }); + Utils4J.invoke(new IllegalNullArgumentException("abc"), "getArgument", new Class[]{String.class}, new Object[]{""}); }).isInstanceOf(InvokeMethodFailedException.class); } @@ -524,8 +535,8 @@ public final void testEncryptDecryptPasswordBased() { final String str1 = "This is a secret text 1234567890-ÄÖÜäöüß"; final byte[] data1 = str1.getBytes(); final char[] password = "MyVerySecretPw!".toCharArray(); - final byte[] salt = new byte[] { (byte) 0xc7, (byte) 0x73, (byte) 0x21, (byte) 0x8c, (byte) 0x7e, (byte) 0xc8, (byte) 0xee, - (byte) 0x99 }; + final byte[] salt = new byte[]{(byte) 0xc7, (byte) 0x73, (byte) 0x21, (byte) 0x8c, (byte) 0x7e, (byte) 0xc8, (byte) 0xee, + (byte) 0x99}; final int count = 100; final byte[] encrypted = Utils4J.encryptPasswordBased(algorithm, data1, password, salt, count); @@ -670,7 +681,7 @@ private static class ExceptionContainer { /** * Create a runnable that locks the file. - * + * * @param file * File to lock. * @param ec @@ -681,11 +692,11 @@ private static class ExceptionContainer { * Milliseconds to sleep between retries. * @param sleepMillis * Number of milliseconds to hold the lock. - * + * * @return New runnable instance. */ private Runnable createLockRunnable(final File file, final ExceptionContainer ec, final int tryLockMax, final long tryWaitMillis, - final long sleepMillis) { + final long sleepMillis) { return new Runnable() { @Override public void run() { @@ -711,7 +722,7 @@ public void run() { /** * Start the two threads and wait until both finished. - * + * * @param thread1 * First thread. * @param thread2 @@ -903,6 +914,90 @@ public final void testSetPrivateField() { } + @Test + public final void testTryLockedOK() { + + // PREPARE + final Semaphore semaphore = new Semaphore(1); + final AtomicBoolean executed = new AtomicBoolean(); + + // TEST + Utils4J.tryLocked(semaphore, () -> executed.set(true)); + + // VERIFY + assertThat(executed.get()).isTrue(); + + } + + + @Test + public final void testTryLockedFails() { + + // PREPARE + final Semaphore semaphore = new Semaphore(1); + final AtomicBoolean executed = new AtomicBoolean(); + + Utils4J.runLocked(semaphore, () -> { + + // TEST + Utils4J.tryLocked(semaphore, () -> executed.set(true)); + + // VERIFY + assertThat(executed.get()).isFalse(); + + }, ex -> fail("First lock is not expected to fail", ex)); + + } + + @Test + public final void testRunLockedOK() { + + // PREPARE + final Semaphore semaphore = new Semaphore(1); + final AtomicBoolean executed = new AtomicBoolean(); + + // TEST + Utils4J.runLocked(semaphore, () -> executed.set(true), ex -> fail("Lock is not expected to fail", ex)); + + // VERIFY + assertThat(executed.get()).isTrue(); + + } + + + @Test + public final void testRunLockedFails() { + + // PREPARE + final List executionOrder = Collections.synchronizedList(new ArrayList<>()); + final Semaphore semaphore = new Semaphore(1); + final AtomicReference firstFailed = new AtomicReference<>(); + final Thread t1 = new Thread(() -> { + Utils4J.runLocked(semaphore, () -> { + executionOrder.add("1A"); + Utils4J.sleep(2000); + executionOrder.add("1B"); + }, firstFailed::set); + }); + t1.start(); + + final AtomicBoolean secondExecuted = new AtomicBoolean(); + final AtomicReference secondFailed = new AtomicReference<>(); + + // TEST + Utils4J.sleep(1000); // Wait until 1st thread started + executionOrder.add("2A"); + Utils4J.runLocked(semaphore, () -> secondExecuted.set(true), secondFailed::set); + executionOrder.add("2B"); + + // VERIFY + assertThat(firstFailed.get()).isNull(); + assertThat(secondFailed.get()).isNull(); + assertThat(secondExecuted.get()).isTrue(); + assertThat(executionOrder).containsExactly("1A", "2A", "1B", "2B"); + + } + private static class MyTestClass { private String name;