com.datastax.oss.driver.internal.core.metadata.token.RandomTokenFactory Maven / Gradle / Ivy
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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 com.datastax.oss.driver.internal.core.metadata.token;
import com.datastax.oss.driver.api.core.metadata.token.Token;
import com.datastax.oss.driver.api.core.metadata.token.TokenRange;
import com.datastax.oss.driver.shaded.guava.common.base.Preconditions;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import net.jcip.annotations.ThreadSafe;
@ThreadSafe
public class RandomTokenFactory implements TokenFactory {
public static final String PARTITIONER_NAME = "org.apache.cassandra.dht.RandomPartitioner";
private static final BigInteger MIN_VALUE = BigInteger.ONE.negate();
static final BigInteger MAX_VALUE = BigInteger.valueOf(2).pow(127);
public static final RandomToken MIN_TOKEN = new RandomToken(MIN_VALUE);
public static final RandomToken MAX_TOKEN = new RandomToken(MAX_VALUE);
private final MessageDigest prototype;
private final boolean supportsClone;
public RandomTokenFactory() {
prototype = createMessageDigest();
boolean supportsClone;
try {
prototype.clone();
supportsClone = true;
} catch (CloneNotSupportedException e) {
supportsClone = false;
}
this.supportsClone = supportsClone;
}
@Override
public String getPartitionerName() {
return PARTITIONER_NAME;
}
@Override
public Token hash(ByteBuffer partitionKey) {
return new RandomToken(md5(partitionKey));
}
@Override
public Token parse(String tokenString) {
return new RandomToken(new BigInteger(tokenString));
}
@Override
public String format(Token token) {
Preconditions.checkArgument(
token instanceof RandomToken, "Can only format RandomToken instances");
return ((RandomToken) token).getValue().toString();
}
@Override
public Token minToken() {
return MIN_TOKEN;
}
@Override
public TokenRange range(Token start, Token end) {
Preconditions.checkArgument(
start instanceof RandomToken && end instanceof RandomToken,
"Can only build ranges of RandomToken instances");
return new RandomTokenRange((RandomToken) start, (RandomToken) end);
}
private static MessageDigest createMessageDigest() {
try {
return MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("MD5 doesn't seem to be available on this JVM", e);
}
}
private BigInteger md5(ByteBuffer data) {
MessageDigest digest = newMessageDigest();
digest.update(data.duplicate());
return new BigInteger(digest.digest()).abs();
}
private MessageDigest newMessageDigest() {
if (supportsClone) {
try {
return (MessageDigest) prototype.clone();
} catch (CloneNotSupportedException ignored) {
}
}
return createMessageDigest();
}
}