Java tutorial
/* * Copyright (C) 2008-2010 Institute for Computational Biomedicine, * Weill Medical College of Cornell University * * 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 edu.cornell.med.icb.util; import org.apache.commons.lang.StringUtils; import java.util.zip.Adler32; /** * Utility class to add a simple 2 character checksum * to a string and a method to validate the string has * the correct checksum. * @author Kevin Dorff */ public final class SimpleChecksum { /** * Private constructor for utility class. */ private SimpleChecksum() { super(); } /** * The characters to use in the checksum. */ private static final char[] CHECKSUM_CHARS = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; /** * Takes a string and returns a that same string * with two additional characters which are a simple * checksum, each char will be "A".."Z". An empty * (no characters) or null string will just be * returned with no change. * @param valToChecksum the string to add the checksum to * @return the string with the checksum */ public static String simpleChecksum(final String valToChecksum) { if (StringUtils.isEmpty(valToChecksum)) { return valToChecksum; } final Adler32 adler = new Adler32(); adler.update(valToChecksum.getBytes()); final long[] result = splitLong(adler.getValue()); return String.format("%s%c%c", valToChecksum, CHECKSUM_CHARS[(int) result[0]], CHECKSUM_CHARS[(int) result[1]]); } /** * Take a string that contains a simple checksum and * validate the that checksum is correct. * @param checksumString the string to check where the * last two characters are the checksum * @return true of the checksum is correct */ public static boolean validate(final String checksumString) { if (checksumString == null || checksumString.length() < 3) { return false; } final String baseString = checksumString.substring(0, checksumString.length() - 2); final String newVal = simpleChecksum(baseString); return checksumString.equals(newVal); } /** * Splits a long value into two long values, representing * the left and right side. This isn't necessarily the * top four bytes and bottom four bytes, it is based on * the number of bytes that are actually used in the value. * @param inval long value to split * @return two resultant long values in an array */ private static long[] splitLong(final long inval) { // Take the hex value and use HALF of the // left hex digits to make the first character // and half of right hex digits to make the // second character. final String checksumString = Long.toHexString(inval); final String[] maskStrings = makeHexMaskStrings(checksumString); final long[] maskLongs = new long[2]; maskLongs[0] = Long.parseLong(maskStrings[0], 16); maskLongs[1] = Long.parseLong(maskStrings[1], 16); final long[] result = new long[2]; result[0] = (inval & maskLongs[0]) % CHECKSUM_CHARS.length; result[1] = (inval & maskLongs[1]) % CHECKSUM_CHARS.length; return result; } /** * Make two hex masks of the incoming hex string. The hex string must be * no longer than 16 digits, not be null/empty, and (of course) contain only * hex digits. The two masks will to mask the left and right side of * the string. If you pass in "abcdef" you will receive back * "fff000" and "000fff". * @param hexString hex string to make two masks for * @return two hex mask strings in a String[] */ static String[] makeHexMaskStrings(final String hexString) { if (StringUtils.isEmpty(hexString) || hexString.length() > 16) { throw new IllegalArgumentException( "Hex string '" + hexString + "' must be 1 to 16 characters long and not null."); } for (int i = 0; i < hexString.length(); i++) { final char c = hexString.charAt(i); if (c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f') { continue; } throw new IllegalArgumentException( "Hex string '" + hexString + "' must contain only hex digits, 0-9A-F"); } final int leftSize; final int rightSize; if (hexString.length() == 1) { leftSize = 0; rightSize = 1; } else { leftSize = hexString.length() / 2; rightSize = hexString.length() - leftSize; } final StringBuilder leftMask = new StringBuilder(); final StringBuilder rightMask = new StringBuilder(); for (int i = 0; i < leftSize; i++) { leftMask.append('F'); rightMask.append('0'); } for (int i = 0; i < rightSize; i++) { leftMask.append('0'); rightMask.append('F'); } final String[] masks = new String[2]; masks[0] = leftMask.toString(); masks[1] = rightMask.toString(); return masks; } }