All Downloads are FREE. Search and download functionalities are using the official Maven repository.

liquibase.change.CheckSum Maven / Gradle / Ivy

There is a newer version: 4.30.0
Show newest version
package liquibase.change;

import liquibase.ChecksumVersion;
import liquibase.Scope;
import liquibase.util.MD5Util;
import liquibase.util.StringUtil;

import java.io.IOException;
import java.io.InputStream;
import java.text.Normalizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * CheckSums are used by liquibase to determine if a Change has been modified since it was originally ran.
 * CheckSums can be computed on either a String or an {@link InputStream}.
 * The CheckSum contains a version number which can be used to determine whether the algorithm for computing a
 * storedCheckSum has changed since the last time it was computed. If the algorithm changes, we cannot rely on
 * the storedCheckSum value.
 * 

* It is not up to this class to determine what should be storedCheckSum-ed, it simply hashes what is passed to it. */ public final class CheckSum { private final int version; private final String storedCheckSum; private static final char DELIMITER = ':'; private static final String CHECKSUM_REGEX = "(^\\d++)" + DELIMITER + "([a-zA-Z0-9]++)"; private static final Pattern CHECKSUM_PATTERN = Pattern.compile(CHECKSUM_REGEX); /** * Constructor. Stores a given checksum generated by a given algorithm version into the new CheckSum object. * * @param checksum Generated checksum (format depends on version) * @param version The version of the Liquibase checksum generator used */ private CheckSum(String checksum, int version) { this.storedCheckSum = checksum; this.version = version; } /** * Parse the given storedCheckSum string value and return a new CheckSum object. */ public static CheckSum parse(String checksumValue) { if (StringUtil.isEmpty(checksumValue)) { return null; } // The general layout of a checksum is: // <1+ digits: algorithm version number>:<1..n characters alphanumeric checksum> // Example: 7:2cdf9876e74347162401315d34b83746 Matcher matcher = CHECKSUM_PATTERN.matcher(checksumValue); if (matcher.find()) { return new CheckSum(matcher.group(2), Integer.parseInt(matcher.group(1))); } else { // No version information found return new CheckSum(checksumValue, 1); } } /** * Return the current CheckSum algorithm version. * * @deprecated Use {@link ChecksumVersion#latest()} instead */ @Deprecated public static int getCurrentVersion() { return ChecksumVersion.latest().getVersion(); } /** * Compute a storedCheckSum of the given string. */ public static CheckSum compute(String valueToChecksum) { return new CheckSum(MD5Util.computeMD5( //remove "Unknown" unicode char 65533 Normalizer.normalize(StringUtil.standardizeLineEndings(valueToChecksum) .replace("\uFFFD", ""), Normalizer.Form.NFC) ), Scope.getCurrentScope().getChecksumVersion().getVersion()); } /** * Compute a CheckSum of the given data stream (no normalization of line endings!) */ public static CheckSum compute(final InputStream stream, boolean standardizeLineEndings) { InputStream newStream = stream; if (standardizeLineEndings) { newStream = new InputStream() { private boolean isPrevR = false; @Override public int read() throws IOException { int read = stream.read(); if (read == '\r') { isPrevR = true; return '\n'; } else if (read == '\n' && isPrevR) { isPrevR = false; return read(); } else { isPrevR = false; return read; } } }; } return new CheckSum(MD5Util.computeMD5(newStream), Scope.getCurrentScope().getChecksumVersion().getVersion()); } @Override public String toString() { return version + String.valueOf(DELIMITER) + storedCheckSum; } /** * Return the Checksum Algorithm version for this CheckSum */ public int getVersion() { return version; } @Override public int hashCode() { return toString().hashCode(); } @Override public boolean equals(Object obj) { return (obj instanceof CheckSum) && this.toString().equals(obj.toString()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy