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