Fixes for using custom ClassLoaders, try/catch for getting metadata

This commit is contained in:
J. Brisbin
2010-12-27 08:07:00 -06:00
parent a7c2558cda
commit 29c601075b
2 changed files with 128 additions and 51 deletions

View File

@@ -39,6 +39,7 @@ import org.springframework.http.converter.json.MappingJacksonHttpMessageConverte
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.client.support.RestGatewaySupport;
@@ -93,7 +94,8 @@ public abstract class AbstractRiakTemplate extends RestGatewaySupport implements
/**
* For converting objects to/from other kinds of objects.
*/
protected ConversionService conversionService = ConversionServiceFactory.createDefaultConversionService();
protected ConversionService conversionService = ConversionServiceFactory
.createDefaultConversionService();
/**
* For caching objects based on ETags.
*/
@@ -123,6 +125,9 @@ public abstract class AbstractRiakTemplate extends RestGatewaySupport implements
*/
protected QosParameters defaultQosParameters = null;
protected Class<?> defaultType = String.class;
protected ClassLoader classLoader = null;
/**
* Take all the defaults.
*/
@@ -187,6 +192,42 @@ public abstract class AbstractRiakTemplate extends RestGatewaySupport implements
this.defaultQosParameters = defaultQosParameters;
}
/**
* Get the default type to use if none can be inferred.
*
* @return
*/
public Class<?> getDefaultType() {
return defaultType;
}
/**
* Set the default type to use if none can be inferred.
*
* @param defaultType
*/
public void setDefaultType(Class<?> defaultType) {
this.defaultType = defaultType;
}
/**
* Get the {@link ClassLoader} to use when trying to load objects from the store.
*
* @return
*/
public ClassLoader getClassLoader() {
return classLoader;
}
/**
* Set the {@link ClassLoader} to use when trying to load objects from the store.
*
* @param classLoader
*/
public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
public String getHost() {
Matcher m = prefix.matcher(defaultUri);
if (m.matches()) {
@@ -278,7 +319,7 @@ public abstract class AbstractRiakTemplate extends RestGatewaySupport implements
protected MediaType extractMediaType(Object value) {
MediaType mediaType = (value instanceof byte[] ? MediaType.APPLICATION_OCTET_STREAM : MediaType.APPLICATION_JSON);
if (value.getClass().getAnnotations().length > 0) {
if (null != value && value.getClass().getAnnotations().length > 0) {
KeyValueStoreMetaData meta = value.getClass()
.getAnnotation(KeyValueStoreMetaData.class);
if (null != meta) {
@@ -327,7 +368,8 @@ public abstract class AbstractRiakTemplate extends RestGatewaySupport implements
}
@SuppressWarnings({"unchecked"})
protected <T> RiakValue<T> extractValue(final ResponseEntity<?> response, Class<?> origType, Class<T> requiredType) throws
protected <T> RiakValue<T> extractValue(final ResponseEntity<?> response, Class<?> origType,
Class<T> requiredType) throws
IOException {
if (response.hasBody()) {
RiakMetaData meta = extractMetaData(response.getHeaders());
@@ -346,8 +388,9 @@ public abstract class AbstractRiakTemplate extends RestGatewaySupport implements
o = conv.read(requiredType, new HttpInputMessage() {
public InputStream getBody() throws IOException {
Object body = response.getBody();
return new ByteArrayInputStream((body instanceof byte[] ? (byte[]) body : ((String) body)
.getBytes()));
return new ByteArrayInputStream(
(body instanceof byte[] ? (byte[]) body : ((String) body)
.getBytes()));
}
public HttpHeaders getHeaders() {
@@ -360,7 +403,8 @@ public abstract class AbstractRiakTemplate extends RestGatewaySupport implements
}
} else {
throw new DataStoreOperationException("Cannot convert object of type " + origType + " to type " + requiredType);
throw new DataStoreOperationException(
"Cannot convert object of type " + origType + " to type " + requiredType);
}
}
}
@@ -377,19 +421,23 @@ public abstract class AbstractRiakTemplate extends RestGatewaySupport implements
String bucketName = (null != bucketKeyPair.getBucket() ? bucketKeyPair.getBucket()
.toString() : requiredType.getName());
RestTemplate restTemplate = getRestTemplate();
HttpHeaders resp = restTemplate.headForHeaders(defaultUri,
bucketName,
bucketKeyPair.getKey());
if (!obj.getMetaData()
.getProperties()
.get("ETag")
.toString()
.equals(resp.getETag())) {
obj = null;
} else {
if (log.isDebugEnabled()) {
log.debug("Returning CACHED object: " + obj);
try {
HttpHeaders resp = restTemplate.headForHeaders(defaultUri,
bucketName,
bucketKeyPair.getKey());
if (!obj.getMetaData()
.getProperties()
.get("ETag")
.toString()
.equals(resp.getETag())) {
obj = null;
} else {
if (log.isDebugEnabled()) {
log.debug("Returning CACHED object: " + obj);
}
}
} catch (ResourceAccessException ignored) {
return null;
}
}
@@ -411,17 +459,20 @@ public abstract class AbstractRiakTemplate extends RestGatewaySupport implements
List<String> params = new LinkedList<String>();
if (null != qosParams.getReadThreshold()) {
params.add(String.format("r=%s", qosParams.<Object>getReadThreshold()));
} else if (null != defaultQosParameters && null != defaultQosParameters.getReadThreshold()) {
} else if (null != defaultQosParameters && null != defaultQosParameters
.getReadThreshold()) {
params.add(String.format("r=%s", defaultQosParameters.getReadThreshold()));
}
if (null != qosParams.getWriteThreshold()) {
params.add(String.format("w=%s", qosParams.<Object>getWriteThreshold()));
} else if (null != defaultQosParameters && null != defaultQosParameters.getWriteThreshold()) {
} else if (null != defaultQosParameters && null != defaultQosParameters
.getWriteThreshold()) {
params.add(String.format("w=%s", defaultQosParameters.getWriteThreshold()));
}
if (null != qosParams.getDurableWriteThreshold()) {
params.add(String.format("dw=%s", qosParams.<Object>getDurableWriteThreshold()));
} else if (null != defaultQosParameters && null != defaultQosParameters.getDurableWriteThreshold()) {
} else if (null != defaultQosParameters && null != defaultQosParameters
.getDurableWriteThreshold()) {
params.add(String.format("dw=%s", defaultQosParameters.getDurableWriteThreshold()));
}
@@ -443,27 +494,39 @@ public abstract class AbstractRiakTemplate extends RestGatewaySupport implements
}
protected <B, K> Class<?> getType(B bucket, K key) {
HttpHeaders headers = getRestTemplate().headForHeaders(defaultUri, bucket, key);
return getType(bucket, key, getClass().getClassLoader());
}
protected <B, K> Class<?> getType(B bucket, K key, ClassLoader classLoader) {
Class<?> clazz = null;
if (null != headers) {
String s = headers.getFirst(RIAK_META_CLASSNAME);
if (null != s) {
try {
clazz = Class.forName(s);
} catch (ClassNotFoundException ignored) {
try {
HttpHeaders headers = getRestTemplate().headForHeaders(defaultUri, bucket, key);
if (null != headers) {
String s = headers.getFirst(RIAK_META_CLASSNAME);
if (null != s) {
try {
if (null != classLoader) {
clazz = Class.forName(s, false, classLoader);
} else {
clazz = Class.forName(s);
}
} catch (ClassNotFoundException ignored) {
}
}
}
}
if (null == clazz) {
if (headers.getContentType().equals(MediaType.APPLICATION_JSON)) {
clazz = Map.class;
} else if (headers.getContentType().equals(MediaType.TEXT_PLAIN)) {
clazz = String.class;
} else {
// handle as bytes
log.error("Need to handle bytes!");
clazz = byte[].class;
if (null == clazz) {
if (headers.getContentType().equals(MediaType.APPLICATION_JSON)) {
clazz = Map.class;
} else if (headers.getContentType().equals(MediaType.TEXT_PLAIN)) {
clazz = String.class;
} else {
// handle as bytes
log.error("Need to handle bytes!");
clazz = byte[].class;
}
}
} catch (ResourceAccessException notFound) {
clazz = String.class;
}
return clazz;
}

View File

@@ -104,7 +104,8 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue
return setWithMetaData(bucket, key, value, null, null);
}
public <B, K, V> BucketKeyValueStoreOperations set(B bucket, K key, V value, QosParameters qosParams) {
public <B, K, V> BucketKeyValueStoreOperations set(B bucket, K key, V value,
QosParameters qosParams) {
return setWithMetaData(bucket, key, value, null, qosParams);
}
@@ -112,11 +113,14 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue
return setAsBytes(bucket, key, value, null);
}
public <B, K> BucketKeyValueStoreOperations setAsBytes(B bucket, K key, byte[] value, QosParameters qosParams) {
public <B, K> BucketKeyValueStoreOperations setAsBytes(B bucket, K key, byte[] value,
QosParameters qosParams) {
return setWithMetaData(bucket, key, value, null, qosParams);
}
public <B, K, V> BucketKeyValueStoreOperations setWithMetaData(B bucket, K key, V value, Map<String, String> metaData, QosParameters qosParams) {
public <B, K, V> BucketKeyValueStoreOperations setWithMetaData(B bucket, K key, V value,
Map<String, String> metaData,
QosParameters qosParams) {
Assert.notNull(key, "Key cannot be null!");
// Get a key name that may or may not include the QOS parameters.
String keyName = (null != qosParams ? key.toString() + extractQosParameters(qosParams) : key
@@ -130,6 +134,9 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue
RestTemplate restTemplate = getRestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set("X-Riak-ClientId", RIAK_CLIENT_ID);
if (log.isDebugEnabled() && null == value) {
log.debug("bucket=" + bucket + ", key=" + key);
}
headers.setContentType(extractMediaType(value));
if (null != vclock) {
headers.set(RIAK_VCLOCK, vclock);
@@ -139,7 +146,8 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue
headers.set(entry.getKey(), entry.getValue());
}
}
headers.set(RIAK_META_CLASSNAME, value.getClass().getName());
headers.set(RIAK_META_CLASSNAME,
(null != value ? value.getClass().getName() : defaultType.getName()));
HttpEntity<V> entity = new HttpEntity<V>(value, headers);
try {
restTemplate.put(defaultUri, entity, bucket, keyName);
@@ -152,7 +160,8 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue
return this;
}
public <B, K, V> BucketKeyValueStoreOperations setWithMetaData(B bucket, K key, V value, Map<String, String> metaData) {
public <B, K, V> BucketKeyValueStoreOperations setWithMetaData(B bucket, K key, V value,
Map<String, String> metaData) {
return setWithMetaData(bucket, key, value, metaData, null);
}
@@ -233,7 +242,7 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue
key,
requiredType.getName()));
}
Class<?> origType = getType(bucket, key);
Class<?> origType = getType(bucket, key, classLoader);
RiakValue<T> val = null;
try {
ResponseEntity<?> result = restTemplate.getForEntity(defaultUri,
@@ -301,7 +310,7 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue
@SuppressWarnings({"unchecked"})
public <B, K, T> T get(B bucket, K key) {
Class targetClass = getType(bucket, key);
Class targetClass = getType(bucket, key, classLoader);
RiakValue<T> obj = getWithMetaData(bucket, key, targetClass);
return (null != obj ? obj.get() : null);
}
@@ -443,7 +452,8 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue
return this;
}
public <B, K> BucketKeyValueStoreOperations setIfKeyNonExistentAsBytes(B bucket, K key, byte[] value) {
public <B, K> BucketKeyValueStoreOperations setIfKeyNonExistentAsBytes(B bucket, K key,
byte[] value) {
if (!containsKey(bucket, key)) {
setAsBytes(bucket, key, value);
} else {
@@ -523,7 +533,8 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue
return conv.convert(obj, targetType);
} else {
throw new DataAccessResourceFailureException(
"Can't find a converter to to convert " + obj.getClass() + " returned from M/R job to required type " + targetType);
"Can't find a converter to to convert " + obj
.getClass() + " returned from M/R job to required type " + targetType);
}
} else {
return (T) obj;
@@ -557,7 +568,8 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue
* @return
*/
@SuppressWarnings({"unchecked"})
public <B1, K1, B2, K2> RiakTemplate link(B1 destBucket, K1 destKey, B2 sourceBucket, K2 sourceKey, String tag) {
public <B1, K1, B2, K2> RiakTemplate link(B1 destBucket, K1 destKey, B2 sourceBucket,
K2 sourceKey, String tag) {
RestTemplate restTemplate = getRestTemplate();
// Skip all conversion on the data since all we care about is the Link header.
@@ -677,11 +689,12 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue
}
Class<?> clazz = requiredType;
if (null == clazz) {
clazz = getType(bucketName, key);
clazz = getType(bucketName, key, classLoader);
}
// Can convert message?
for (HttpMessageConverter converter : restTemplate.getMessageConverters()) {
for (HttpMessageConverter converter : restTemplate
.getMessageConverters()) {
if (converter.canRead(clazz, MediaType.parseMediaType(partType))) {
HttpInputMessage msg = new HttpInputMessage() {
public InputStream getBody() throws IOException {
@@ -745,7 +758,8 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue
}
@SuppressWarnings({"unchecked"})
public <B> BucketKeyValueStoreOperations updateBucketSchema(B bucket, Map<String, Object> props) {
public <B> BucketKeyValueStoreOperations updateBucketSchema(B bucket,
Map<String, Object> props) {
Map<Object, Object> bucketProps = new LinkedHashMap<Object, Object>();
bucketProps.put("props", props);
RestTemplate restTemplate = getRestTemplate();