/*
* Licensed to DuraSpace under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* DuraSpace licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.fcrepo.kernel.api.utils;
import static org.apache.commons.codec.binary.Hex.encodeHexString;
import static org.fcrepo.kernel.api.utils.ContentDigest.DIGEST_ALGORITHM.SHA1;
import static org.slf4j.LoggerFactory.getLogger;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import org.fcrepo.kernel.api.exception.RepositoryRuntimeException;
import org.slf4j.Logger;
/**
* Digest helpers to convert digests (checksums) into URI strings
* (based loosely on Magnet URIs)
* @author Chris Beer
* @since Mar 6, 2013
*/
public final class ContentDigest {
private static final Logger LOGGER = getLogger(ContentDigest.class);
public enum DIGEST_ALGORITHM {
SHA1("SHA-1", "urn:sha1"), SHA256("SHA-256", "urn:sha256"), MD5("MD5", "urn:md5"), MISSING("NONE", "missing");
final public String algorithm;
final private String scheme;
DIGEST_ALGORITHM(final String alg, final String scheme) {
this.algorithm = alg;
this.scheme = scheme;
}
/**
* Return the scheme associated with the provided algorithm (e.g. SHA-1 returns urn:sha1)
*
* @param alg for which scheme is requested
* @return scheme
*/
public static String getScheme(final String alg) {
return Arrays.stream(values()).filter(value ->
value.algorithm.equalsIgnoreCase(alg) || value.algorithm.replace("-", "").equalsIgnoreCase(alg)
).findFirst().orElse(MISSING).scheme;
}
/**
* Return enum value for the provided scheme (e.g. urn:sha1 returns SHA-1)
*
* @param argScheme for which enum is requested
* @return enum value associated with the arg scheme
*/
public static DIGEST_ALGORITHM fromScheme(final String argScheme) {
return Arrays.stream(values()).filter(value -> value.scheme.equalsIgnoreCase(argScheme)
).findFirst().orElse(MISSING);
}
/**
* Return true if the provided algorithm is included in this enum
*
* @param alg to test
* @return true if arg algorithm is supported
*/
public static boolean isSupportedAlgorithm(final String alg) {
return !getScheme(alg).equals(MISSING.scheme);
}
}
public static final String DEFAULT_ALGORITHM = DIGEST_ALGORITHM.SHA1.algorithm;
private ContentDigest() {
}
/**
* Convert a MessageDigest algorithm and checksum value to a URN
* @param algorithm the message digest algorithm
* @param value the checksum value
* @return URI
*/
public static URI asURI(final String algorithm, final String value) {
try {
final String scheme = DIGEST_ALGORITHM.getScheme(algorithm);
return new URI(scheme, value, null);
} catch (final URISyntaxException unlikelyException) {
LOGGER.warn("Exception creating checksum URI: {}",
unlikelyException);
throw new RepositoryRuntimeException(unlikelyException);
}
}
/**
* Convert a MessageDigest algorithm and checksum byte-array data to a URN
* @param algorithm the message digest algorithm
* @param data the checksum byte-array data
* @return URI
*/
public static URI asURI(final String algorithm, final byte[] data) {
return asURI(algorithm, asString(data));
}
/**
* Given a digest URI, get the corresponding MessageDigest algorithm
* @param digestUri the digest uri
* @return MessageDigest algorithm
*/
public static String getAlgorithm(final URI digestUri) {
if (digestUri == null) {
return DEFAULT_ALGORITHM;
}
return DIGEST_ALGORITHM.fromScheme(digestUri.getScheme() + ":" +
digestUri.getSchemeSpecificPart().split(":", 2)[0]).algorithm;
}
private static String asString(final byte[] data) {
return encodeHexString(data);
}
/**
* Placeholder checksum value.
* @return URI
*/
public static URI missingChecksum() {
return asURI(SHA1.algorithm, SHA1.scheme);
}
}