Terms of Service | Privacy Policy | Cookie Policy

Commit e5b7d62f authored by Uwe Plonus's avatar Uwe Plonus

Documented and refactored code generator package

parent f1d61a1c
Pipeline #423 passed with stages
in 23 minutes and 54 seconds
/*
* 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/>.
*/
package org.sw4j.tool.barcode.random.generator;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sw4j.tool.barcode.random.codedata.CodeData;
import org.sw4j.tool.barcode.random.config.CodeConfig;
import org.sw4j.tool.barcode.random.config.CodeType;
/**
* <p>
* This is a {@link java.util.function.Consumer Consumer} for
* {@link org.sw4j.tool.barcode.random.generator.RandomIdent RandomIdent} which generates one barcode for a
* {@code RandomIdent}.
* </p>
* <p>
* This class is thread safe, as long as no barcodes for the same ident are generated.
* </p>
* @author Uwe Plonus &lt;u.plonus@gmail.com&gt;
*/
public class BarcodeWriter implements Consumer<RandomIdent> {
/**
* <p>
* The logger of this class.
* </p>
*/
private final Logger logger = Logger.getLogger(BarcodeWriter.class.getName());
/**
* <p>
* The configuration for the barcode that should me generated.
* </p>
*/
private final CodeConfig codeConfig;
/**
* <p>
* The factories for the input and output stream.
* </p>
*/
private final CodeData codeData;
/**
* <p>
* Create a new instance with the given barcode config and output factories.
* </p>
* @param codeConfig the configuration for the barcode to generate.
* @param codeData the factories for the output files.
*/
public BarcodeWriter(final CodeConfig codeConfig, final CodeData codeData) {
this.codeConfig = codeConfig;
this.codeData = codeData;
}
/**
* <p>
* Generate the barcode for the given ident and configured barcode.
* </p>
* @param randomIdent the ident (and its random numbers) for output.
*/
@Override
public void accept(final RandomIdent randomIdent) {
CodeType codeType = codeConfig.getType();
String codeEncoding = codeConfig.getEncoding();
String codeUrl = codeConfig.getUrl();
codeUrl = codeUrl.replace("{code}", randomIdent.getEncoded(codeEncoding));
try {
OutputStream os = codeData.getOutputForIdent(codeType, codeEncoding, randomIdent.getIdent(),
codeConfig.getFiletype());
MultiFormatWriter codeWriter = new MultiFormatWriter();
Map<EncodeHintType, Object> encodingParameters = new HashMap<>();
encodingParameters.put(EncodeHintType.CHARACTER_SET, "utf-8");
setErrorCorrection(encodingParameters);
BitMatrix matrix = codeWriter.encode(codeUrl, codeType.getFormat(), codeConfig.getWidth(),
codeConfig.getHeight());
MatrixToImageWriter.writeToStream(matrix, codeConfig.getFiletype(), os);
} catch (IOException | WriterException exc) {
logger.log(Level.WARNING,
String.format("Writing of Code 'type: %s / encoding: %s / ident: %s' failed.",
codeType.getType(), codeEncoding, randomIdent.getIdent()), exc);
}
}
/**
* <p>
* Configure the barcode error correction depending on the bacode type.
* </p>
* @param encodingParameters the encoding parameters where the error correction should be set in.
*/
private void setErrorCorrection(final Map<EncodeHintType, Object> encodingParameters) {
switch (codeConfig.getType()) {
case QRCODE:
try {
encodingParameters.put(EncodeHintType.ERROR_CORRECTION,
ErrorCorrectionLevel.valueOf(codeConfig.getErrorCorrection()));
} catch (IllegalArgumentException | NullPointerException exc) {
encodingParameters.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
}
break;
default:
logger.warning("This point should never be reached.");
}
}
}
/*
* 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/>.
*/
package org.sw4j.tool.barcode.random.generator;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.sw4j.tool.barcode.random.encoder.ByteArrayEncoder;
/**
* <p>
* This class contains the random number and the encoded representations for a single ident.
* </p>
* <p>
* This class is immutable.
* </p>
* @author Uwe Plonus &lt;u.plonus@gmail.com&gt;
*/
public class RandomIdent {
/**
* <p>
* The ident number.
* </p>
*/
private final String ident;
/**
* <p>
* The generated random number.
* </p>
*/
private final byte[] random;
/**
* <p>
* A map containing all encoded values for the ident. The key is the encoding and the value the encoded value.
* </p>
*/
private final Map<String, String> encoded;
/**
* <p>
* Create a new {@code RandomIdent} and the random number for the {@qcode ident}. The random number has a size of
* {@code randomSize} bits (rounded down to the next whole byte). For the generation of the random number the given
* {@code rng} will be used. The generated random number will be encoded in all given {@code encodings}.
* </p>
* <p>
* For high quality random numbers use an appropriate random number generator
* (e.g. {@link java.security.SecureRandom SecureRandom}).
* </p>
* @param ident the ident for which the random number will be generated for.
* @param randomSize the size in bits (rounded down to the next byte).
* @param rng the random number generator to use.
* @param encodings the encodings that are used for the encoded representation of the random number.
* @throws IllegalArgumentException if no encoder for a given encoding can be found.
*/
public RandomIdent(final String ident, final int randomSize, final Random rng, final Set<String> encodings) {
this.ident = ident;
random = new byte[randomSize / 8];
rng.nextBytes(random);
encoded = new HashMap<>();
encodings.forEach((encoding) -> {
String rawEncoding = encoding;
int endIndex = -1;
int startIndex = -1;
boolean hasMinus = false;
if (rawEncoding.matches(".+\\{\\d*-?\\d+\\}")) {
Pattern p = Pattern.compile("(.+)\\{((\\d*)-)?(\\d+)\\}");
Matcher m = p.matcher(rawEncoding);
m.matches();
rawEncoding = m.group(1);
if (m.group(2) != null && m.group(2).length() > 1) {
startIndex = Integer.parseInt(m.group(2).substring(0, m.group(2).length() - 1));
}
String startIndexGroup = m.group(2);
hasMinus = m.group(3) != null;
endIndex = Integer.parseInt(m.group(4));
}
ByteArrayEncoder encoder = ByteArrayEncoder.forEncoding(rawEncoding);
if (encoder == null) {
throw new IllegalArgumentException(
String.format("Cannot find an encoder for encoding %s", rawEncoding));
}
String encodedValue = encoder.encode(random);
if (endIndex > 0) {
if (hasMinus) {
if (startIndex >= 0) {
encodedValue = encodedValue.substring(startIndex, endIndex);
} else {
encodedValue = encodedValue.substring(encodedValue.length() - endIndex);
}
} else {
encodedValue = encodedValue.substring(0, endIndex);
}
}
encoded.put(encoding, encodedValue);
});
}
/**
* <p>
* Return the ident number.
* </p>
* @return the ident number.
*/
public String getIdent() {
return ident;
}
/**
* <p>
* Return the raw random number generated.
* </p>
* @return the raw random number.
*/
public byte[] getRandom() {
return Arrays.copyOf(random, random.length);
}
/**
* <p>
* Return the random number in the given {@code encoding}. Only the encodings that were given during construction
* can be returned.
* </p>
* @param encoding the encoding for which the encoded value should be returned.
* @return the encoded value or {@code null} if the encoding is unknown.
*/
public String getEncoded(final String encoding) {
return encoded.get(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>
* This package contains the generator of the barcodes and encoded random numbers.
* </p>
*/
package org.sw4j.tool.barcode.random.generator;
......@@ -33,7 +33,7 @@ import javax.xml.bind.DatatypeConverter;
import org.sw4j.tool.barcode.random.codedata.CodeData;
import org.sw4j.tool.barcode.random.config.CodeConfig;
import org.sw4j.tool.barcode.random.config.RandomConfig;
import org.sw4j.tool.barcode.random.generator.CodeGenerator.RandomIdent;
import org.sw4j.tool.barcode.random.generator.RandomIdent;
import org.sw4j.tool.barcode.random.support.PredictableRandom;
import org.sw4j.tool.barcode.random.support.TestCodeData;
import static org.testng.Assert.*;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment