createContainer, deleteContainer, updates to container to parse metadata and accompany testcases.

Added handling of null ObjectName.
This commit is contained in:
Kenneth Nagin 2012-05-20 14:56:01 +03:00 committed by Adrian Cole
parent 227dbf777a
commit 3d1a2dd7fa
6 changed files with 365 additions and 200 deletions

View File

@ -29,7 +29,7 @@ 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 {
@ -83,7 +83,8 @@ public class CDMIObject {
}
protected B fromCDMIObject(CDMIObject in) {
return objectID(in.getObjectID()).objectType(in.getObjectType()).objectName(in.getObjectName());
return objectID(in.getObjectID()).objectType(in.getObjectType())
.objectName(in.getObjectName());
}
}
@ -99,13 +100,18 @@ public class CDMIObject {
/**
* Object ID of the object <br/>
* 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.
* 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;
return (objectID == null) ? "" : objectID;
}
/**
@ -117,15 +123,15 @@ public class CDMIObject {
}
/**
* 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.
* 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;
return (objectName == null) ? "" : objectName;
}
@Override
@ -135,7 +141,8 @@ public class CDMIObject {
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)
return equal(this.objectID, that.objectID)
&& equal(this.objectName, that.objectName)
&& equal(this.objectType, that.objectType);
}
@ -159,7 +166,7 @@ public class CDMIObject {
}
protected ToStringHelper string() {
return Objects.toStringHelper("").add("objectID", objectID).add("objectName", objectName).add("objectType",
objectType);
return Objects.toStringHelper("").add("objectID", objectID)
.add("objectName", objectName).add("objectType", objectType);
}
}

View File

@ -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,7 +38,7 @@ import com.google.common.collect.Maps;
/**
*
* @author Adrian Cole
* @author Kenneth Nagin
*/
public class Container extends CDMIObject {
@ -45,31 +51,35 @@ public class Container extends CDMIObject {
return builder().fromContainer(this);
}
public static class Builder<B extends Builder<B>> extends CDMIObject.Builder<B> {
public static class Builder<B extends Builder<B>> extends
CDMIObject.Builder<B> {
private Set<String> children = ImmutableSet.of();
private Map<String, String> metadata = Maps.newHashMap();
private Map<String, JsonBall> metadata = Maps.newHashMap();
/**
* @see Container#getChildren()
*/
public B children(String... children) {
return children(ImmutableSet.copyOf(checkNotNull(children, "children")));
return children(ImmutableSet.copyOf(checkNotNull(children,
"children")));
}
/**
* @see Container#getChildren()
*/
public B children(Set<String> children) {
this.children = ImmutableSet.copyOf(checkNotNull(children, "children"));
this.children = ImmutableSet.copyOf(checkNotNull(children,
"children"));
return self();
}
/**
* @see Container#getMetadata()
*/
public B metadata(Map<String, String> metadata) {
this.metadata = ImmutableMap.copyOf(checkNotNull(metadata, "metadata"));
public B metadata(Map<String, JsonBall> metadata) {
this.metadata = ImmutableMap.copyOf(checkNotNull(metadata,
"metadata"));
return self();
}
@ -79,7 +89,8 @@ public class Container extends CDMIObject {
}
public B fromContainer(Container in) {
return fromCDMIObject(in).children(in.getChildren()).metadata(in.getMetadata());
return fromCDMIObject(in).children(in.getChildren()).metadata(
in.getMetadata());
}
}
@ -87,30 +98,116 @@ public class Container extends CDMIObject {
}
private final Set<String> children;
private final Map<String, String> metadata;
private final Map<String, JsonBall> metadata;
private Map<String, String> userMetaDataIn;
private Map<String, String> systemMetaDataIn;
private List<Map<String, String>> aclMetaDataIn;
protected Container(Builder<?> builder) {
super(builder);
this.children = ImmutableSet.copyOf(checkNotNull(builder.children, "children"));
this.metadata = ImmutableMap.copyOf(checkNotNull(builder.metadata, "metadata"));
this.children = ImmutableSet.copyOf(checkNotNull(builder.children,
"children"));
this.metadata = ImmutableMap.copyOf(checkNotNull(builder.metadata,
"metadata"));
}
/**
* Names of the children objects in the container object. Child container objects end with "/".
* Names of the children objects in the container object. Child container
* objects end with "/".
*/
public Set<String> getChildren() {
return children;
}
/**
* 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.
* 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<String, String> getMetadata() {
public Map<String, JsonBall> getMetadata() {
return 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<String, String>();
systemMetaDataIn = new HashMap<String, String>();
aclMetaDataIn = new ArrayList<Map<String, String>>();
Iterator<String> 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<String, String> aclMap = new HashMap<String, String>();
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());
}
}
}
/**
* Get User Metadata for the container object. This field includes any user
* metadata
*/
public Map<String, String> getUserMetadata() {
if (userMetaDataIn == null) {
parseMetadata();
}
return userMetaDataIn;
}
/**
* Get System Metadata for the container object excluding ACL related
* metadata
*/
public Map<String, String> getSystemMetadata() {
if (systemMetaDataIn == null) {
parseMetadata();
}
return systemMetaDataIn;
}
/**
* Get System Metadata for the container object excluding ACL related
* metadata
*/
public List<Map<String, String>> getACLMetadata() {
if (aclMetaDataIn == null) {
parseMetadata();
}
return aclMetaDataIn;
}
@Override
public boolean equals(Object o) {
if (this == o)
@ -118,7 +215,8 @@ public class Container extends CDMIObject {
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);
return super.equals(that) && equal(this.children, that.children)
&& equal(this.metadata, that.metadata);
}
@Override
@ -128,7 +226,8 @@ public class Container extends CDMIObject {
@Override
public ToStringHelper string() {
return super.string().add("children", children).add("metadata", metadata);
return super.string().add("children", children)
.add("metadata", metadata);
}
}

View File

@ -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 <a href="http://www.snia.org/cdmi">api doc</a>
*/
@SkipEncoding( { '/', '=' })
@ -57,4 +60,24 @@ public interface ContainerAsyncClient {
@Path("/{containerName}/")
ListenableFuture<Container> getContainer(@PathParam("containerName") String containerName);
/**
* @see ContainerClient#createContainer
*/
@PUT
@Consumes( { ObjectTypes.CONTAINER, MediaType.APPLICATION_JSON })
@Produces( { ObjectTypes.CONTAINER})
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Path("/{containerName}/")
ListenableFuture<Container> 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<Void> deleteContainer(@PathParam("containerName") String containerName);
}

View File

@ -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 <a href="http://www.snia.org/cdmi">api doc</a>
*/
@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
public interface ContainerClient {
Container createContainer(String containerName);
Container getContainer(String containerName);
void deleteContainer(String containerName);
}

View File

@ -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<Map<String, String>> aclMetadataOut = container.getACLMetadata();
System.out.println("ACLMetaData: ");
for (Map<String, String> 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);
}
}

View File

@ -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<Container> {
@ -47,8 +48,8 @@ public class ParseContainerTest extends BaseItemParserTest<Container> {
.objectType("application/cdmi-container")
.objectID("00007E7F00102E230ED82694DAA975D2")
.objectName("MyContainer/")
.metadata(ImmutableMap.<String, String>builder()
.put("cdmi_size", "83")
.metadata(ImmutableMap.<String, JsonBall>builder()
.put("cdmi_size", new JsonBall("\"83\""))
.build())
.children(ImmutableSet.<String>builder()
.add("MyDataObject.txt")