You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by wo...@apache.org on 2010/09/22 18:26:58 UTC

svn commit: r1000070 - in /incubator/libcloud/sandbox/java/trunk/src/simplecloud/storage: interfaces/IStorageAdapter.java providers/amazon/S3Adapter.java providers/nirvanix/NirvanixAdapter.java

Author: woodser
Date: Wed Sep 22 16:26:57 2010
New Revision: 1000070

URL: http://svn.apache.org/viewvc?rev=1000070&view=rev
Log:
Added metadata management support to Nirvanix & Amazon S3 adapters.
- 10/10 calls implemented for Amazon S3
- 10/10 calls implemented for Nirvanix
- Modification to IStorageAdapter interface to support metadata calls

Modified:
    incubator/libcloud/sandbox/java/trunk/src/simplecloud/storage/interfaces/IStorageAdapter.java
    incubator/libcloud/sandbox/java/trunk/src/simplecloud/storage/providers/amazon/S3Adapter.java
    incubator/libcloud/sandbox/java/trunk/src/simplecloud/storage/providers/nirvanix/NirvanixAdapter.java

Modified: incubator/libcloud/sandbox/java/trunk/src/simplecloud/storage/interfaces/IStorageAdapter.java
URL: http://svn.apache.org/viewvc/incubator/libcloud/sandbox/java/trunk/src/simplecloud/storage/interfaces/IStorageAdapter.java?rev=1000070&r1=1000069&r2=1000070&view=diff
==============================================================================
--- incubator/libcloud/sandbox/java/trunk/src/simplecloud/storage/interfaces/IStorageAdapter.java (original)
+++ incubator/libcloud/sandbox/java/trunk/src/simplecloud/storage/interfaces/IStorageAdapter.java Wed Sep 22 16:26:57 2010
@@ -16,7 +16,7 @@ public interface IStorageAdapter {
 	
 	public IItem fetchItem(String path, Map<Object, Object> options);
 	
-	public boolean storeItem(String destinationPath, IItem item, Map<Object, Object> options);
+	public boolean storeItem(String destinationPath, IItem item, Map<String, String> metadata, Map<Object, Object> options);
 	
 	public void deleteItem(String path, Map<Object, Object> options);
 	

Modified: incubator/libcloud/sandbox/java/trunk/src/simplecloud/storage/providers/amazon/S3Adapter.java
URL: http://svn.apache.org/viewvc/incubator/libcloud/sandbox/java/trunk/src/simplecloud/storage/providers/amazon/S3Adapter.java?rev=1000070&r1=1000069&r2=1000070&view=diff
==============================================================================
--- incubator/libcloud/sandbox/java/trunk/src/simplecloud/storage/providers/amazon/S3Adapter.java (original)
+++ incubator/libcloud/sandbox/java/trunk/src/simplecloud/storage/providers/amazon/S3Adapter.java Wed Sep 22 16:26:57 2010
@@ -26,9 +26,7 @@ import base.interfaces.IResponse;
 /*
  * Adapter for interacting with Amazon S3.
  * 
- * TODO: different locations
- * TODO: comment required option parameters
- * TODO: general comments
+ * TODO: support different geographic locations
  */
 public class S3Adapter extends StorageAdapter {
 	
@@ -54,6 +52,9 @@ public class S3Adapter extends StorageAd
 		connection = new S3Connection(accessId, accessKey, host, this);
 	}
 
+	/*
+	 * Required options: Type.SRC_BUCKET
+	 */
 	public IItem fetchItem(String path, Map<Object, Object> options) {
 		String bucket = (String)options.get(Type.SRC_BUCKET);
 		connection.connect(bucket + '.' + HOST);
@@ -62,14 +63,20 @@ public class S3Adapter extends StorageAd
 		return (IItem)rh.getParsedObject();
 	}
 
-	public boolean storeItem(String destinationPath, IItem item, Map<Object, Object> options) {
+	/* 
+	 * Required options: Type.SRC_BUCKET
+	 */
+	public boolean storeItem(String destinationPath, IItem item, Map<String, String> metadata, Map<Object, Object> options) {
 		String bucket = (String)options.get(Type.SRC_BUCKET);
 		connection.connect(bucket + '.' + HOST);
-		IResponse response = connection.request("PUT", destinationPath, null, null, item);
+		IResponse response = connection.request("PUT", destinationPath, metadata, null, item);
 		new S3Handler(response);
 		return response.getStatus() == 200;
 	}
 	
+	/*
+	 * Required options: Type.SRC_BUCKET
+	 */
 	public void deleteItem(String path, Map<Object, Object> options) {
 		String bucket = (String)options.get(Type.SRC_BUCKET);
 		connection.connect(bucket + '.' + HOST);
@@ -77,6 +84,9 @@ public class S3Adapter extends StorageAd
 		new S3Handler(response);
 	}
 
+	/*
+	 * Required options: Type.SRC_BUCKET, Type.DEST_BUCKET
+	 */
 	public void copyItem(String sourcePath, String destinationPath, Map<Object, Object> options) {
 		String srcBucket = (String)options.get(Type.SRC_BUCKET);
 		String destBucket = (String)options.get(Type.DEST_BUCKET);
@@ -87,6 +97,9 @@ public class S3Adapter extends StorageAd
 		new S3Handler(response);
 	}
 
+	/*
+	 * Required options: Type.SRC_BUCKET, Type.DEST_BUCKET
+	 */
 	public void moveItem(String sourcePath, String destinationPath, Map<Object, Object> options) {
 		// Copy the item
 		String srcBucket = (String)options.get(Type.SRC_BUCKET);
@@ -103,12 +116,18 @@ public class S3Adapter extends StorageAd
 		new S3Handler(response);
 	}
 
+	/*
+	 * Required options: Type.SRC_BUCKET
+	 */
 	public void renameItem(String path, String name, Map<Object, Object> options) {
 		String destPath = path.substring(0, path.lastIndexOf('/') + 1) + name;
 		options.put(Type.DEST_BUCKET, options.get(Type.SRC_BUCKET));
 		moveItem(path, destPath, options);
 	}
 
+	/*
+	 * Required options: Type.SRC_BUCKET
+	 */
 	public List<String> listItems(String path, Map<Object, Object> options) {
 		String bucket = (String)options.get(Type.SRC_BUCKET);
 		connection.connect(bucket + '.' + HOST);
@@ -130,22 +149,37 @@ public class S3Adapter extends StorageAd
 		return null;	// Error
 	}
 
-	@Override
+	/*
+	 * Required options: Type.SRC_BUCKET
+	 */
 	public Map<String, String> fetchMetadata(String path, Map<Object, Object> options) {
-		// TODO Auto-generated method stub
-		return null;
+		String bucket = (String)options.get(Type.SRC_BUCKET);
+		connection.connect(bucket + '.' + HOST);
+		IResponse response = connection.request("GET", path, null, null, null);
+		new S3Handler(response);
+		return response.getHeaders();
 	}
 
-	@Override
+	/*
+	 * The key/value metadata is forwarded directly to the server without
+	 * interpretation.
+	 * 
+	 * Required options: Type.SRC_BUCKET
+	 */
 	public void storeMetadata(String destinationPath, Map<String, String> metadata, Map<Object, Object> options) {
-		// TODO Auto-generated method stub
-		
+		String bucket = (String)options.get(Type.SRC_BUCKET);
+		connection.connect(bucket + '.' + HOST);
+		IResponse response = connection.request("PUT", destinationPath, metadata, null, null);
+		new S3Handler(response);
 	}
 
-	@Override
+	/*
+	 * Amazon S3 does not currently support deleting metadata.
+	 * 
+	 * Workaround: fetchItem, deleteItem, then storeItem with updated metadata
+	 */
 	public void deleteMetadata(String path, Map<Object, Object> options) {
-		// TODO Auto-generated method stub
-		
+		throw new RuntimeException("Deleting metadata is not supported");
 	}
 	
 	private List<String> parseItems(Element elem) {

Modified: incubator/libcloud/sandbox/java/trunk/src/simplecloud/storage/providers/nirvanix/NirvanixAdapter.java
URL: http://svn.apache.org/viewvc/incubator/libcloud/sandbox/java/trunk/src/simplecloud/storage/providers/nirvanix/NirvanixAdapter.java?rev=1000070&r1=1000069&r2=1000070&view=diff
==============================================================================
--- incubator/libcloud/sandbox/java/trunk/src/simplecloud/storage/providers/nirvanix/NirvanixAdapter.java (original)
+++ incubator/libcloud/sandbox/java/trunk/src/simplecloud/storage/providers/nirvanix/NirvanixAdapter.java Wed Sep 22 16:26:57 2010
@@ -94,8 +94,9 @@ public class NirvanixAdapter extends Dri
 
 	/*
 	 * TODO: This was hacked together because of lacking multipart-form posts in ConnectionKey.
+	 * TODO: metadata
 	 */
-	public boolean storeItem(String destinationPath, IItem item, Map<Object, Object> options) {
+	public boolean storeItem(String destinationPath, IItem item, Map<String, String> metadata, Map<Object, Object> options) {
 		// First get the StorageNode
 		Map<String, String> nodeParams = new HashMap<String, String>();
 		nodeParams.put("sessionToken", sessionToken);
@@ -219,22 +220,47 @@ public class NirvanixAdapter extends Dri
 		return parseItems((Document)rh.getParsedObject());
 	}
 
-	@Override
 	public Map<String, String> fetchMetadata(String path, Map<Object, Object> options) {
-		// TODO Auto-generated method stub
-		return null;
+		Map<String, String> params = new HashMap<String, String>();
+		params.put("sessionToken", sessionToken);
+		params.put("path", path);
+		IResponse response = connection.request("GET", "/ws/Metadata/GetMetadata.ashx", null, params, null);
+		NirvanixHandler handler = new NirvanixHandler(response);
+		return parseMetadata((Document)handler.getParsedObject());
 	}
 
-	@Override
+	/*
+	 * NOTE: Because Nirvanix specifies multiple metadata key/value pairs with
+	 * the same key, and a Map is used to store the key/value pairs, only one
+	 * metadata item may be stored at a time.
+	 * 
+	 * TODO: Possibly use List<KeyValuePair> for headers/params? Map does not
+	 * support multi-mapping.
+	 */
 	public void storeMetadata(String destinationPath, Map<String, String> metadata, Map<Object, Object> options) {
-		// TODO Auto-generated method stub
-
+		if (metadata.keySet().size() != 1) {
+			throw new RuntimeException("Support limitation: exactly one metadata key/value pair must be set");
+		}
+		
+		String metadataParam = "";
+		for (String key : metadata.keySet()) {
+			metadataParam += key + ":" + metadata.get(key);
+		}
+		
+		Map<String, String> params = new HashMap<String, String>();
+		params.put("sessionToken", sessionToken);
+		params.put("path", destinationPath);
+		params.put("metadata", metadataParam);
+		IResponse response = connection.request("GET", "/ws/Metadata/SetMetadata.ashx", null, params, null);
+		new NirvanixHandler(response);
 	}
 
-	@Override
 	public void deleteMetadata(String path, Map<Object, Object> options) {
-		// TODO Auto-generated method stub
-
+		Map<String, String> params = new HashMap<String, String>();
+		params.put("sessionToken", sessionToken);
+		params.put("path", path);
+		IResponse response = connection.request("GET", "/ws/Metadata/DeleteAllMetadata.ashx", null, params, null);
+		new NirvanixHandler(response);
 	}
 	
 	private List<String> parseDownloadNodes(Document doc) {
@@ -293,6 +319,22 @@ public class NirvanixAdapter extends Dri
 		return null;	// Error
 	}
 	
+	private Map<String, String> parseMetadata(Document doc) {
+		try {
+			Map<String, String> metadata = new HashMap<String, String>();
+			XPath xpath = XPathFactory.newInstance().newXPath();
+			NodeList types = (NodeList)xpath.evaluate("/Response/Metadata/Type", doc.getDocumentElement(), XPathConstants.NODESET);
+			NodeList values = (NodeList)xpath.evaluate("/Response/Metadata/Value", doc.getDocumentElement(), XPathConstants.NODESET);
+			for (int i = 0; i < types.getLength(); i++) {
+				metadata.put(types.item(i).getTextContent(), values.item(i).getTextContent());
+			}
+			return metadata;
+		} catch (XPathExpressionException e) {
+			e.printStackTrace();
+			return null;
+		}
+	}
+	
 	/*
 	 * Simple extension of InputStreamBody to support length.
 	 *