com.scurrilous.circe.impl.AbstractHashProvider Maven / Gradle / Ivy
/*******************************************************************************
* Copyright 2014 Trevor Robinson
*
* Licensed 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.scurrilous.circe.impl;
import java.util.EnumSet;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import com.scurrilous.circe.Hash;
import com.scurrilous.circe.HashParameters;
import com.scurrilous.circe.HashProvider;
import com.scurrilous.circe.HashSupport;
import com.scurrilous.circe.IncrementalIntHash;
import com.scurrilous.circe.IncrementalLongHash;
import com.scurrilous.circe.StatefulHash;
import com.scurrilous.circe.StatefulIntHash;
import com.scurrilous.circe.StatefulLongHash;
import com.scurrilous.circe.StatelessHash;
import com.scurrilous.circe.StatelessIntHash;
import com.scurrilous.circe.StatelessLongHash;
/**
* Base implementation for hash function providers.
*
* @param base supported hash parameters type
*/
public abstract class AbstractHashProvider
implements HashProvider {
private final Class
parametersClass;
/**
* Constructs a new {@link AbstractHashProvider} with the given base
* parameters class.
*
* @param parametersClass the base hash parameters class supported
*/
protected AbstractHashProvider(Class
parametersClass) {
this.parametersClass = parametersClass;
}
@Override
public final EnumSet querySupport(HashParameters params) {
if (!parametersClass.isAssignableFrom(params.getClass()))
return EnumSet.noneOf(HashSupport.class);
return querySupportTyped(parametersClass.cast(params));
}
/**
* Implemented by subclasses to provide information about the available
* implementations corresponding to the given hash algorithm parameters.
* Called by {@link #querySupport} if the hash parameters match the base
* type supported by this provider.
*
* @param params the hash algorithm parameters
* @return a set of flags indicating the level of support
*/
protected abstract EnumSet querySupportTyped(P params);
/**
* Requests a hash function using the given parameters and support flags.
* This method is only responsible for checking support flags returned by
* {@link #querySupportTyped}.
*
* To support caching of stateless hash functions, call
* {@link #getCacheable} from this method and implement
* {@link #createCacheable}.
*
* @param params the hash algorithm parameters
* @param required the required hash support flags
* @return a hash function
* @throws UnsupportedOperationException if this provider cannot support the
* given parameters
*/
protected abstract Hash get(P params, EnumSet required);
/**
* Called by implementations that support caching of stateless hash
* functions when a cached instance is desired. If a cached instance is not
* available, this method calls {@link #createCacheable} to create one,
* which is then cached (if caching is available).
*
* @param params the hash algorithm parameters
* @param required the required hash support flags
* @return a hash function
* @throws UnsupportedOperationException if this provider cannot support the
* given parameters
*/
protected final Hash getCacheable(final P params, final EnumSet required) {
if (HashCacheLoader.hasCache()) {
final HashCache cache = HashCacheLoader.getCache();
try {
return cache.get(params, required, new Callable() {
@Override
public Hash call() throws Exception {
return createCacheable(params, required);
}
});
} catch (ExecutionException e) {
final Throwable cause = e.getCause();
if (cause instanceof RuntimeException)
throw (RuntimeException) cause;
throw new UnsupportedOperationException(e);
}
}
return createCacheable(params, required);
}
/**
* Called by {@link #getCacheable} to create new cacheable stateless hash
* functions. The default implementation simply throws
* {@link UnsupportedOperationException}.
*
* @param params the hash algorithm parameters
* @param required the required hash support flags
* @return a stateless hash function
* @throws UnsupportedOperationException if this provider cannot support the
* given parameters
*/
protected StatelessHash createCacheable(P params, EnumSet required) {
throw new UnsupportedOperationException();
}
private Hash castAndGet(HashParameters params, EnumSet required) {
if (!parametersClass.isAssignableFrom(params.getClass()))
throw new UnsupportedOperationException();
return get(parametersClass.cast(params), required);
}
@Override
public StatefulHash createStateful(HashParameters params) {
final Hash hash = castAndGet(params, EnumSet.of(HashSupport.STATEFUL));
if (hash instanceof StatefulHash)
return (StatefulHash) hash;
if (hash instanceof StatelessHash)
return ((StatelessHash) hash).createStateful();
throw new UnsupportedOperationException();
}
@Override
public StatelessIntHash getStatelessInt(HashParameters params) {
final Hash hash = castAndGet(params, EnumSet.of(HashSupport.INT_SIZED));
if (hash instanceof StatelessIntHash)
return (StatelessIntHash) hash;
if (hash instanceof StatefulIntHash)
return ((StatefulIntHash) hash).asStateless();
throw new UnsupportedOperationException();
}
@Override
public StatelessLongHash getStatelessLong(HashParameters params) {
final Hash hash = castAndGet(params, EnumSet.of(HashSupport.LONG_SIZED));
if (hash instanceof StatelessLongHash)
return (StatelessLongHash) hash;
if (hash instanceof StatefulLongHash)
return ((StatefulLongHash) hash).asStateless();
if (hash instanceof StatelessIntHash)
return new IntStatelessLongHash((StatelessIntHash) hash);
if (hash instanceof StatefulIntHash)
return new IntStatelessLongHash(((StatefulIntHash) hash).asStateless());
throw new UnsupportedOperationException();
}
@Override
public IncrementalIntHash getIncrementalInt(HashParameters params) {
final Hash hash = castAndGet(params,
EnumSet.of(HashSupport.INT_SIZED, HashSupport.STATELESS_INCREMENTAL));
if (hash instanceof IncrementalIntHash)
return (IncrementalIntHash) hash;
throw new UnsupportedOperationException();
}
@Override
public IncrementalLongHash getIncrementalLong(HashParameters params) {
final Hash hash = castAndGet(params,
EnumSet.of(HashSupport.LONG_SIZED, HashSupport.STATELESS_INCREMENTAL));
if (hash instanceof IncrementalLongHash)
return (IncrementalLongHash) hash;
throw new UnsupportedOperationException();
}
}