Terms of Service | Privacy Policy | Cookie Policy

...
 
Commits (6)
......@@ -43,7 +43,7 @@
<!-- Reporting Plugins -->
<changes-plugin.version>2.12.1</changes-plugin.version>
<checkstyle-plugin.version>3.0.0</checkstyle-plugin.version>
<dependency-check-plugin.version>5.0.0-M1</dependency-check-plugin.version>
<dependency-check-plugin.version>4.0.2</dependency-check-plugin.version>
<fluido-skin.version>1.6</fluido-skin.version>
<javadoc-plugin.version>3.0.1</javadoc-plugin.version>
<jxr-plugin.version>3.0.0</jxr-plugin.version>
......@@ -480,6 +480,7 @@
<threshold>Low</threshold>
<effort>Max</effort>
<includeFilterFile>org/sw4j/quality-profile/spotbugs/spotbugs-3.1.1.xml</includeFilterFile>
<excludeFilterFile>src/main/spotbugs/exclusion.xml</excludeFilterFile>
</configuration>
</plugin>
<plugin>
......
<?xml version="1.0" encoding="UTF-8"?>
<suppressions xmlns="https://www.owasp.org/index.php/OWASP_Dependency_Check_Suppression">
<suppress base="false">
<notes><![CDATA[
The CPE is about a node.js library that handles static html files whereas StAX is a XML parser library.
Therefore the CPE generates false positives for the library used in this project.
]]></notes>
<gav regex="true" caseSensitive="true">stax:stax:.*</gav>
<cpe regex="true" caseSensitive="true">cpe:/a:st_project:st:.*</cpe>
</suppress>
<!--<suppress base="true|false">
<notes><![CDATA[Reason]]></notes>
......
......@@ -16,9 +16,6 @@
*/
package org.sw4j.tool.barcode.random;
import org.sw4j.tool.barcode.random.codedata.FileCodeData;
import org.sw4j.tool.barcode.random.generator.CodeGenerator;
import org.sw4j.tool.barcode.random.config.Config;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
......@@ -29,33 +26,81 @@ import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.sw4j.tool.barcode.random.codedata.FileCodeData;
import org.sw4j.tool.barcode.random.config.Config;
import org.sw4j.tool.barcode.random.generator.CodeGenerator;
/**
* This is the main class of the random barcode generator.
*
* @author Uwe Plonus &lt;u.plonus@gmail.com&gt;
*/
public class Main {
private static final Logger logger = Logger.getLogger(Main.class.getName());
/**
* <p>
* Exit code of the application when the {@code app.home} system property is not set.
* </p>
*/
private static final int EXIT_NO_APP_HOME = -3;
/**
* <p>
* The logger of this class.
* </p>
*/
private final Logger logger = Logger.getLogger(Main.class.getName());
/**
* <p>
* The sole constructor of this class.
* </p>
*/
public Main() {
}
public static void main(String... args) throws IOException {
/**
* <p>
* The main method to start the application.
* </p>
*
* @TODO handle the IOException internally
* @param args the command line arguments.
* @throws IOException forwarded exception.
*/
public static void main(final String... args) throws IOException {
new Main().run(args);
}
public void run(String... args) throws IOException {
/**
* <p>
* Run the application with the given command line arguments.
* </p>
* <p>
* The application uses the system property {@code app.home} to determine the home folder of the application and
* resolve the default configuration file relative to this folder.
* </p>
* <p>
* This method needs the system property {@code app.home} to be set. If the system property is not set then the
* application is terminated with exit code {@code -3}.
* </p>
*
* @TODO handle the IOException internally
* @param args the command line arguments.
* @throws IOException forwarded exception
*/
public void run(final String... args) throws IOException {
String appHome = System.getProperty("app.home");
if (appHome == null) {
System.err.println("app.home not set");
System.exit(-3);
System.exit(EXIT_NO_APP_HOME);
}
CommandLine cl = parseCommandLine(args);
File configFile;
boolean hasConfigParam = false;
if (cl.hasOption("c")) {
configFile = new File(cl.getOptionValue("c"));
hasConfigParam = true;
} else {
String configFileName = "etc/barcode.yaml";
configFile = new File(appHome, configFileName);
......@@ -69,7 +114,15 @@ public class Main {
System.out.println("End");
}
public CommandLine parseCommandLine(String... args) {
/**
* <p>
* Parses the command line and returns the parsed command line.
* </p>
*
* @param args the command line arguments.
* @return the parsed command line.
*/
private CommandLine parseCommandLine(final String... args) {
Options clo = new Options();
clo.addOption(Option
......@@ -79,8 +132,7 @@ public class Main {
.required(false)
.argName("config-file")
.desc("The config file to use.")
.build()
);
.build());
CommandLineParser clp = new DefaultParser();
CommandLine cl = new CommandLine.Builder().build();
......
......@@ -22,34 +22,42 @@ import java.io.OutputStream;
import org.sw4j.tool.barcode.random.config.CodeType;
/**
*
* <p>
* This interface is an abstraction for the application to be able to read different input and output formats (e.g.
* streams from a file or from other transports like HTTP).
* </p>
* @author Uwe Plonus &lt;u.plonus@gmail.com&gt;
*/
public interface CodeData {
/**
* <p>
* Returns an input stream for reading the source data.
* @return
* @throws IOException
* </p>
* @return an {@code InputStream} for reading the input data.
* @throws IOException if the creation of the {@code InputStream} fails.
*/
InputStream getInput() throws IOException;
/**
* Returns an output stream for writing the output (without bar codes).
* @return
* @throws IOException
* <p>
* Returns an output stream for writing the output csv data.
* </p>
* @return an {@code OutputStream} for writing the output csv data.
* @throws IOException if the creation of the {@code OutputStream} fails.
*/
OutputStream getOutput() throws IOException;
/**
* Returns an output stream for writing the bar code for the given identifier and format.
*
* @param type the type of the code to (e.g. qrcode)
* <p>
* Returns an individual output stream for writing the barcode for the given identifier and format.
* </p>
* @param type the type of the code to write.
* @param format the format of the random number (e.g. hex)
* @param ident
* @param suffix the suffix of the file
* @return
* @throws IOException
* @param ident the identifier from the input file.
* @param suffix the suffix of the file.
* @return an {@code OutputStream} for writing the individual barcode.
* @throws IOException if the creation of the {@code OutputStream} fails.
*/
OutputStream getOutputForIdent(CodeType type, String format, String ident, String suffix) throws IOException;
......
......@@ -26,34 +26,92 @@ import org.sw4j.tool.barcode.random.config.CodeType;
import org.sw4j.tool.barcode.random.config.Config;
/**
*
* <p>
* This is a concrete implementation of the {@link CodeData} interface that handles files for input and output.
* </p>
* <p>
* <em>This class is not thread safe.</em>
* </p>
* @author Uwe Plonus &lt;u.plonus@gmail.com&gt;
*/
public class FileCodeData implements CodeData {
public final Config config;
/**
* <p>
* The configuration with the data for the input and output files.
* </p>
*/
private final Config config;
public FileCodeData(Config config) {
/**
* <p>
* Create a new {@code FileCodeData} with the given configuration.
* </p>
* @param config the configuration (files and folders) to use for the input and output data.
*/
public FileCodeData(final Config config) {
this.config = config;
}
/**
* <p>
* Create a new {@code FileInputStream} for the input file given in the configuration. The {@code InputStream} must
* be closed by the caller.
* </p>
* @return a new {@code FileInputStream} for reading the input data.
* @throws IOException if the creation of the {@code FileInputStream} fails.
*/
@Override
public InputStream getInput() throws IOException {
return new FileInputStream(config.getInput().getName());
}
/**
* <p>
* Create a new {@code FileOutputStream} for writing the csv output file. If the folder for the output file does not
* exists then it will be created.
* </p>
* @return a new {@code FileOutputStream} for writing the csv data.
* @throws IOException if the creation of the {@code FileOutputStream} or the folder fails.
*/
@Override
public OutputStream getOutput() throws IOException {
File folder = new File(config.getOutput().getFolder());
folder.mkdirs();
if (!folder.exists()) {
if (!folder.mkdirs()) {
throw new IOException(
String.format("Cannot create output folder '%s'.", folder.getAbsoluteFile()));
}
}
return new FileOutputStream(new File(folder, config.getOutput().getFile().getName()));
}
/**
* <p>
* Create a new {@code FileOutputStream} for writing a barcode. If the folder for the output file does not exists
* then it will be created.
* </p>
* <p>
* This method may be called from different threads as long as the parameters are different.
* </p>
* @param type the type to write.
* @param format the encoding format to write.
* @param ident the ident of the data.
* @param suffix the suffix of the file to write.
* @return a new {@code FileOutputStream} for writing the barcode data.
* @throws IOException if the creation of the {@code FileOutputStream} or the folder fails.
*/
@Override
public OutputStream getOutputForIdent(CodeType type, String format, String ident, String suffix)
public OutputStream getOutputForIdent(final CodeType type, final String format, final String ident,
final String suffix)
throws IOException {
File folder = new File(config.getOutput().getFolder());
folder.mkdirs();
if (!folder.exists()) {
if (!folder.mkdirs()) {
throw new IOException(
String.format("Cannot create output folder '%s'.", folder.getAbsoluteFile()));
}
}
return new FileOutputStream(new File(folder,
String.format("%s-%s-%s.%s", type.getType(), format, ident, suffix)));
}
......
/*
* Copyright (C) 2019 sw4j.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* <p>
* This package contains an abstraction for the input and output of the code generation.
* </p>
* <p>
* The major abstraction is the interface {@link org.sw4j.tool.barcode.random.codedata.CodeData} which returns an input
* stream or output stream depending on the needs of the application.
* </p>
*/
package org.sw4j.tool.barcode.random.codedata;
......@@ -19,15 +19,63 @@ package org.sw4j.tool.barcode.random.coder;
import java.util.Arrays;
/**
*
* <p>
* This utility class implements a base58 encoding with the alphabet from bitcoin.
* </p>
* <p>
* This class is thread safe.
* </p>
* @author Uwe Plonus &lt;u.plonus@gmail.com&gt;
*/
public class Base58 {
public final class Base58 {
/**
* <p>
* The number of ASCII characters, used for the reverse lookup array.
* </p>
*/
private static final int NUMBER_ASCII_CHARS = 128;
/**
* <p>
* The base of a byte (256).
* </p>
*/
private static final int BYTE_BASE = 256;
/**
* <p>
* The base of a character in the base58 string.
* </p>
*/
private static final int BASE = 58;
/**
* <p>
* The bit mask to mask a single byte out of a larger integer number.
* </p>
*/
private static final int BYTE_MASK = 0xff;
/**
* <p>
* The alphabet to use for the base58 encoding.
* </p>
*/
private static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
private static final int[] INDEX = new int[128];
/**
* <p>
* The reverse lookup for the {@link #ALPHABET}.
* </p>
*/
private static final int[] INDEX = new int[NUMBER_ASCII_CHARS];
/**
* <p>
* Static initializer to setup the reverse lookup table.
* </p>
*/
static {
for (int i = 0; i < INDEX.length; i++) {
INDEX[i] = -1;
......@@ -38,8 +86,17 @@ public class Base58 {
}
/**
* <p>
* Hidden default constructor for this utility class.
* </p>
*/
private Base58() {
}
/**
* <p>
* Convert the data into a Base58 string.
*
* </p>
* @param data the data to encode.
* @return the encoded data.
*/
......@@ -49,7 +106,7 @@ public class Base58 {
int leadingZeros = leadingZeros(data);
boolean done = (copy.length == 0 || copy.length == leadingZeros);
while (!done) {
byte remainder = divide(copy, 256, 58);
byte remainder = divide(copy, BYTE_BASE, BASE);
result.insert(0, ALPHABET[remainder]);
done = true;
for (int i = 0; i < copy.length; i++) {
......@@ -62,11 +119,18 @@ public class Base58 {
return result.toString();
}
private static int leadingZeros(final byte[] copy) {
/**
* <p>
* Helper method to count the number of leading zero values in a byte array.
* </p>
* @param data the byte array to inspect.
* @return the number of leading zero bytes in the array.
*/
private static int leadingZeros(final byte[] data) {
int leadingZeros = 0;
boolean foundNonZero = false;
for (int i = 0; !foundNonZero && i < copy.length; i++) {
if (copy[i] == 0) {
for (int i = 0; !foundNonZero && i < data.length; i++) {
if (data[i] == 0) {
leadingZeros++;
} else {
foundNonZero = true;
......@@ -75,12 +139,19 @@ public class Base58 {
return leadingZeros;
}
/**
* <p>
* Convert the Base58 string into a byte array.
* </p>
* @param data the base58 string to convert back into a byte array.
* @return the decoded data.
*/
public static byte[] decode(final String data) {
byte[] input = new byte[data.length()];
byte[] output = new byte[data.length()];
for (int i = 0; i < data.length(); i++) {
char c = data.charAt(i);
int digit = c < 128 ? INDEX[c] : -1;
int digit = c < NUMBER_ASCII_CHARS ? INDEX[c] : -1;
if (digit < 0) {
throw new IllegalArgumentException(String.format("The digit '%c' is not recognized.", c));
}
......@@ -90,7 +161,7 @@ public class Base58 {
int outputIndex = output.length;
int zeros = leadingZeros(input);
while (zeros < input.length) {
byte remainder = divide(input, 58, 256);
byte remainder = divide(input, BASE, BYTE_BASE);
output[--outputIndex] = remainder;
zeros = leadingZeros(input);
}
......@@ -98,19 +169,22 @@ public class Base58 {
}
/**
*
* <p>
* A helper method to divide the dividend (in the byte array) by a divisor. The elements of the byte array are
* treated as figures to the given base.
* </p>
* @param dividend the dividend of the division. Contains the quotient of the division after the method is finished.
* @param base the base (max 256) of the digits in the number (each element is a digit).
* @param divisor the divisor (max 256) of the division.
* @return the remainder of the division.
*/
public static byte divide(byte[] dividend, int base, int divisor) {
public static byte divide(final byte[] dividend, final int base, final int divisor) {
if (divisor == 0) {
throw new IllegalArgumentException("The divisor may not be 0.");
}
int remainder = 0;
for (int i = 0; i < dividend.length; i++) {
int digit = (int)(dividend[i] & 0xff);
int digit = (int)(dividend[i] & BYTE_MASK);
if (digit > base) {
throw new IllegalArgumentException(
String.format("The digit at place %d (%d) is larger than the base %d.", i, digit, base));
......
/*
* Copyright (C) 2019 sw4j.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* <p>
* This package contains all coders for encodings (like base58) that are not included in JSE.
* </p>
*/
package org.sw4j.tool.barcode.random.coder;
/*
* Copyright (C) 2019 sw4j.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* <p>
* This package contains all classes needed to configure the application.
* </p>
* <p>
* All classes in this should have a builder that can be used to programmatically configure the application.
* Additionally a configuration by a YAML or JSON file should be possible (by annotating the parameters).
* </p>
*/
package org.sw4j.tool.barcode.random.config;
......@@ -30,6 +30,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
......@@ -249,7 +250,7 @@ public class CodeGenerator {
}
public byte[] getRandom() {
return random;
return Arrays.copyOf(random, random.length);
}
public String getEncoded(String encoding) {
......
/*
* Copyright (C) 2019 sw4j.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* <p>
* The main package of the random barcode creator. This package only contains the {@code Main} class of the application.
* </p>
*/
package org.sw4j.tool.barcode.random;
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
<Match>
<Class name="org.sw4j.tool.barcode.random.Main"/>
<Method name="run"/>
<Bug pattern="DM_EXIT"/>
</Match>
</FindBugsFilter>
\ No newline at end of file