From: Mathieu Baudier Date: Wed, 28 Oct 2020 08:22:31 +0000 (+0100) Subject: Document and clarify Argeo Util. X-Git-Tag: argeo-commons-2.1.89~50 X-Git-Url: http://git.argeo.org/?p=lgpl%2Fargeo-commons.git;a=commitdiff_plain;h=986233dff943b24e545caecaa4658639c36172eb Document and clarify Argeo Util. --- diff --git a/org.argeo.util/src/org/argeo/util/CsvParser.java b/org.argeo.util/src/org/argeo/util/CsvParser.java index 1f52e986e..277417059 100644 --- a/org.argeo.util/src/org/argeo/util/CsvParser.java +++ b/org.argeo.util/src/org/argeo/util/CsvParser.java @@ -4,6 +4,9 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -22,42 +25,61 @@ public abstract class CsvParser { /** * Actually process a parsed line. If - * {@link #setStrictLineAsLongAsHeader(Boolean)} is true (default) the - * header and the tokens are guaranteed to have the same size. + * {@link #setStrictLineAsLongAsHeader(Boolean)} is true (default) the header + * and the tokens are guaranteed to have the same size. * - * @param lineNumber - * the current line number, starts at 1 (the header, if header - * processing is enabled, the first line otherwise) - * @param header - * the read-only header or null if {@link #setNoHeader(Boolean)} - * is true (default is false) - * @param tokens - * the parsed tokens + * @param lineNumber the current line number, starts at 1 (the header, if header + * processing is enabled, the first line otherwise) + * @param header the read-only header or null if + * {@link #setNoHeader(Boolean)} is true (default is false) + * @param tokens the parsed tokens */ - protected abstract void processLine(Integer lineNumber, - List header, List tokens); + protected abstract void processLine(Integer lineNumber, List header, List tokens); /** * Parses the CSV file (stream is closed at the end) */ public synchronized void parse(InputStream in) { - parse(in, null); + parse(in, (Charset) null); } /** * Parses the CSV file (stream is closed at the end) */ public synchronized void parse(InputStream in, String encoding) { - BufferedReader reader = null; + Reader reader; + if (encoding == null) + reader = new InputStreamReader(in); + else + try { + reader = new InputStreamReader(in, encoding); + } catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException(e); + } + parse(reader); + } + + /** + * Parses the CSV file (stream is closed at the end) + */ + public synchronized void parse(InputStream in, Charset charset) { + Reader reader; + if (charset == null) + reader = new InputStreamReader(in); + else + reader = new InputStreamReader(in, charset); + parse(reader); + } + + /** + * Parses the CSV file (stream is closed at the end) + */ + public synchronized void parse(Reader r) { Integer lineCount = 0; - try { - if (encoding == null) - reader = new BufferedReader(new InputStreamReader(in)); - else - reader = new BufferedReader(new InputStreamReader(in, encoding)); + try (BufferedReader bufferedReader = new BufferedReader(r)) { List header = null; if (!noHeader) { - String headerStr = reader.readLine(); + String headerStr = bufferedReader.readLine(); if (headerStr == null)// empty file return; lineCount++; @@ -65,7 +87,7 @@ public abstract class CsvParser { StringBuffer currStr = new StringBuffer(""); Boolean wasInquote = false; while (parseLine(headerStr, header, currStr, wasInquote)) { - headerStr = reader.readLine(); + headerStr = bufferedReader.readLine(); if (headerStr == null) break; wasInquote = true; @@ -74,7 +96,7 @@ public abstract class CsvParser { } String line = null; - lines: while ((line = reader.readLine()) != null) { + lines: while ((line = bufferedReader.readLine()) != null) { line = preProcessLine(line); if (line == null) { // skip line @@ -85,7 +107,7 @@ public abstract class CsvParser { StringBuffer currStr = new StringBuffer(""); Boolean wasInquote = false; sublines: while (parseLine(line, tokens, currStr, wasInquote)) { - line = reader.readLine(); + line = bufferedReader.readLine(); if (line == null) break sublines; wasInquote = true; @@ -96,29 +118,22 @@ public abstract class CsvParser { if (tokenSize == 1 && line.trim().equals("")) continue lines;// empty line if (headerSize != tokenSize) { - throw new UtilsException("Token size " + tokenSize - + " is different from header size " - + headerSize + " at line " + lineCount - + ", line: " + line + ", header: " + header + throw new IllegalStateException("Token size " + tokenSize + " is different from header size " + + headerSize + " at line " + lineCount + ", line: " + line + ", header: " + header + ", tokens: " + tokens); } } processLine(lineCount, header, tokens); } - } catch (UtilsException e) { - throw e; } catch (IOException e) { - throw new UtilsException("Cannot parse CSV file (line: " - + lineCount + ")", e); - } finally { - StreamUtils.closeQuietly(reader); + throw new RuntimeException("Cannot parse CSV file (line: " + lineCount + ")", e); } } /** - * Called before each (logical) line is processed, giving a change to modify - * it (typically for cleaning dirty files). To be overridden, return the - * line unchanged by default. Skip the line if 'null' is returned. + * Called before each (logical) line is processed, giving a change to modify it + * (typically for cleaning dirty files). To be overridden, return the line + * unchanged by default. Skip the line if 'null' is returned. */ protected String preProcessLine(String line) { return line; @@ -129,8 +144,7 @@ public abstract class CsvParser { * * @return whether to continue parsing this line */ - protected Boolean parseLine(String str, List tokens, - StringBuffer currStr, Boolean wasInquote) { + protected Boolean parseLine(String str, List tokens, StringBuffer currStr, Boolean wasInquote) { // List tokens = new ArrayList(); // System.out.println("#LINE: " + str); @@ -209,8 +223,7 @@ public abstract class CsvParser { return strictLineAsLongAsHeader; } - public synchronized void setStrictLineAsLongAsHeader( - Boolean strictLineAsLongAsHeader) { + public synchronized void setStrictLineAsLongAsHeader(Boolean strictLineAsLongAsHeader) { this.strictLineAsLongAsHeader = strictLineAsLongAsHeader; } diff --git a/org.argeo.util/src/org/argeo/util/CsvParserWithLinesAsMap.java b/org.argeo.util/src/org/argeo/util/CsvParserWithLinesAsMap.java index 68fe8ad00..8eb6e9463 100644 --- a/org.argeo.util/src/org/argeo/util/CsvParserWithLinesAsMap.java +++ b/org.argeo.util/src/org/argeo/util/CsvParserWithLinesAsMap.java @@ -13,19 +13,15 @@ public abstract class CsvParserWithLinesAsMap extends CsvParser { /** * Actually processes a line. * - * @param lineNumber - * the current line number, starts at 1 (the header, if header - * processing is enabled, the first lien otherwise) - * @param line - * the parsed tokens as a map whose keys are the header fields + * @param lineNumber the current line number, starts at 1 (the header, if header + * processing is enabled, the first lien otherwise) + * @param line the parsed tokens as a map whose keys are the header fields */ - protected abstract void processLine(Integer lineNumber, - Map line); + protected abstract void processLine(Integer lineNumber, Map line); - protected final void processLine(Integer lineNumber, List header, - List tokens) { + protected final void processLine(Integer lineNumber, List header, List tokens) { if (header == null) - throw new UtilsException("Only CSV with header is supported"); + throw new IllegalArgumentException("Only CSV with header is supported"); Map line = new HashMap(); for (int i = 0; i < header.size(); i++) { String key = header.get(i); diff --git a/org.argeo.util/src/org/argeo/util/CsvWriter.java b/org.argeo.util/src/org/argeo/util/CsvWriter.java index ba5b3c710..97b519103 100644 --- a/org.argeo.util/src/org/argeo/util/CsvWriter.java +++ b/org.argeo.util/src/org/argeo/util/CsvWriter.java @@ -18,8 +18,7 @@ public class CsvWriter { /** * Creates a CSV writer. * - * @param out - * the stream to write to. Caller is responsible for closing it. + * @param out the stream to write to. Caller is responsible for closing it. */ public CsvWriter(OutputStream out) { this.out = new OutputStreamWriter(out); @@ -28,21 +27,19 @@ public class CsvWriter { /** * Creates a CSV writer. * - * @param out - * the stream to write to. Caller is responsible for closing it. + * @param out the stream to write to. Caller is responsible for closing it. */ public CsvWriter(OutputStream out, String encoding) { try { this.out = new OutputStreamWriter(out, encoding); } catch (UnsupportedEncodingException e) { - throw new UtilsException("Cannot initialize CSV writer", e); + throw new IllegalArgumentException(e); } } /** - * Write a CSV line. Also used to write a header if needed (this is - * transparent for the CSV writer): simply call it first, before writing the - * lines. + * Write a CSV line. Also used to write a header if needed (this is transparent + * for the CSV writer): simply call it first, before writing the lines. */ public void writeLine(List tokens) { try { @@ -55,14 +52,13 @@ public class CsvWriter { out.write('\n'); out.flush(); } catch (IOException e) { - throw new UtilsException("Could not write " + tokens, e); + throw new RuntimeException("Could not write " + tokens, e); } } /** - * Write a CSV line. Also used to write a header if needed (this is - * transparent for the CSV writer): simply call it first, before writing the - * lines. + * Write a CSV line. Also used to write a header if needed (this is transparent + * for the CSV writer): simply call it first, before writing the lines. */ public void writeLine(Object[] tokens) { try { @@ -79,7 +75,7 @@ public class CsvWriter { out.write('\n'); out.flush(); } catch (IOException e) { - throw new UtilsException("Could not write " + tokens, e); + throw new RuntimeException("Could not write " + tokens, e); } } diff --git a/org.argeo.util/src/org/argeo/util/DigestUtils.java b/org.argeo.util/src/org/argeo/util/DigestUtils.java index 022af1038..ce018007c 100644 --- a/org.argeo.util/src/org/argeo/util/DigestUtils.java +++ b/org.argeo.util/src/org/argeo/util/DigestUtils.java @@ -20,7 +20,7 @@ public class DigestUtils { public final static String SHA512 = "SHA-512"; private static Boolean debug = false; - // TODO: make it writable + // TODO: make it configurable private final static Integer byteBufferCapacity = 100 * 1024;// 100 KB public static byte[] sha1(byte[] bytes) { @@ -29,8 +29,8 @@ public class DigestUtils { digest.update(bytes); byte[] checksum = digest.digest(); return checksum; - } catch (Exception e) { - throw new UtilsException("Cannot SHA1 digest", e); + } catch (NoSuchAlgorithmException e) { + throw new IllegalArgumentException(e); } } @@ -41,8 +41,8 @@ public class DigestUtils { byte[] checksum = digest.digest(); String res = encodeHexString(checksum); return res; - } catch (Exception e) { - throw new UtilsException("Cannot digest with algorithm " + algorithm, e); + } catch (NoSuchAlgorithmException e) { + throw new IllegalArgumentException("Cannot digest with algorithm " + algorithm, e); } } @@ -62,8 +62,10 @@ public class DigestUtils { byte[] checksum = digest.digest(); String res = encodeHexString(checksum); return res; - } catch (Exception e) { - throw new UtilsException("Cannot digest with algorithm " + algorithm, e); + } catch (NoSuchAlgorithmException e) { + throw new IllegalArgumentException("Cannot digest with algorithm " + algorithm, e); + } catch (IOException e) { + throw new RuntimeException(e); } finally { StreamUtils.closeQuietly(in); } @@ -81,7 +83,7 @@ public class DigestUtils { ByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, sz); return digest(algorithm, bb); } catch (IOException e) { - throw new UtilsException("Cannot digest " + file + " with algorithm " + algorithm, e); + throw new IllegalArgumentException("Cannot digest " + file + " with algorithm " + algorithm, e); } finally { StreamUtils.closeQuietly(fis); if (fc.isOpen()) @@ -105,7 +107,7 @@ public class DigestUtils { System.out.println((end - begin) + " ms / " + ((end - begin) / 1000) + " s"); return res; } catch (NoSuchAlgorithmException e) { - throw new UtilsException("Cannot digest with algorithm " + algorithm, e); + throw new IllegalArgumentException("Cannot digest with algorithm " + algorithm, e); } } @@ -146,8 +148,10 @@ public class DigestUtils { if (debug) System.out.println((end - begin) + " ms / " + ((end - begin) / 1000) + " s"); return md.digest(); - } catch (Exception e) { - throw new UtilsException("Cannot digest " + file + " with algorithm " + algorithm, e); + } catch (NoSuchAlgorithmException e) { + throw new IllegalArgumentException("Cannot digest " + file + " with algorithm " + algorithm, e); + } catch (IOException e) { + throw new RuntimeException("Cannot digest " + file + " with algorithm " + algorithm, e); } } diff --git a/org.argeo.util/src/org/argeo/util/DirH.java b/org.argeo.util/src/org/argeo/util/DirH.java index 4035b96bc..b6d962f06 100644 --- a/org.argeo.util/src/org/argeo/util/DirH.java +++ b/org.argeo.util/src/org/argeo/util/DirH.java @@ -1,5 +1,6 @@ package org.argeo.util; +import java.io.IOException; import java.io.PrintStream; import java.nio.charset.Charset; import java.nio.file.DirectoryStream; @@ -12,7 +13,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -/** Hashes the hashes of the files in a directory.*/ +/** Hashes the hashes of the files in a directory. */ public class DirH { private final static Charset charset = Charset.forName("UTF-16"); @@ -30,12 +31,11 @@ public class DirH { private final byte[] dirName; /** - * @param dirName - * can be null or empty + * @param dirName can be null or empty */ private DirH(byte[][] hashes, byte[][] fileNames, byte[] dirName) { if (hashes.length != fileNames.length) - throw new UtilsException(hashes.length + " hashes and " + fileNames.length + " file names"); + throw new IllegalArgumentException(hashes.length + " hashes and " + fileNames.length + " file names"); this.hashes = hashes; this.fileNames = fileNames; this.dirName = dirName == null ? new byte[0] : dirName; @@ -49,7 +49,7 @@ public class DirH { hashSize = hashes[0].length; for (int i = 0; i < hashes.length; i++) { if (hashes[i].length != hashSize) - throw new UtilsException( + throw new IllegalArgumentException( "Hash size for " + new String(fileNames[i], charset) + " is " + hashes[i].length); } @@ -63,7 +63,7 @@ public class DirH { } digest = md.digest(); } catch (NoSuchAlgorithmException e) { - throw new UtilsException("Cannot digest", e); + throw new IllegalArgumentException("Cannot digest", e); } } @@ -100,8 +100,8 @@ public class DirH { } byte[][] hashes = hs.toArray(new byte[hs.size()][]); return new DirH(hashes, fileNames, dir.toString().getBytes(charset)); - } catch (Exception e) { - throw new UtilsException("Cannot digest " + dir, e); + } catch (IOException e) { + throw new RuntimeException("Cannot digest " + dir, e); } } diff --git a/org.argeo.util/src/org/argeo/util/LangUtils.java b/org.argeo.util/src/org/argeo/util/LangUtils.java index 1a7a8815e..7824d12de 100644 --- a/org.argeo.util/src/org/argeo/util/LangUtils.java +++ b/org.argeo.util/src/org/argeo/util/LangUtils.java @@ -20,6 +20,7 @@ import java.util.Properties; import javax.naming.InvalidNameException; import javax.naming.ldap.LdapName; +/** Utilities around Java basic features. */ public class LangUtils { /* * NON-API OSGi diff --git a/org.argeo.util/src/org/argeo/util/PasswordEncryption.java b/org.argeo.util/src/org/argeo/util/PasswordEncryption.java index a026bed22..c95c7879e 100644 --- a/org.argeo.util/src/org/argeo/util/PasswordEncryption.java +++ b/org.argeo.util/src/org/argeo/util/PasswordEncryption.java @@ -5,6 +5,8 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.security.InvalidKeyException; import java.security.Key; @@ -26,7 +28,8 @@ public class PasswordEncryption { public final static String DEFAULT_SECRETE_KEY_FACTORY = "PBKDF2WithHmacSHA1"; public final static String DEFAULT_SECRETE_KEY_ENCRYPTION = "AES"; public final static String DEFAULT_CIPHER_NAME = "AES/CBC/PKCS5Padding"; - public final static String DEFAULT_CHARSET = "UTF-8"; +// public final static String DEFAULT_CHARSET = "UTF-8"; + public final static Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; private Integer iterationCount = DEFAULT_ITERATION_COUNT; private Integer secreteKeyLength = DEFAULT_SECRETE_KEY_LENGTH; @@ -68,11 +71,11 @@ public class PasswordEncryption { + " secrete key length instead of " + previousSecreteKeyLength); try { initKeyAndCiphers(password, passwordSalt, initializationVector); - } catch (Exception e1) { - throw new UtilsException("Cannot get secret key (with restricted length)", e1); + } catch (GeneralSecurityException e1) { + throw new IllegalStateException("Cannot get secret key (with restricted length)", e1); } - } catch (Exception e) { - throw new UtilsException("Cannot get secret key", e); + } catch (GeneralSecurityException e) { + throw new IllegalStateException("Cannot get secret key", e); } } @@ -110,8 +113,6 @@ public class PasswordEncryption { StreamUtils.closeQuietly(out); } catch (IOException e) { throw e; - } catch (Exception e) { - throw new UtilsException("Cannot encrypt", e); } finally { StreamUtils.closeQuietly(decryptedIn); } @@ -123,8 +124,6 @@ public class PasswordEncryption { StreamUtils.copy(decryptedIn, decryptedOut); } catch (IOException e) { throw e; - } catch (Exception e) { - throw new UtilsException("Cannot decrypt", e); } finally { StreamUtils.closeQuietly(encryptedIn); } @@ -138,8 +137,8 @@ public class PasswordEncryption { in = new ByteArrayInputStream(str.getBytes(DEFAULT_CHARSET)); encrypt(in, out); return out.toByteArray(); - } catch (Exception e) { - throw new UtilsException("Cannot encrypt", e); + } catch (IOException e) { + throw new RuntimeException(e); } finally { StreamUtils.closeQuietly(out); } @@ -152,8 +151,8 @@ public class PasswordEncryption { out = new ByteArrayOutputStream(); decrypt(in, out); return new String(out.toByteArray(), DEFAULT_CHARSET); - } catch (Exception e) { - throw new UtilsException("Cannot decrypt", e); + } catch (IOException e) { + throw new RuntimeException(e); } finally { StreamUtils.closeQuietly(out); } diff --git a/org.argeo.util/src/org/argeo/util/StreamUtils.java b/org.argeo.util/src/org/argeo/util/StreamUtils.java index 7e66c0a39..6d7d940ce 100644 --- a/org.argeo.util/src/org/argeo/util/StreamUtils.java +++ b/org.argeo.util/src/org/argeo/util/StreamUtils.java @@ -6,7 +6,7 @@ import java.io.OutputStream; import java.io.Reader; import java.io.Writer; -/** Utilities to be used when APache COmmons IO is not available. */ +/** Utilities to be used when Apache Commons IO is not available. */ class StreamUtils { private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; diff --git a/org.argeo.util/src/org/argeo/util/Throughput.java b/org.argeo.util/src/org/argeo/util/Throughput.java index b8741a3ef..266ddbc58 100644 --- a/org.argeo.util/src/org/argeo/util/Throughput.java +++ b/org.argeo.util/src/org/argeo/util/Throughput.java @@ -4,9 +4,9 @@ import java.text.NumberFormat; import java.text.ParseException; import java.util.Locale; +/** A throughput, that is, a value per unit of time. */ public class Throughput { - private final static NumberFormat usNumberFormat = NumberFormat - .getInstance(Locale.US); + private final static NumberFormat usNumberFormat = NumberFormat.getInstance(Locale.US); public enum Unit { s, m, h, d @@ -30,7 +30,7 @@ public class Throughput { else if (unit.equals(Unit.d)) value = ((double) count * 24d * 60d * 60d * 1000d) / periodMs; else - throw new UtilsException("Unsupported unit " + unit); + throw new IllegalArgumentException("Unsupported unit " + unit); this.unit = unit; } @@ -41,15 +41,14 @@ public class Throughput { public Throughput(String def) { int index = def.indexOf('/'); if (def.length() < 3 || index <= 0 || index != def.length() - 2) - throw new UtilsException(def + " no a proper throughput definition" - + " (should be /, e.g. 3.54/s or 1500/h"); + throw new IllegalArgumentException( + def + " no a proper throughput definition" + " (should be /, e.g. 3.54/s or 1500/h"); String valueStr = def.substring(0, index); String unitStr = def.substring(index + 1); try { this.value = usNumberFormat.parse(valueStr).doubleValue(); } catch (ParseException e) { - throw new UtilsException("Cannot parse " + valueStr - + " as a number.", e); + throw new IllegalArgumentException("Cannot parse " + valueStr + " as a number.", e); } this.unit = Unit.valueOf(unitStr); } @@ -64,7 +63,7 @@ public class Throughput { else if (unit.equals(Unit.d)) return Math.round((24d * 60d * 60d * 1000d) / value); else - throw new UtilsException("Unsupported unit " + unit); + throw new IllegalArgumentException("Unsupported unit " + unit); } @Override diff --git a/org.argeo.util/src/org/argeo/util/UtilsException.java b/org.argeo.util/src/org/argeo/util/UtilsException.java deleted file mode 100644 index 28b03d96b..000000000 --- a/org.argeo.util/src/org/argeo/util/UtilsException.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.argeo.util; - -/** Utils specific exception. */ -class UtilsException extends RuntimeException { - private static final long serialVersionUID = 1L; - - /** Creates an exception with a message. */ - public UtilsException(String message) { - super(message); - } - - /** Creates an exception with a message and a root cause. */ - public UtilsException(String message, Throwable e) { - super(message, e); - } - -}