001/**
002 * Copyright 2015 DuraSpace, Inc.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.fcrepo.kernel.utils;
017
018import static com.google.common.base.Throwables.propagate;
019import static java.util.Collections.singletonMap;
020import static org.apache.commons.codec.binary.Hex.encodeHexString;
021import static org.slf4j.LoggerFactory.getLogger;
022
023import java.net.URI;
024import java.net.URISyntaxException;
025import java.util.Map;
026
027import org.slf4j.Logger;
028
029import com.google.common.collect.ImmutableMap;
030
031/**
032 * Digest helpers to convert digests (checksums) into URI strings
033 * (based loosely on Magnet URIs)
034 * @author Chris Beer
035 * @since Mar 6, 2013
036 */
037public final class ContentDigest {
038
039    private static final Logger LOGGER = getLogger(ContentDigest.class);
040
041    public static final Map<String, String> algorithmToScheme = ImmutableMap
042            .of("SHA-1", "urn:sha1", "SHA1", "urn:sha1");
043
044    public static final Map<String, String> schemeToAlgorithm =
045        singletonMap("urn:sha1", "SHA-1");
046
047    public static final String DEFAULT_ALGORITHM = "SHA-1";
048
049    private ContentDigest() {
050    }
051
052    /**
053     * Convert a MessageDigest algorithm and checksum value to a URN
054     * @param algorithm the message digest algorithm
055     * @param value the checksum value
056     * @return URI
057     */
058    public static URI asURI(final String algorithm, final String value) {
059        try {
060            final String scheme = algorithmToScheme.get(algorithm);
061
062            return new URI(scheme, value, null);
063        } catch (final URISyntaxException unlikelyException) {
064            LOGGER.warn("Exception creating checksum URI: {}",
065                               unlikelyException);
066            throw propagate(unlikelyException);
067        }
068    }
069
070    /**
071     * Convert a MessageDigest algorithm and checksum byte-array data to a URN
072     * @param algorithm the message digest algorithm
073     * @param data the checksum byte-array data
074     * @return URI
075     */
076    public static URI asURI(final String algorithm, final byte[] data) {
077        return asURI(algorithm, asString(data));
078    }
079
080    /**
081     * Given a digest URI, get the corresponding MessageDigest algorithm
082     * @param digestUri the digest uri
083     * @return MessageDigest algorithm
084     */
085    public static String getAlgorithm(final URI digestUri) {
086        if (digestUri == null) {
087            return DEFAULT_ALGORITHM;
088        }
089        return schemeToAlgorithm
090        .get(digestUri.getScheme() + ":" +
091             digestUri.getSchemeSpecificPart().split(":", 2)[0]);
092    }
093
094    private static String asString(final byte[] data) {
095        return encodeHexString(data);
096    }
097
098    /**
099     * Placeholder checksum value.
100     * @return URI
101     */
102    public static URI missingChecksum() {
103        return asURI("SHA-1", "missing");
104    }
105
106}