From 29c601075b97ed891e2e8786a3259ca01127faf7 Mon Sep 17 00:00:00 2001 From: "J. Brisbin" Date: Mon, 27 Dec 2010 08:07:00 -0600 Subject: [PATCH] Fixes for using custom ClassLoaders, try/catch for getting metadata --- .../riak/core/AbstractRiakTemplate.java | 139 +++++++++++++----- .../data/keyvalue/riak/core/RiakTemplate.java | 40 +++-- 2 files changed, 128 insertions(+), 51 deletions(-) diff --git a/spring-data-riak/src/main/java/org/springframework/data/keyvalue/riak/core/AbstractRiakTemplate.java b/spring-data-riak/src/main/java/org/springframework/data/keyvalue/riak/core/AbstractRiakTemplate.java index d9f4b1b4b..345e97745 100644 --- a/spring-data-riak/src/main/java/org/springframework/data/keyvalue/riak/core/AbstractRiakTemplate.java +++ b/spring-data-riak/src/main/java/org/springframework/data/keyvalue/riak/core/AbstractRiakTemplate.java @@ -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 RiakValue extractValue(final ResponseEntity response, Class origType, Class requiredType) throws + protected RiakValue extractValue(final ResponseEntity response, Class origType, + Class 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 params = new LinkedList(); if (null != qosParams.getReadThreshold()) { params.add(String.format("r=%s", qosParams.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.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.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 Class getType(B bucket, K key) { - HttpHeaders headers = getRestTemplate().headForHeaders(defaultUri, bucket, key); + return getType(bucket, key, getClass().getClassLoader()); + } + + protected 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; } diff --git a/spring-data-riak/src/main/java/org/springframework/data/keyvalue/riak/core/RiakTemplate.java b/spring-data-riak/src/main/java/org/springframework/data/keyvalue/riak/core/RiakTemplate.java index 432789fb6..518bde723 100644 --- a/spring-data-riak/src/main/java/org/springframework/data/keyvalue/riak/core/RiakTemplate.java +++ b/spring-data-riak/src/main/java/org/springframework/data/keyvalue/riak/core/RiakTemplate.java @@ -104,7 +104,8 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue return setWithMetaData(bucket, key, value, null, null); } - public BucketKeyValueStoreOperations set(B bucket, K key, V value, QosParameters qosParams) { + public 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 BucketKeyValueStoreOperations setAsBytes(B bucket, K key, byte[] value, QosParameters qosParams) { + public BucketKeyValueStoreOperations setAsBytes(B bucket, K key, byte[] value, + QosParameters qosParams) { return setWithMetaData(bucket, key, value, null, qosParams); } - public BucketKeyValueStoreOperations setWithMetaData(B bucket, K key, V value, Map metaData, QosParameters qosParams) { + public BucketKeyValueStoreOperations setWithMetaData(B bucket, K key, V value, + Map 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 entity = new HttpEntity(value, headers); try { restTemplate.put(defaultUri, entity, bucket, keyName); @@ -152,7 +160,8 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue return this; } - public BucketKeyValueStoreOperations setWithMetaData(B bucket, K key, V value, Map metaData) { + public BucketKeyValueStoreOperations setWithMetaData(B bucket, K key, V value, + Map 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 val = null; try { ResponseEntity result = restTemplate.getForEntity(defaultUri, @@ -301,7 +310,7 @@ public class RiakTemplate extends AbstractRiakTemplate implements BucketKeyValue @SuppressWarnings({"unchecked"}) public T get(B bucket, K key) { - Class targetClass = getType(bucket, key); + Class targetClass = getType(bucket, key, classLoader); RiakValue 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 BucketKeyValueStoreOperations setIfKeyNonExistentAsBytes(B bucket, K key, byte[] value) { + public 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 RiakTemplate link(B1 destBucket, K1 destKey, B2 sourceBucket, K2 sourceKey, String tag) { + public 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 BucketKeyValueStoreOperations updateBucketSchema(B bucket, Map props) { + public BucketKeyValueStoreOperations updateBucketSchema(B bucket, + Map props) { Map bucketProps = new LinkedHashMap(); bucketProps.put("props", props); RestTemplate restTemplate = getRestTemplate();