
com.netflix.evcache.EVCacheKey Maven / Gradle / Ivy
package com.netflix.evcache;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.netflix.archaius.api.Property;
import com.netflix.evcache.util.KeyHasher;
import com.netflix.evcache.util.KeyHasher.HashingAlgorithm;
public class EVCacheKey {
private static final Logger log = LoggerFactory.getLogger(EVCacheKey.class);
private final String appName;
private final HashingAlgorithm hashingAlgorithmAtAppLevel;
private final Property shouldEncodeHashKeyAtAppLevel;
private final Property maxDigestBytesAtAppLevel;
private final Property maxHashLengthAtAppLevel;
private final String key;
private final String canonicalKey;
private String canonicalKeyForDuet;
// Note that this we cache hashed keys based on Hashing Algorithm alone, but not based on other hashing properties
// like max.hash.length. So changing max.hash.length alone would not necessarily trigger hash recalculation, but
// one would have to change the hashing algorithm in order to having hashing properties taken into account.
// This is to make such a hashing property change very obvious and not subtle.
private final Map hashedKeysByAlgorithm;
private final Map hashedKeysByAlgorithmForDuet;
private final String encoder;
public EVCacheKey(String appName, String key, String canonicalKey, HashingAlgorithm hashingAlgorithmAtAppLevel, Property shouldEncodeHashKeyAtAppLevel, Property maxDigestBytesAtAppLevel, Property maxHashLengthAtAppLevel) {
this(appName, key, canonicalKey, hashingAlgorithmAtAppLevel, shouldEncodeHashKeyAtAppLevel, maxDigestBytesAtAppLevel, maxHashLengthAtAppLevel, null);
}
public EVCacheKey(String appName, String key, String canonicalKey, HashingAlgorithm hashingAlgorithmAtAppLevel, Property shouldEncodeHashKeyAtAppLevel, Property maxDigestBytesAtAppLevel, Property maxHashLengthAtAppLevel, String encoder) {
super();
this.appName = appName;
this.key = key;
this.canonicalKey = canonicalKey;
this.hashingAlgorithmAtAppLevel = hashingAlgorithmAtAppLevel;
this.shouldEncodeHashKeyAtAppLevel = shouldEncodeHashKeyAtAppLevel;
this.maxDigestBytesAtAppLevel = maxDigestBytesAtAppLevel;
this.maxHashLengthAtAppLevel = maxHashLengthAtAppLevel;
this.encoder = encoder;
hashedKeysByAlgorithm = new HashMap<>();
hashedKeysByAlgorithmForDuet = new HashMap<>();
}
public String getKey() {
return key;
}
@Deprecated
public String getCanonicalKey() {
return canonicalKey;
}
public String getCanonicalKey(boolean isDuet) {
return isDuet ? getCanonicalKeyForDuet() : canonicalKey;
}
private String getCanonicalKeyForDuet() {
if (null == canonicalKeyForDuet) {
final int duetKeyLength = appName.length() + 1 + canonicalKey.length();
canonicalKeyForDuet = new StringBuilder(duetKeyLength).append(appName).append(':').append(canonicalKey).toString();
if (log.isDebugEnabled()) log.debug("canonicalKeyForDuet : " + canonicalKeyForDuet);
}
return canonicalKeyForDuet;
}
@Deprecated
public String getHashKey() {
return getHashKey(hashingAlgorithmAtAppLevel, null == shouldEncodeHashKeyAtAppLevel ? null : shouldEncodeHashKeyAtAppLevel.get(), null == maxDigestBytesAtAppLevel ? null : maxDigestBytesAtAppLevel.get(), null == maxHashLengthAtAppLevel ? null : maxHashLengthAtAppLevel.get(), encoder);
}
// overlays app level hashing and client level hashing
public String getHashKey(boolean isDuet, HashingAlgorithm hashingAlgorithm, Boolean shouldEncodeHashKey, Integer maxDigestBytes, Integer maxHashLength, String baseEnoder) {
if (hashingAlgorithm == HashingAlgorithm.NO_HASHING) {
return null;
}
if (null == hashingAlgorithm) {
hashingAlgorithm = hashingAlgorithmAtAppLevel;
}
if (null == shouldEncodeHashKey) {
shouldEncodeHashKey = this.shouldEncodeHashKeyAtAppLevel.get();
}
if (null == maxDigestBytes) {
maxDigestBytes = this.maxDigestBytesAtAppLevel.get();
}
if (null == maxHashLength) {
maxHashLength = this.maxHashLengthAtAppLevel.get();
}
if(null == baseEnoder) {
baseEnoder = encoder;
}
final String rKey = isDuet ? getHashKeyForDuet(hashingAlgorithm, shouldEncodeHashKey, maxDigestBytes, maxHashLength, baseEnoder) : getHashKey(hashingAlgorithm, shouldEncodeHashKey, maxDigestBytes, maxHashLength, baseEnoder);
if (log.isDebugEnabled()) log.debug("Key : " + rKey);
return rKey;
}
// overlays app level hashing algorithm and client level hashing algorithm
public String getDerivedKey(boolean isDuet, HashingAlgorithm hashingAlgorithm, Boolean shouldEncodeHashKey, Integer maxDigestBytes, Integer maxHashLength, String baseEnoder) {
// this overlay of hashingAlgorithm helps determine if there at all needs to be hashing performed, otherwise, will return canonical key
if (null == hashingAlgorithm) {
hashingAlgorithm = hashingAlgorithmAtAppLevel;
}
final String derivedKey = null == hashingAlgorithm || hashingAlgorithm == HashingAlgorithm.NO_HASHING ? getCanonicalKey(isDuet) : getHashKey(isDuet, hashingAlgorithm, shouldEncodeHashKey, maxDigestBytes, maxHashLength, baseEnoder);
if (log.isDebugEnabled()) log.debug("derivedKey : " + derivedKey);
return derivedKey;
}
private String getHashKey(HashingAlgorithm hashingAlgorithm, Boolean shouldEncodeHashKey, Integer maxDigestBytes, Integer maxHashLength, String encoder) {
if (null == hashingAlgorithm) {
return null;
}
final String key = hashingAlgorithm.toString()+ maxDigestBytes != null ? maxDigestBytes.toString() : "-" + maxHashLength != null ? maxHashLength.toString() : "-" + encoder != null ? encoder : "-";
String val = hashedKeysByAlgorithm.get(key);
if(val == null) {
val = KeyHasher.getHashedKeyEncoded(getCanonicalKey(false), hashingAlgorithm, maxDigestBytes, maxHashLength, encoder);
hashedKeysByAlgorithm.put(key , val);
}
if (log.isDebugEnabled()) log.debug("getHashKey : " + val);
// TODO: Once the issue around passing hashedKey in bytes[] is figured, we will start using (nullable) shouldEncodeHashKey, and call KeyHasher.getHashedKeyInBytes() accordingly
return val;
}
private String getHashKeyForDuet(HashingAlgorithm hashingAlgorithm, Boolean shouldEncodeHashKey, Integer maxDigestBytes, Integer maxHashLength, String encoder) {
if (null == hashingAlgorithm) {
return null;
}
final String key = hashingAlgorithm.toString()+ maxDigestBytes != null ? maxDigestBytes.toString() : "-" + maxHashLength != null ? maxHashLength.toString() : "-" + encoder != null ? encoder : "-";
String val = hashedKeysByAlgorithmForDuet.get(key);
if(val == null) {
val = KeyHasher.getHashedKeyEncoded(getCanonicalKeyForDuet(), hashingAlgorithm, maxDigestBytes, maxHashLength, encoder);
hashedKeysByAlgorithmForDuet.put(key , val);
}
if (log.isDebugEnabled()) log.debug("getHashKeyForDuet : " + val);
// TODO: Once the issue around passing hashedKey in bytes[] is figured, we will start using (nullable) shouldEncodeHashKey, and call KeyHasher.getHashedKeyInBytes() accordingly
return val;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((canonicalKey == null) ? 0 : canonicalKey.hashCode());
result = prime * result + ((canonicalKeyForDuet == null) ? 0 : canonicalKeyForDuet.hashCode());
result = prime * result + ((key == null) ? 0 : key.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
EVCacheKey other = (EVCacheKey) obj;
if (canonicalKey == null) {
if (other.canonicalKey != null)
return false;
} else if (!canonicalKey.equals(other.canonicalKey))
return false;
if (canonicalKeyForDuet == null) {
if (other.canonicalKeyForDuet != null)
return false;
} else if (!canonicalKeyForDuet.equals(other.canonicalKeyForDuet))
return false;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equals(other.key))
return false;
return true;
}
@Override
public String toString() {
return "EVCacheKey [key=" + key + ", canonicalKey=" + canonicalKey + ", canonicalKeyForDuet=" + canonicalKeyForDuet + (hashedKeysByAlgorithm.size() > 0 ? ", hashedKeysByAlgorithm=" + hashedKeysByAlgorithm.toString() : "") + (hashedKeysByAlgorithmForDuet.size() > 0 ? ", hashedKeysByAlgorithmForDuet=" + hashedKeysByAlgorithmForDuet.toString() + "]" : "]");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy