diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/CDMIObject.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/CDMIObject.java index 59508653ed..52faa8ecc1 100644 --- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/CDMIObject.java +++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/CDMIObject.java @@ -29,137 +29,144 @@ import com.google.common.base.Objects.ToStringHelper; /** * The base type for all objects in the CDMI model. * - * @author Adrian Cole + * @author Kenneth Nagin */ public class CDMIObject { - public static Builder builder() { - return new ConcreteBuilder(); - } + public static Builder builder() { + return new ConcreteBuilder(); + } - public Builder toBuilder() { - return builder().fromCDMIObject(this); - } + public Builder toBuilder() { + return builder().fromCDMIObject(this); + } - private static class ConcreteBuilder extends Builder { - } + private static class ConcreteBuilder extends Builder { + } - public static abstract class Builder> { - private String objectID; - private String objectType; - private String objectName; + public static abstract class Builder> { + private String objectID; + private String objectType; + private String objectName; - @SuppressWarnings("unchecked") - protected B self() { - return (B) this; - } + @SuppressWarnings("unchecked") + protected B self() { + return (B) this; + } - /** - * @see CDMIObject#getObjectID() - */ - public B objectID(String objectID) { - this.objectID = objectID; - return self(); - } + /** + * @see CDMIObject#getObjectID() + */ + public B objectID(String objectID) { + this.objectID = objectID; + return self(); + } - /** - * @see CDMIObject#getObjectType() - */ - public B objectType(String objectType) { - this.objectType = objectType; - return self(); - } + /** + * @see CDMIObject#getObjectType() + */ + public B objectType(String objectType) { + this.objectType = objectType; + return self(); + } - /** - * @see CDMIObject#getObjectName() - */ - public B objectName(String objectName) { - this.objectName = objectName; - return self(); - } + /** + * @see CDMIObject#getObjectName() + */ + public B objectName(String objectName) { + this.objectName = objectName; + return self(); + } - public CDMIObject build() { - return new CDMIObject(this); - } + public CDMIObject build() { + return new CDMIObject(this); + } - protected B fromCDMIObject(CDMIObject in) { - return objectID(in.getObjectID()).objectType(in.getObjectType()).objectName(in.getObjectName()); - } - } + protected B fromCDMIObject(CDMIObject in) { + return objectID(in.getObjectID()).objectType(in.getObjectType()) + .objectName(in.getObjectName()); + } + } - private final String objectID; - private final String objectType; - private final String objectName; + private final String objectID; + private final String objectType; + private final String objectName; - protected CDMIObject(Builder builder) { - this.objectID = checkNotNull(builder.objectID, "objectID"); - this.objectType = checkNotNull(builder.objectType, "objectType"); - this.objectName = builder.objectName; - } + protected CDMIObject(Builder builder) { + this.objectID = checkNotNull(builder.objectID, "objectID"); + this.objectType = checkNotNull(builder.objectType, "objectType"); + this.objectName = builder.objectName; + } - /** - * Object ID of the object
- * Every object stored within a CDMI-compliant system shall have a globally unique object - * identifier (ID) assigned at creation time. The CDMI object ID is a string with requirements - * for how it is generated and how it obtains its uniqueness. Each offering that implements CDMI - * is able to produce these identifiers without conflicting with other offerings. - */ - public String getObjectID() { - return objectID; - } + /** + * Object ID of the object
+ * Every object stored within a CDMI-compliant system shall have a globally + * unique object identifier (ID) assigned at creation time. The CDMI object + * ID is a string with requirements for how it is generated and how it + * obtains its uniqueness. Each offering that implements CDMI is able to + * produce these identifiers without conflicting with other offerings. + * + * note: CDMI Servers do not always support ObjectID tags, however + * downstream jclouds code does not handle null so we return a empty String + * instead. + */ + public String getObjectID() { + return (objectID == null) ? "" : objectID; + } - /** - * - * type of the object - */ - public String getObjectType() { - return objectType; - } + /** + * + * type of the object + */ + public String getObjectType() { + return objectType; + } - /** - * For objects in a container, the objectName field shall be returned. For objects not in a - * container (objects that are only accessible by ID), the objectName field shall not be - * returned. - * - * Name of the object - */ - @Nullable - public String getObjectName() { - return objectName; - } + /** + * For objects in a container, the objectName field shall be returned. For + * objects not in a container (objects that are only accessible by ID), the + * objectName field shall not be returned. + * + * Name of the object + */ + @Nullable + public String getObjectName() { + return (objectName == null) ? "" : objectName; + } - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - CDMIObject that = CDMIObject.class.cast(o); - return equal(this.objectID, that.objectID) && equal(this.objectName, that.objectName) - && equal(this.objectType, that.objectType); - } + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + CDMIObject that = CDMIObject.class.cast(o); + return equal(this.objectID, that.objectID) + && equal(this.objectName, that.objectName) + && equal(this.objectType, that.objectType); + } - public boolean clone(Object o) { - if (this == o) - return false; - if (o == null || getClass() != o.getClass()) - return false; - CDMIObject that = CDMIObject.class.cast(o); - return equal(this.objectType, that.objectType); - } + public boolean clone(Object o) { + if (this == o) + return false; + if (o == null || getClass() != o.getClass()) + return false; + CDMIObject that = CDMIObject.class.cast(o); + return equal(this.objectType, that.objectType); + } - @Override - public int hashCode() { - return Objects.hashCode(objectID, objectName, objectType); - } + @Override + public int hashCode() { + return Objects.hashCode(objectID, objectName, objectType); + } - @Override - public String toString() { - return string().toString(); - } + @Override + public String toString() { + return string().toString(); + } - protected ToStringHelper string() { - return Objects.toStringHelper("").add("objectID", objectID).add("objectName", objectName).add("objectType", - objectType); - } + protected ToStringHelper string() { + return Objects.toStringHelper("").add("objectID", objectID) + .add("objectName", objectName).add("objectType", objectType); + } } diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/Container.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/Container.java index f0d1affb08..24567f541a 100644 --- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/Container.java +++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/Container.java @@ -21,9 +21,15 @@ package org.jclouds.snia.cdmi.v1.domain; import static com.google.common.base.Objects.equal; import static com.google.common.base.Preconditions.checkNotNull; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Set; +import org.jclouds.domain.JsonBall; + import com.google.common.base.Objects; import com.google.common.base.Objects.ToStringHelper; import com.google.common.collect.ImmutableMap; @@ -32,103 +38,196 @@ import com.google.common.collect.Maps; /** * - * @author Adrian Cole + * @author Kenneth Nagin */ public class Container extends CDMIObject { - public static Builder builder() { - return new ConcreteBuilder(); - } + public static Builder builder() { + return new ConcreteBuilder(); + } - @Override - public Builder toBuilder() { - return builder().fromContainer(this); - } + @Override + public Builder toBuilder() { + return builder().fromContainer(this); + } - public static class Builder> extends CDMIObject.Builder { + public static class Builder> extends + CDMIObject.Builder { - private Set children = ImmutableSet.of(); - private Map metadata = Maps.newHashMap(); + private Set children = ImmutableSet.of(); + private Map metadata = Maps.newHashMap(); - /** - * @see Container#getChildren() - */ - public B children(String... children) { - return children(ImmutableSet.copyOf(checkNotNull(children, "children"))); - } + /** + * @see Container#getChildren() + */ + public B children(String... children) { + return children(ImmutableSet.copyOf(checkNotNull(children, + "children"))); + } - /** - * @see Container#getChildren() - */ - public B children(Set children) { - this.children = ImmutableSet.copyOf(checkNotNull(children, "children")); - return self(); - } + /** + * @see Container#getChildren() + */ + public B children(Set children) { + this.children = ImmutableSet.copyOf(checkNotNull(children, + "children")); + return self(); + } - /** - * @see Container#getMetadata() - */ - public B metadata(Map metadata) { - this.metadata = ImmutableMap.copyOf(checkNotNull(metadata, "metadata")); - return self(); - } + /** + * @see Container#getMetadata() + */ + public B metadata(Map metadata) { + this.metadata = ImmutableMap.copyOf(checkNotNull(metadata, + "metadata")); + return self(); + } - @Override - public Container build() { - return new Container(this); - } + @Override + public Container build() { + return new Container(this); + } - public B fromContainer(Container in) { - return fromCDMIObject(in).children(in.getChildren()).metadata(in.getMetadata()); - } - } + public B fromContainer(Container in) { + return fromCDMIObject(in).children(in.getChildren()).metadata( + in.getMetadata()); + } + } - private static class ConcreteBuilder extends Builder { - } + private static class ConcreteBuilder extends Builder { + } - private final Set children; - private final Map metadata; + private final Set children; + private final Map metadata; - protected Container(Builder builder) { - super(builder); - this.children = ImmutableSet.copyOf(checkNotNull(builder.children, "children")); - this.metadata = ImmutableMap.copyOf(checkNotNull(builder.metadata, "metadata")); - } + private Map userMetaDataIn; + private Map systemMetaDataIn; + private List> aclMetaDataIn; - /** - * Names of the children objects in the container object. Child container objects end with "/". - */ - public Set getChildren() { - return children; - } + protected Container(Builder builder) { + super(builder); + this.children = ImmutableSet.copyOf(checkNotNull(builder.children, + "children")); + this.metadata = ImmutableMap.copyOf(checkNotNull(builder.metadata, + "metadata")); + } - /** - * Metadata for the container object. This field includes any user and data system metadata - * specified in the request body metadata field, along with storage system metadata generated by - * the cloud storage system. - */ - public Map getMetadata() { - return metadata; - } + /** + * Names of the children objects in the container object. Child container + * objects end with "/". + */ + public Set getChildren() { + return children; + } - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - Container that = Container.class.cast(o); - return super.equals(that) && equal(this.children, that.children) && equal(this.metadata, that.metadata); - } + /** + * Metadata for the container object. This field includes any user and + * system metadata specified in the request body metadata field, along with + * storage system metadata generated by the cloud storage system. + */ + public Map getMetadata() { + return metadata; + } - @Override - public int hashCode() { - return Objects.hashCode(super.hashCode(), children, metadata); - } + /** + * Parse Metadata for the container object from the original JsonBall. + * System metadata data is prefixed with cdmi. System ACL metadata data is + * prefixed with cdmi_acl + * + */ + private void parseMetadata() { + userMetaDataIn = new HashMap(); + systemMetaDataIn = new HashMap(); + aclMetaDataIn = new ArrayList>(); + Iterator keys = metadata.keySet().iterator(); + while (keys.hasNext()) { + String key = keys.next(); + JsonBall value = metadata.get(key); + if (key.startsWith("cdmi")) { + if (key.matches("cdmi_acl")) { + String[] cdmi_acl_array = value.toString().split("[{}]"); + for (int i = 0; i < cdmi_acl_array.length; i++) { + if (!(cdmi_acl_array[i].startsWith("[") + || cdmi_acl_array[i].startsWith("]") || cdmi_acl_array[i] + .startsWith(","))) { + HashMap aclMap = new HashMap(); + String[] cdmi_acl_member = cdmi_acl_array[i] + .split(","); + for (String s : cdmi_acl_member) { + String cdmi_acl_key = s.substring(0, + s.indexOf(":")); + String cdmi_acl_value = s.substring(s + .indexOf(":") + 1); + cdmi_acl_value.replace('"', ' ').trim(); + aclMap.put(cdmi_acl_key, cdmi_acl_value); + } + aclMetaDataIn.add(aclMap); + } + } + } else { + systemMetaDataIn.put(key, value.toString() + .replace('"', ' ').trim()); + } + } else { + userMetaDataIn.put(key, value.toString().replace('"', ' ') + .trim()); + } + } + } - @Override - public ToStringHelper string() { - return super.string().add("children", children).add("metadata", metadata); - } + /** + * Get User Metadata for the container object. This field includes any user + * metadata + */ + public Map getUserMetadata() { + if (userMetaDataIn == null) { + parseMetadata(); + } + return userMetaDataIn; + } + + /** + * Get System Metadata for the container object excluding ACL related + * metadata + */ + public Map getSystemMetadata() { + if (systemMetaDataIn == null) { + parseMetadata(); + } + return systemMetaDataIn; + } + + /** + * Get System Metadata for the container object excluding ACL related + * metadata + */ + public List> getACLMetadata() { + if (aclMetaDataIn == null) { + parseMetadata(); + } + return aclMetaDataIn; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Container that = Container.class.cast(o); + return super.equals(that) && equal(this.children, that.children) + && equal(this.metadata, that.metadata); + } + + @Override + public int hashCode() { + return Objects.hashCode(super.hashCode(), children, metadata); + } + + @Override + public ToStringHelper string() { + return super.string().add("children", children) + .add("metadata", metadata); + } } diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/ContainerAsyncClient.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/ContainerAsyncClient.java index 1bbf7257f8..f738dfc249 100644 --- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/ContainerAsyncClient.java +++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/ContainerAsyncClient.java @@ -19,9 +19,12 @@ package org.jclouds.snia.cdmi.v1.features; import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; import javax.ws.rs.GET; +import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import org.jclouds.rest.annotations.ExceptionParser; @@ -40,7 +43,7 @@ import com.google.common.util.concurrent.ListenableFuture; * Container Object Resource Operations * * @see ContainerClient - * @author Adrian Cole + * @author Kenneth Nagin * @see api doc */ @SkipEncoding( { '/', '=' }) @@ -56,5 +59,25 @@ public interface ContainerAsyncClient { @ExceptionParser(ReturnNullOnNotFoundOr404.class) @Path("/{containerName}/") ListenableFuture getContainer(@PathParam("containerName") String containerName); + + /** + * @see ContainerClient#createContainer + */ + @PUT + @Consumes( { ObjectTypes.CONTAINER, MediaType.APPLICATION_JSON }) + @Produces( { ObjectTypes.CONTAINER}) + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + @Path("/{containerName}/") + ListenableFuture createContainer(@PathParam("containerName") String containerName); + + /** + * @see ContainerClient#createContainer() + */ + @DELETE +// @Consumes( { ObjectTypes.CONTAINER, MediaType.APPLICATION_JSON }) + @Consumes( MediaType.APPLICATION_JSON ) + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + @Path("/{containerName}/") + ListenableFuture deleteContainer(@PathParam("containerName") String containerName); } diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/ContainerClient.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/ContainerClient.java index 76df5c73d8..2bd3b8e867 100644 --- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/ContainerClient.java +++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/ContainerClient.java @@ -27,12 +27,15 @@ import org.jclouds.snia.cdmi.v1.domain.Container; * Container Object Resource Operations * * @see ContainerAsyncClient - * @author Adrian Cole + * @author Kenneth Nagin * @see api doc */ @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS) public interface ContainerClient { + Container createContainer(String containerName); - Container getContainer(String containerName); + Container getContainer(String containerName); + + void deleteContainer(String containerName); } diff --git a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/ContainerClientLiveTest.java b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/ContainerClientLiveTest.java index 1ee33f40f8..012a527665 100644 --- a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/ContainerClientLiveTest.java +++ b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/ContainerClientLiveTest.java @@ -21,6 +21,10 @@ package org.jclouds.snia.cdmi.v1.features; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + import org.jclouds.snia.cdmi.v1.ObjectTypes; import org.jclouds.snia.cdmi.v1.domain.Container; import org.jclouds.snia.cdmi.v1.internal.BaseCDMIClientLiveTest; @@ -28,21 +32,49 @@ import org.testng.annotations.Test; /** * - * @author Adrian Cole + * @author Kenneth Nagin */ @Test(groups = "live", testName = "ContainerClientLiveTest") public class ContainerClientLiveTest extends BaseCDMIClientLiveTest { - @Test - public void testGetContainer() throws Exception { + public void testCreateContainer() throws Exception { + String pContainerName = "MyContainer" + System.currentTimeMillis(); ContainerClient client = cdmiContext.getApi().getContainerClient(); - Container container = client.getContainer("TODO: figure out how to list containers"); + Logger.getAnonymousLogger().info("createContainer: " + pContainerName); + Container container = client.createContainer(pContainerName); assertNotNull(container); + System.out.println(container); + Logger.getAnonymousLogger().info("getContainer: " + pContainerName); + container = client.getContainer(pContainerName); + assertNotNull(container); + System.out.println(container); assertEquals(container.getObjectType(), ObjectTypes.CONTAINER); assertNotNull(container.getObjectID()); assertNotNull(container.getObjectName()); + assertEquals(container.getObjectName(), pContainerName + "/"); assertNotNull(container.getChildren()); + assertEquals(container.getChildren().isEmpty(), true); + System.out.println("Children: " + container.getChildren()); assertNotNull(container.getMetadata()); + assertNotNull(container.getUserMetadata()); + System.out.println("UserMetaData: " + container.getUserMetadata()); + assertNotNull(container.getSystemMetadata()); + System.out.println("SystemMetaData: " + container.getSystemMetadata()); + assertNotNull(container.getACLMetadata()); + List> aclMetadataOut = container.getACLMetadata(); + System.out.println("ACLMetaData: "); + for (Map aclMap : aclMetadataOut) { + System.out.println(aclMap); + } + container = client.getContainer("/"); + System.out.println("root container: " + container); + assertEquals(container.getChildren().contains(pContainerName + "/"), true); + Logger.getAnonymousLogger().info("deleteContainer: " + pContainerName); + client.deleteContainer(pContainerName); + container = client.getContainer("/"); + System.out.println("root container: " + container); + assertEquals(container.getChildren().contains(pContainerName + "/"), false); + } } diff --git a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/parse/ParseContainerTest.java b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/parse/ParseContainerTest.java index 14fea2114b..2cd3ef478d 100644 --- a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/parse/ParseContainerTest.java +++ b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/parse/ParseContainerTest.java @@ -21,6 +21,7 @@ package org.jclouds.snia.cdmi.v1.parse; import javax.ws.rs.Consumes; import javax.ws.rs.core.MediaType; +import org.jclouds.domain.JsonBall; import org.jclouds.json.BaseItemParserTest; import org.jclouds.snia.cdmi.v1.domain.Container; import org.testng.annotations.Test; @@ -30,7 +31,7 @@ import com.google.common.collect.ImmutableSet; /** * - * @author Adrian Cole + * @author Kenneth Nagin */ @Test(groups = "unit", testName = "ParseContainerTest") public class ParseContainerTest extends BaseItemParserTest { @@ -47,8 +48,8 @@ public class ParseContainerTest extends BaseItemParserTest { .objectType("application/cdmi-container") .objectID("00007E7F00102E230ED82694DAA975D2") .objectName("MyContainer/") - .metadata(ImmutableMap.builder() - .put("cdmi_size", "83") + .metadata(ImmutableMap.builder() + .put("cdmi_size", new JsonBall("\"83\"")) .build()) .children(ImmutableSet.builder() .add("MyDataObject.txt")