mirror of https://github.com/apache/jclouds.git
Issue 75: Added container deletion and listing options, and get account metadata
git-svn-id: http://jclouds.googlecode.com/svn/trunk@1625 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
parent
b7fbf48dbb
commit
02f858fd97
|
@ -27,14 +27,22 @@ import java.util.List;
|
|||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HEAD;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
|
||||
import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata;
|
||||
import org.jclouds.rackspace.cloudfiles.domain.ContainerMetadata;
|
||||
import org.jclouds.rackspace.cloudfiles.functions.ParseAccountMetadataResponseFromHeaders;
|
||||
import org.jclouds.rackspace.cloudfiles.functions.ParseContainerListFromGsonResponse;
|
||||
import org.jclouds.rackspace.cloudfiles.functions.ReturnTrueOn204FalseOtherwise;
|
||||
import org.jclouds.rackspace.cloudfiles.functions.ReturnTrueOn404FalseOtherwise;
|
||||
import org.jclouds.rackspace.cloudfiles.options.ListContainerOptions;
|
||||
import org.jclouds.rackspace.filters.AuthenticateRequest;
|
||||
import org.jclouds.rest.ExceptionParser;
|
||||
import org.jclouds.rest.Query;
|
||||
import org.jclouds.rest.RequestFilters;
|
||||
import org.jclouds.rest.ResponseParser;
|
||||
|
@ -53,14 +61,32 @@ import org.jclouds.rest.SkipEncoding;
|
|||
@RequestFilters(AuthenticateRequest.class)
|
||||
public interface CloudFilesConnection {
|
||||
|
||||
@HEAD
|
||||
@ResponseParser(ParseAccountMetadataResponseFromHeaders.class)
|
||||
@Path("/")
|
||||
AccountMetadata getAccountMetadata();
|
||||
|
||||
// TODO: Should this method automatically retrieve paged results, i.e. for > 10,000 containers?
|
||||
@GET
|
||||
@ResponseParser(ParseContainerListFromGsonResponse.class)
|
||||
@Query(key = "format", value = "json")
|
||||
@Path("/")
|
||||
List<ContainerMetadata> listOwnedContainers();
|
||||
|
||||
@GET
|
||||
@ResponseParser(ParseContainerListFromGsonResponse.class)
|
||||
@Query(key = "format", value = "json")
|
||||
@Path("/")
|
||||
List<ContainerMetadata> listOwnedContainers(ListContainerOptions options);
|
||||
|
||||
@PUT
|
||||
@Path("{container}")
|
||||
boolean putContainer(@PathParam("container") String container);
|
||||
|
||||
@DELETE
|
||||
@ResponseParser(ReturnTrueOn204FalseOtherwise.class)
|
||||
@ExceptionParser(ReturnTrueOn404FalseOtherwise.class)
|
||||
@Path("{container}")
|
||||
boolean deleteContainerIfEmpty(@PathParam("container") String container);
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.rackspace.cloudfiles.domain;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author James Murty
|
||||
*
|
||||
*/
|
||||
public class AccountMetadata {
|
||||
|
||||
public AccountMetadata(long containerCount, long bytes) {
|
||||
this.containerCount = containerCount;
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
public AccountMetadata() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("ContainerMetadata [bytes=").append(bytes)
|
||||
.append(", containerCount=").append(containerCount).append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (int) (bytes ^ (bytes >>> 32));
|
||||
result = prime * result + (int) (containerCount ^ (containerCount >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
AccountMetadata other = (AccountMetadata) obj;
|
||||
if (bytes != other.bytes)
|
||||
return false;
|
||||
if (containerCount != other.containerCount)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private long containerCount;
|
||||
private long bytes;
|
||||
|
||||
public void setContainerCount(long count) {
|
||||
this.containerCount = count;
|
||||
}
|
||||
|
||||
public long getContainerCount() {
|
||||
return containerCount;
|
||||
}
|
||||
|
||||
public void setBytes(long bytes) {
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
public long getBytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.rackspace.cloudfiles.functions;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata;
|
||||
import org.jclouds.rackspace.cloudfiles.reference.CloudFilesHeaders;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* This parses {@link AccountMetadata} from HTTP headers.
|
||||
*
|
||||
* @author James Murty
|
||||
*/
|
||||
public class ParseAccountMetadataResponseFromHeaders implements
|
||||
Function<HttpResponse, AccountMetadata> {
|
||||
|
||||
/**
|
||||
* parses the http response headers to create a new {@link AccountMetadata} object.
|
||||
*/
|
||||
public AccountMetadata apply(final HttpResponse from) {
|
||||
String bytesString = checkNotNull(
|
||||
from.getFirstHeaderOrNull(CloudFilesHeaders.ACCOUNT_BYTES_USED),
|
||||
CloudFilesHeaders.ACCOUNT_BYTES_USED);
|
||||
String containersCountString = checkNotNull(
|
||||
from.getFirstHeaderOrNull(CloudFilesHeaders.ACCOUNT_CONTAINER_COUNT),
|
||||
CloudFilesHeaders.ACCOUNT_CONTAINER_COUNT);
|
||||
return new AccountMetadata(
|
||||
Long.parseLong(containersCountString),
|
||||
Long.parseLong(bytesString));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.rackspace.cloudfiles.functions;
|
||||
|
||||
import org.jclouds.http.HttpResponse;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
public class ReturnTrueOn204FalseOtherwise implements Function<HttpResponse, Boolean> {
|
||||
|
||||
public Boolean apply(HttpResponse from) {
|
||||
return (from.getStatusCode() == 204);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.rackspace.cloudfiles.functions;
|
||||
|
||||
import org.jclouds.http.HttpResponseException;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
public class ReturnTrueOn404FalseOtherwise implements Function<Exception, Boolean> {
|
||||
|
||||
public Boolean apply(Exception from) {
|
||||
if (from instanceof HttpResponseException) {
|
||||
return (404 == ((HttpResponseException)from).getResponse().getStatusCode());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.rackspace.cloudfiles.options;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import org.jclouds.http.options.BaseHttpRequestOptions;
|
||||
|
||||
/**
|
||||
* Contains options supported in the REST API for the GET container operation. <h2>
|
||||
*/
|
||||
public class ListContainerOptions extends BaseHttpRequestOptions {
|
||||
public static final ListContainerOptions NONE = new ListContainerOptions();
|
||||
|
||||
/**
|
||||
* Indicates where to begin listing the account's containers. The list will only include
|
||||
* containers whose names occur lexicographically after the marker. This is convenient for
|
||||
* pagination: To get the next page of results use the last container name of the current
|
||||
* page as the marker.
|
||||
*/
|
||||
public ListContainerOptions afterMarker(String marker) {
|
||||
queryParameters.put("marker", checkNotNull(marker, "marker"));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The maximum number of containers that will be included in the response body.
|
||||
* The server might return fewer than this many containers, but will not return more.
|
||||
*/
|
||||
public ListContainerOptions maxResults(int limit) {
|
||||
checkState(limit >= 0, "limit must be >= 0");
|
||||
checkState(limit <= 10000, "limit must be <= 10000");
|
||||
queryParameters.put("limit", Integer.toString(limit));
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
/**
|
||||
* @see ListContainerOptions#afterMarker(String)
|
||||
*/
|
||||
public static ListContainerOptions afterMarker(String marker) {
|
||||
ListContainerOptions options = new ListContainerOptions();
|
||||
return options.afterMarker(marker);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ListContainerOptions#limit(int)
|
||||
*/
|
||||
public static ListContainerOptions maxResults(int limit) {
|
||||
ListContainerOptions options = new ListContainerOptions();
|
||||
return options.maxResults(limit);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -28,10 +28,14 @@ import static org.jclouds.rackspace.cloudfiles.reference.CloudFilesConstants.PRO
|
|||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata;
|
||||
import org.jclouds.rackspace.cloudfiles.domain.ContainerMetadata;
|
||||
import org.jclouds.rackspace.cloudfiles.options.ListContainerOptions;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
|
@ -53,17 +57,85 @@ public class CloudFilesConnectionLiveTest {
|
|||
sysRackspaceKey).withJsonDebug().buildContext().getConnection();
|
||||
List<ContainerMetadata> response = connection.listOwnedContainers();
|
||||
assertNotNull(response);
|
||||
long initialContainerCount = response.size();
|
||||
assertTrue(initialContainerCount >= 0);
|
||||
|
||||
String[] containerNames = new String[] {
|
||||
bucketPrefix + ".testListOwnedContainers1",bucketPrefix + ".testListOwnedContainers2"};
|
||||
assertTrue(connection.putContainer(containerNames[0]));
|
||||
assertTrue(connection.putContainer(containerNames[1]));
|
||||
response = connection.listOwnedContainers();
|
||||
assertEquals(response.size(), initialContainerCount + 2);
|
||||
|
||||
assertTrue(connection.deleteContainerIfEmpty(containerNames[0]));
|
||||
assertTrue(connection.deleteContainerIfEmpty(containerNames[1]));
|
||||
response = connection.listOwnedContainers();
|
||||
assertEquals(response.size(), initialContainerCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeadAccountMetadata() throws Exception {
|
||||
CloudFilesConnection connection = CloudFilesContextBuilder.newBuilder(sysRackspaceUser,
|
||||
sysRackspaceKey).withJsonDebug().buildContext().getConnection();
|
||||
AccountMetadata metadata = connection.getAccountMetadata();
|
||||
assertNotNull(metadata);
|
||||
long initialContainerCount = metadata.getContainerCount();
|
||||
|
||||
String containerName = bucketPrefix + ".testHeadAccountMetadata";
|
||||
assertTrue(connection.putContainer(containerName));
|
||||
|
||||
metadata = connection.getAccountMetadata();
|
||||
assertNotNull(metadata);
|
||||
assertEquals(metadata.getContainerCount(), initialContainerCount + 1);
|
||||
|
||||
assertTrue(connection.deleteContainerIfEmpty(containerName));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteContainer() throws Exception {
|
||||
CloudFilesConnection connection = CloudFilesContextBuilder.newBuilder(sysRackspaceUser,
|
||||
sysRackspaceKey).withJsonDebug().buildContext().getConnection();
|
||||
|
||||
assertTrue(connection.deleteContainerIfEmpty("does-not-exist"));
|
||||
|
||||
String containerName = bucketPrefix + ".testDeleteContainer";
|
||||
assertTrue(connection.putContainer(containerName));
|
||||
assertTrue(connection.deleteContainerIfEmpty(containerName));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPutContainers() throws Exception {
|
||||
CloudFilesConnection connection = CloudFilesContextBuilder.newBuilder(sysRackspaceUser,
|
||||
sysRackspaceKey).withJsonDebug().buildContext().getConnection();
|
||||
assertTrue(connection.putContainer(bucketPrefix + ".hello"));
|
||||
List<ContainerMetadata> response = connection.listOwnedContainers();
|
||||
String containerName1 = bucketPrefix + ".hello";
|
||||
assertTrue(connection.putContainer(containerName1));
|
||||
// List only the container just created, using a marker with the container name less 1 char
|
||||
List<ContainerMetadata> response = connection.listOwnedContainers(ListContainerOptions.Builder
|
||||
.afterMarker(containerName1.substring(0, containerName1.length() - 1))
|
||||
.maxResults(1));
|
||||
assertNotNull(response);
|
||||
assertEquals(response.size(), 1);
|
||||
assertEquals(response.get(0).getName(), bucketPrefix + ".hello");
|
||||
|
||||
// TODO: Contrary to the API documentation, a container can be created with '?' in the name.
|
||||
String containerName2 = bucketPrefix + "?should-be-illegal-question-char";
|
||||
connection.putContainer(containerName2);
|
||||
// List only the container just created, using a marker with the container name less 1 char
|
||||
response = connection.listOwnedContainers(ListContainerOptions.Builder
|
||||
.afterMarker(containerName2.substring(0, containerName2.length() - 1))
|
||||
.maxResults(1));
|
||||
assertEquals(response.size(), 1);
|
||||
|
||||
// TODO: Should throw a specific exception, not UndeclaredThrowableException
|
||||
try {
|
||||
connection.putContainer(bucketPrefix + "/illegal-slash-char");
|
||||
fail("Should not be able to create container with illegal '/' character");
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
assertTrue(connection.deleteContainerIfEmpty(containerName1));
|
||||
assertTrue(connection.deleteContainerIfEmpty(containerName2));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue