Issue 73: cloudfiles now in blobstore

git-svn-id: http://jclouds.googlecode.com/svn/trunk@2011 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2009-10-30 20:51:50 +00:00
parent 92b7a3ea89
commit 73cd1e3241
41 changed files with 1879 additions and 370 deletions

View File

@ -23,6 +23,7 @@
*/ */
package org.jclouds.rackspace.cloudfiles; package org.jclouds.rackspace.cloudfiles;
import java.net.URI;
import java.util.Map; import java.util.Map;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -58,11 +59,11 @@ import org.jclouds.rackspace.cloudfiles.functions.ObjectName;
import org.jclouds.rackspace.cloudfiles.functions.ParseAccountMetadataResponseFromHeaders; import org.jclouds.rackspace.cloudfiles.functions.ParseAccountMetadataResponseFromHeaders;
import org.jclouds.rackspace.cloudfiles.functions.ParseCdnUriFromHeaders; import org.jclouds.rackspace.cloudfiles.functions.ParseCdnUriFromHeaders;
import org.jclouds.rackspace.cloudfiles.functions.ParseContainerCDNMetadataFromHeaders; import org.jclouds.rackspace.cloudfiles.functions.ParseContainerCDNMetadataFromHeaders;
import org.jclouds.rackspace.cloudfiles.functions.ParseContainerCDNMetadataListFromGsonResponse; import org.jclouds.rackspace.cloudfiles.functions.ParseContainerCDNMetadataListFromJsonResponse;
import org.jclouds.rackspace.cloudfiles.functions.ParseContainerListFromJsonResponse; import org.jclouds.rackspace.cloudfiles.functions.ParseContainerListFromJsonResponse;
import org.jclouds.rackspace.cloudfiles.functions.ParseObjectFromHeadersAndHttpContent; import org.jclouds.rackspace.cloudfiles.functions.ParseObjectFromHeadersAndHttpContent;
import org.jclouds.rackspace.cloudfiles.functions.ParseObjectInfoFromHeaders;
import org.jclouds.rackspace.cloudfiles.functions.ParseObjectInfoListFromJsonResponse; import org.jclouds.rackspace.cloudfiles.functions.ParseObjectInfoListFromJsonResponse;
import org.jclouds.rackspace.cloudfiles.functions.ParseObjectMetadataFromHeaders;
import org.jclouds.rackspace.cloudfiles.functions.ReturnTrueOn404FalseOn409; import org.jclouds.rackspace.cloudfiles.functions.ReturnTrueOn404FalseOn409;
import org.jclouds.rackspace.cloudfiles.options.ListCdnContainerOptions; import org.jclouds.rackspace.cloudfiles.options.ListCdnContainerOptions;
import org.jclouds.rackspace.cloudfiles.options.ListContainerOptions; import org.jclouds.rackspace.cloudfiles.options.ListContainerOptions;
@ -140,16 +141,15 @@ public interface CloudFilesClient {
@ResponseParser(ParseContainerListFromJsonResponse.class) @ResponseParser(ParseContainerListFromJsonResponse.class)
@QueryParams(keys = "format", values = "json") @QueryParams(keys = "format", values = "json")
@Path("/") @Path("/")
SortedSet<ContainerMetadata> listContainers(ListContainerOptions... options); Future<? extends SortedSet<ContainerMetadata>> listContainers(ListContainerOptions... options);
@POST @POST
@Path("{container}/{name}") @Path("{container}/{name}")
boolean setObjectMetadata(@PathParam("container") String container, boolean setObjectInfo(@PathParam("container") String container, @PathParam("name") String name,
@PathParam("name") String name,
@BinderParam(BindMapToHeadersWithPrefix.class) Map<String, String> userMetadata); @BinderParam(BindMapToHeadersWithPrefix.class) Map<String, String> userMetadata);
@GET @GET
@ResponseParser(ParseContainerCDNMetadataListFromGsonResponse.class) @ResponseParser(ParseContainerCDNMetadataListFromJsonResponse.class)
@QueryParams(keys = "format", values = "json") @QueryParams(keys = "format", values = "json")
@Path("/") @Path("/")
@Endpoint(CloudFilesCDN.class) @Endpoint(CloudFilesCDN.class)
@ -168,20 +168,20 @@ public interface CloudFilesClient {
@Path("{container}") @Path("{container}")
@ResponseParser(ParseCdnUriFromHeaders.class) @ResponseParser(ParseCdnUriFromHeaders.class)
@Endpoint(CloudFilesCDN.class) @Endpoint(CloudFilesCDN.class)
String enableCDN(@PathParam("container") String container, URI enableCDN(@PathParam("container") String container,
@HeaderParam(CloudFilesHeaders.CDN_TTL) Long ttl); @HeaderParam(CloudFilesHeaders.CDN_TTL) Long ttl);
@PUT @PUT
@Path("{container}") @Path("{container}")
@ResponseParser(ParseCdnUriFromHeaders.class) @ResponseParser(ParseCdnUriFromHeaders.class)
@Endpoint(CloudFilesCDN.class) @Endpoint(CloudFilesCDN.class)
String enableCDN(@PathParam("container") String container); URI enableCDN(@PathParam("container") String container);
@POST @POST
@Path("{container}") @Path("{container}")
@ResponseParser(ParseCdnUriFromHeaders.class) @ResponseParser(ParseCdnUriFromHeaders.class)
@Endpoint(CloudFilesCDN.class) @Endpoint(CloudFilesCDN.class)
String updateCDN(@PathParam("container") String container, URI updateCDN(@PathParam("container") String container,
@HeaderParam(CloudFilesHeaders.CDN_TTL) Long ttl); @HeaderParam(CloudFilesHeaders.CDN_TTL) Long ttl);
@POST @POST
@ -222,18 +222,20 @@ public interface CloudFilesClient {
@ResponseParser(ParseObjectFromHeadersAndHttpContent.class) @ResponseParser(ParseObjectFromHeadersAndHttpContent.class)
@ExceptionParser(ThrowKeyNotFoundOn404.class) @ExceptionParser(ThrowKeyNotFoundOn404.class)
@Path("{container}/{name}") @Path("{container}/{name}")
Future<CFObject> getObject(@PathParam("container") String container, @PathParam("name") String name, Future<CFObject> getObject(@PathParam("container") String container,
GetOptions... options); @PathParam("name") String name, GetOptions... options);
@HEAD @HEAD
@ResponseParser(ParseObjectMetadataFromHeaders.class) @ResponseParser(ParseObjectInfoFromHeaders.class)
@ExceptionParser(ThrowKeyNotFoundOn404.class) @ExceptionParser(ThrowKeyNotFoundOn404.class)
@Path("{container}/{name}") @Path("{container}/{name}")
MutableObjectInfoWithMetadata getObjectInfo(@PathParam("container") String container, @PathParam("name") String name); MutableObjectInfoWithMetadata getObjectInfo(@PathParam("container") String container,
@PathParam("name") String name);
@DELETE @DELETE
@ExceptionParser(ReturnVoidOnNotFoundOr404.class) @ExceptionParser(ReturnVoidOnNotFoundOr404.class)
@Path("{container}/{name}") @Path("{container}/{name}")
Future<Void> removeObject(@PathParam("container") String container, @PathParam("name") String name); Future<Void> removeObject(@PathParam("container") String container,
@PathParam("name") String name);
} }

View File

@ -0,0 +1,181 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.blobstore.options.ListOptions.Builder.recursive;
import java.util.SortedSet;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import javax.inject.Inject;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.attr.ConsistencyModel;
import org.jclouds.blobstore.attr.ConsistencyModels;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.BoundedSortedSet;
import org.jclouds.blobstore.domain.ResourceMetadata;
import org.jclouds.blobstore.options.ListOptions;
import org.jclouds.blobstore.strategy.ClearListStrategy;
import org.jclouds.concurrent.FutureFunctionWrapper;
import org.jclouds.http.options.GetOptions;
import org.jclouds.logging.Logger.LoggerFactory;
import org.jclouds.rackspace.cloudfiles.CloudFilesClient;
import org.jclouds.rackspace.cloudfiles.blobstore.functions.BlobToObject;
import org.jclouds.rackspace.cloudfiles.blobstore.functions.BlobToObjectGetOptions;
import org.jclouds.rackspace.cloudfiles.blobstore.functions.ContainerToResourceList;
import org.jclouds.rackspace.cloudfiles.blobstore.functions.ContainerToResourceMetadata;
import org.jclouds.rackspace.cloudfiles.blobstore.functions.ListOptionsToListContainerOptions;
import org.jclouds.rackspace.cloudfiles.blobstore.functions.ObjectToBlob;
import org.jclouds.rackspace.cloudfiles.blobstore.functions.ObjectToBlobMetadata;
import org.jclouds.rackspace.cloudfiles.domain.CFObject;
import org.jclouds.rackspace.cloudfiles.domain.ContainerMetadata;
import org.jclouds.rackspace.cloudfiles.domain.ObjectInfo;
import org.jclouds.rackspace.cloudfiles.options.ListContainerOptions;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
@ConsistencyModel(ConsistencyModels.STRICT)
public class CloudFilesBlobStore implements BlobStore {
private final CloudFilesClient connection;
private final Blob.Factory blobFactory;
private final LoggerFactory logFactory;
private final ClearListStrategy clearContainerStrategy;
private final ObjectToBlobMetadata object2BlobMd;
private final ObjectToBlob object2Blob;
private final BlobToObject blob2Object;
private final ListOptionsToListContainerOptions container2ContainerListOptions;
private final BlobToObjectGetOptions blob2ObjectGetOptions;
private final ContainerToResourceMetadata container2ResourceMd;
private final ContainerToResourceList container2ResourceList;
private final ExecutorService service;
@Inject
private CloudFilesBlobStore(CloudFilesClient connection, Blob.Factory blobFactory, LoggerFactory logFactory,
ClearListStrategy clearContainerStrategy, ObjectToBlobMetadata object2BlobMd,
ObjectToBlob object2Blob, BlobToObject blob2Object,
ListOptionsToListContainerOptions container2ContainerListOptions,
BlobToObjectGetOptions blob2ObjectGetOptions,
ContainerToResourceMetadata container2ResourceMd, ContainerToResourceList container2ResourceList,
ExecutorService service) {
this.connection = checkNotNull(connection, "connection");
this.blobFactory = checkNotNull(blobFactory, "blobFactory");
this.logFactory = checkNotNull(logFactory, "logFactory");
this.clearContainerStrategy = checkNotNull(clearContainerStrategy, "clearContainerStrategy");
this.object2BlobMd = checkNotNull(object2BlobMd, "object2BlobMd");
this.object2Blob = checkNotNull(object2Blob, "object2Blob");
this.blob2Object = checkNotNull(blob2Object, "blob2Object");
this.container2ContainerListOptions = checkNotNull(container2ContainerListOptions,
"container2ContainerListOptions");
this.blob2ObjectGetOptions = checkNotNull(blob2ObjectGetOptions, "blob2ObjectGetOptions");
this.container2ResourceMd = checkNotNull(container2ResourceMd, "container2ResourceMd");
this.container2ResourceList = checkNotNull(container2ResourceList, "container2ResourceList");
this.service = checkNotNull(service, "service");
}
protected <F, T> Future<T> wrapFuture(Future<? extends F> future, Function<F, T> function) {
return new FutureFunctionWrapper<F, T>(future, function, logFactory.getLogger(function
.getClass().getName()));
}
/**
* This implementation uses the CloudFiles HEAD Object command to return the result
*/
public BlobMetadata blobMetadata(String container, String key) {
return object2BlobMd.apply(connection.getObjectInfo(container, key));
}
public Future<Void> clearContainer(final String container) {
return service.submit(new Callable<Void>() {
public Void call() throws Exception {
clearContainerStrategy.execute(container, recursive());
return null;
}
});
}
public Future<Boolean> createContainer(String container) {
return connection.createContainer(container);
}
public Future<Void> deleteContainer(final String container) {
return service.submit(new Callable<Void>() {
public Void call() throws Exception {
clearContainerStrategy.execute(container, recursive());
connection.deleteContainerIfEmpty(container).get();
return null;
}
});
}
public boolean exists(String container) {
return connection.containerExists(container);
}
public Future<Blob> getBlob(String container, String key,
org.jclouds.blobstore.options.GetOptions... optionsList) {
GetOptions httpOptions = blob2ObjectGetOptions.apply(optionsList);
Future<CFObject> returnVal = connection.getObject(container, key, httpOptions);
return wrapFuture(returnVal, object2Blob);
}
public Future<? extends SortedSet<? extends ResourceMetadata>> list() {
return wrapFuture(connection.listContainers(),
new Function<SortedSet<ContainerMetadata>, SortedSet<? extends ResourceMetadata>>() {
public SortedSet<? extends ResourceMetadata> apply(SortedSet<ContainerMetadata> from) {
return Sets.newTreeSet(Iterables.transform(from, container2ResourceMd));
}
});
}
public Future<? extends BoundedSortedSet<? extends ResourceMetadata>> list(String container,
ListOptions... optionsList) {
ListContainerOptions httpOptions = container2ContainerListOptions.apply(optionsList);
Future<BoundedSortedSet<ObjectInfo>> returnVal = connection.listObjects(container, httpOptions);
return wrapFuture(returnVal, container2ResourceList);
}
public Future<String> putBlob(String container, Blob blob) {
return connection.putObject(container, blob2Object.apply(blob));
}
public Future<Void> removeBlob(String container, String key) {
return connection.removeObject(container, key);
}
public Blob newBlob() {
return blobFactory.create(null);
}
}

View File

@ -0,0 +1,82 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import org.jclouds.blobstore.BlobStoreContextBuilder;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import org.jclouds.rackspace.cloudfiles.CloudFilesClient;
import org.jclouds.rackspace.cloudfiles.blobstore.config.CloudFilesBlobStoreContextModule;
import org.jclouds.rackspace.cloudfiles.config.CloudFilesRestClientModule;
import org.jclouds.rackspace.config.RackspaceAuthenticationRestModule;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/**
* Creates {@link CloudFilesBlobStoreContext} or {@link Injector} instances based on the most commonly
* requested arguments.
* <p/>
* Note that Threadsafe objects will be bound as singletons to the Injector or Context provided.
* <p/>
* <p/>
* If no <code>Module</code>s are specified, the default {@link JDKLoggingModule logging} and
* {@link JavaUrlHttpCommandExecutorServiceModule http transports} will be installed.
*
* @author Adrian Cole, Andrew Newdigate
* @see CloudFilesBlobStoreContext
*/
public class CloudFilesBlobStoreContextBuilder extends BlobStoreContextBuilder<CloudFilesClient> {
public CloudFilesBlobStoreContextBuilder(Properties props) {
super(new TypeLiteral<CloudFilesClient>() {
}, props);
}
@Override
public CloudFilesBlobStoreContextBuilder withExecutorService(ExecutorService service) {
return (CloudFilesBlobStoreContextBuilder) super.withExecutorService(service);
}
@Override
public CloudFilesBlobStoreContextBuilder withModules(Module... modules) {
return (CloudFilesBlobStoreContextBuilder) super.withModules(modules);
}
@Override
protected void addContextModule(List<Module> modules) {
modules.add(new CloudFilesBlobStoreContextModule());
}
@Override
protected void addClientModule(List<Module> modules) {
modules.add(new RackspaceAuthenticationRestModule());
modules.add(new CloudFilesRestClientModule());
}
}

View File

@ -0,0 +1,68 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore;
import java.net.URI;
import java.util.Properties;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import org.jclouds.rackspace.cloudfiles.CloudFilesClient;
import com.google.inject.Module;
/**
* Creates {@link CloudFilesBlobStoreContext} instances based on the most commonly requested
* arguments.
* <p/>
* Note that Threadsafe objects will be bound as singletons to the Injector or Context provided.
* <p/>
* <p/>
* If no <code>Module</code>s are specified, the default {@link JDKLoggingModule logging} and
* {@link JavaUrlHttpCommandExecutorServiceModule http transports} will be installed.
*
* @author Adrian Cole, Andrew Newdigate
* @see CloudFilesBlobStoreContext
*/
public class CloudFilesBlobStoreContextFactory {
public static BlobStoreContext<CloudFilesClient> createContext(Properties properties,
Module... modules) {
return new CloudFilesBlobStoreContextBuilder(new CloudFilesBlobStorePropertiesBuilder(
properties).build()).withModules(modules).buildContext();
}
public static BlobStoreContext<CloudFilesClient> createContext(String user,
String key, Module... modules) {
return new CloudFilesBlobStoreContextBuilder(new CloudFilesBlobStorePropertiesBuilder(
user, key).build()).withModules(modules).buildContext();
}
public static BlobStoreContext<CloudFilesClient> createContext(URI endpoint,
String user, String key, Module... modules) {
return new CloudFilesBlobStoreContextBuilder(new CloudFilesBlobStorePropertiesBuilder(
user, key).withEndpoint(endpoint).build()).withModules(
modules).buildContext();
}
}

View File

@ -0,0 +1,55 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore;
import java.util.Properties;
import org.jclouds.blobstore.reference.BlobStoreConstants;
import org.jclouds.rackspace.cloudfiles.CloudFilesPropertiesBuilder;
/**
* Builds properties used in CloudFiles Blob Stores
*
* @author Adrian Cole, Andrew Newdigate
*/
public class CloudFilesBlobStorePropertiesBuilder extends CloudFilesPropertiesBuilder {
public CloudFilesBlobStorePropertiesBuilder(String id, String secret) {
super(id, secret);
}
public CloudFilesBlobStorePropertiesBuilder(Properties properties) {
super(properties);
}
/**
* longest time a single synchronous operation can take before throwing an exception.
*/
public CloudFilesBlobStorePropertiesBuilder withRequestTimeout(long milliseconds) {
properties.setProperty(BlobStoreConstants.PROPERTY_BLOBSTORE_TIMEOUT, Long
.toString(milliseconds));
return this;
}
}

View File

@ -0,0 +1,73 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore.config;
import java.net.URI;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.blobstore.BlobMap;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.InputStreamMap;
import org.jclouds.blobstore.config.BlobStoreMapModule;
import org.jclouds.blobstore.config.BlobStoreObjectModule;
import org.jclouds.blobstore.internal.BlobStoreContextImpl;
import org.jclouds.lifecycle.Closer;
import org.jclouds.rackspace.CloudFiles;
import org.jclouds.rackspace.cloudfiles.CloudFilesClient;
import org.jclouds.rackspace.cloudfiles.blobstore.CloudFilesBlobStore;
import org.jclouds.rackspace.cloudfiles.config.CFObjectModule;
import org.jclouds.rackspace.reference.RackspaceConstants;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
/**
* Configures the {@link CloudFilesBlobStoreContext}; requires {@link CloudFilesBlobStore} bound.
*
* @author Adrian Cole
*/
public class CloudFilesBlobStoreContextModule extends AbstractModule {
@Override
protected void configure() {
install(new BlobStoreObjectModule());
install(new BlobStoreMapModule());
install(new CFObjectModule());
bind(BlobStore.class).to(CloudFilesBlobStore.class).asEagerSingleton();
}
@Provides
@Singleton
BlobStoreContext<CloudFilesClient> provideContext(BlobMap.Factory blobMapFactory,
InputStreamMap.Factory inputStreamMapFactory, Closer closer, BlobStore blobStore,
CloudFilesClient defaultApi, @CloudFiles URI endPoint,
@Named(RackspaceConstants.PROPERTY_RACKSPACE_USER) String account) {
return new BlobStoreContextImpl<CloudFilesClient>(blobMapFactory, inputStreamMapFactory,
closer, blobStore, defaultApi, endPoint, account);
}
}

View File

@ -13,11 +13,11 @@ import com.google.common.base.Function;
*/ */
@Singleton @Singleton
public class BlobToObject implements Function<Blob, CFObject> { public class BlobToObject implements Function<Blob, CFObject> {
private final BlobToObjectInfo blob2ObjectMd; private final ResourceToObjectInfo blob2ObjectMd;
private final CFObject.Factory objectProvider; private final CFObject.Factory objectProvider;
@Inject @Inject
BlobToObject(BlobToObjectInfo blob2ObjectMd, CFObject.Factory objectProvider) { BlobToObject(ResourceToObjectInfo blob2ObjectMd, CFObject.Factory objectProvider) {
this.blob2ObjectMd = blob2ObjectMd; this.blob2ObjectMd = blob2ObjectMd;
this.objectProvider = objectProvider; this.objectProvider = objectProvider;
} }

View File

@ -0,0 +1,60 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore.functions;
import javax.inject.Singleton;
import org.jclouds.http.options.GetOptions;
import com.google.common.base.Function;
/**
* @author Adrian Cole
*/
@Singleton
public class BlobToObjectGetOptions implements
Function<org.jclouds.blobstore.options.GetOptions[], GetOptions> {
public GetOptions apply(org.jclouds.blobstore.options.GetOptions[] from) {
GetOptions httpOptions = new GetOptions();
if (from.length != 0) {
if (from[0].getIfMatch() != null) {
httpOptions.ifETagMatches(from[0].getIfMatch());
}
if (from[0].getIfModifiedSince() != null) {
httpOptions.ifModifiedSince(from[0].getIfModifiedSince());
}
if (from[0].getIfNoneMatch() != null) {
httpOptions.ifETagDoesntMatch(from[0].getIfNoneMatch());
}
if (from[0].getIfUnmodifiedSince() != null) {
httpOptions.ifUnmodifiedSince(from[0].getIfUnmodifiedSince());
}
for (String range : from[0].getRanges()) {
String[] firstLast = range.split("\\-");
httpOptions.range(Long.parseLong(firstLast[0]), Long.parseLong(firstLast[1]));
}
}
return httpOptions;
}
}

View File

@ -0,0 +1,60 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore.functions;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.BoundedSortedSet;
import org.jclouds.blobstore.domain.ResourceMetadata;
import org.jclouds.blobstore.domain.internal.BoundedTreeSet;
import org.jclouds.rackspace.cloudfiles.domain.ObjectInfo;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
/**
* @author Adrian Cole
*/
@Singleton
public class ContainerToResourceList implements
Function<BoundedSortedSet<ObjectInfo>, BoundedSortedSet<? extends ResourceMetadata>> {
private final ObjectToBlobMetadata object2blobMd;
@Inject
public ContainerToResourceList(ObjectToBlobMetadata object2blobMd) {
this.object2blobMd = object2blobMd;
}
public BoundedSortedSet<? extends ResourceMetadata> apply(BoundedSortedSet<ObjectInfo> from) {
return new BoundedTreeSet<ResourceMetadata>(Iterables.transform(Iterables.transform(from,
object2blobMd), new Function<BlobMetadata, ResourceMetadata>() {
public ResourceMetadata apply(BlobMetadata arg0) {
return arg0;
}
}), from.getPath(), from.getMarker(), from.getMaxResults(), from.isTruncated());
}
}

View File

@ -0,0 +1,47 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore.functions;
import javax.inject.Singleton;
import org.jclouds.blobstore.domain.MutableResourceMetadata;
import org.jclouds.blobstore.domain.ResourceMetadata;
import org.jclouds.blobstore.domain.ResourceType;
import org.jclouds.blobstore.domain.internal.MutableResourceMetadataImpl;
import org.jclouds.rackspace.cloudfiles.domain.ContainerMetadata;
import com.google.common.base.Function;
/**
* @author Adrian Cole
*/
@Singleton
public class ContainerToResourceMetadata implements Function<ContainerMetadata, ResourceMetadata> {
public ResourceMetadata apply(ContainerMetadata from) {
MutableResourceMetadata to = new MutableResourceMetadataImpl();
to.setName(from.getName());
to.setType(ResourceType.CONTAINER);
return to;
}
}

View File

@ -0,0 +1,57 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore.functions;
import javax.inject.Singleton;
import org.jclouds.blobstore.options.ListOptions;
import org.jclouds.rackspace.cloudfiles.options.ListContainerOptions;
import com.google.common.base.Function;
/**
* @author Adrian Cole
*/
@Singleton
public class ListContainerOptionsToListOptions implements
Function<ListContainerOptions[], ListOptions> {
public ListOptions apply(ListContainerOptions[] optionsList) {
ListOptions options = new ListOptions();
if (optionsList.length != 0) {
if (optionsList[0].getPath() != null) {
options.underPath(optionsList[0].getPath());
}
if (optionsList[0].getPrefix() != null) {
options.underPath(optionsList[0].getPrefix());
options.recursive();
}
if (optionsList[0].getMarker() != null) {
options.afterMarker(optionsList[0].getMarker());
}
options.maxResults(optionsList[0].getMaxResults());
}
return options;
}
}

View File

@ -0,0 +1,65 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore.functions;
import javax.inject.Singleton;
import org.jclouds.blobstore.options.ListOptions;
import org.jclouds.rackspace.cloudfiles.options.ListContainerOptions;
import com.google.common.base.Function;
/**
* @author Adrian Cole
*/
@Singleton
public class ListOptionsToListContainerOptions implements
Function<ListOptions[], ListContainerOptions> {
public ListContainerOptions apply(ListOptions[] optionsList) {
ListContainerOptions options = new ListContainerOptions();
if (optionsList.length != 0) {
if ((optionsList[0].getPath() == null) && (optionsList[0].isRecursive())) {
options.withPrefix("");
}
if ((optionsList[0].getPath() == null) && (!optionsList[0].isRecursive())) {
options.underPath("");
}
if ((optionsList[0].getPath() != null) && (optionsList[0].isRecursive())) {
options.withPrefix(optionsList[0].getPath());
}
if ((optionsList[0].getPath() != null) && (!optionsList[0].isRecursive())) {
options.underPath(optionsList[0].getPath());
}
if (optionsList[0].getMarker() != null) {
options.afterMarker(optionsList[0].getMarker());
}
if (optionsList[0].getMaxResults() != null) {
options.maxResults(optionsList[0].getMaxResults());
}
}
return options;
}
}

View File

@ -7,6 +7,7 @@ import org.jclouds.blobstore.domain.ResourceType;
import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl; import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl;
import org.jclouds.http.HttpUtils; import org.jclouds.http.HttpUtils;
import org.jclouds.rackspace.cloudfiles.domain.MutableObjectInfoWithMetadata; import org.jclouds.rackspace.cloudfiles.domain.MutableObjectInfoWithMetadata;
import org.jclouds.rackspace.cloudfiles.domain.ObjectInfo;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -14,9 +15,8 @@ import com.google.common.base.Function;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class ObjectToBlobMetadata implements public class ObjectToBlobMetadata implements Function<ObjectInfo, MutableBlobMetadata> {
Function<MutableObjectInfoWithMetadata, MutableBlobMetadata> { public MutableBlobMetadata apply(ObjectInfo from) {
public MutableBlobMetadata apply(MutableObjectInfoWithMetadata from) {
MutableBlobMetadata to = new MutableBlobMetadataImpl(); MutableBlobMetadata to = new MutableBlobMetadataImpl();
to.setContentMD5(from.getHash()); to.setContentMD5(from.getHash());
if (from.getContentType() != null) if (from.getContentType() != null)
@ -27,7 +27,8 @@ public class ObjectToBlobMetadata implements
if (from.getBytes() != null) if (from.getBytes() != null)
to.setSize(from.getBytes()); to.setSize(from.getBytes());
to.setType(ResourceType.BLOB); to.setType(ResourceType.BLOB);
to.setUserMetadata(from.getMetadata()); if (from instanceof MutableObjectInfoWithMetadata)
to.setUserMetadata(((MutableObjectInfoWithMetadata)from).getMetadata());
if (from.getContentType() != null && from.getContentType().equals("application/directory")) { if (from.getContentType() != null && from.getContentType().equals("application/directory")) {
to.setType(ResourceType.RELATIVE_PATH); to.setType(ResourceType.RELATIVE_PATH);
} }

View File

@ -3,6 +3,9 @@ package org.jclouds.rackspace.cloudfiles.blobstore.functions;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.blobstore.domain.BlobMetadata; import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.ResourceMetadata;
import org.jclouds.blobstore.domain.ResourceType;
import org.jclouds.http.HttpUtils;
import org.jclouds.rackspace.cloudfiles.domain.MutableObjectInfoWithMetadata; import org.jclouds.rackspace.cloudfiles.domain.MutableObjectInfoWithMetadata;
import org.jclouds.rackspace.cloudfiles.domain.internal.MutableObjectInfoWithMetadataImpl; import org.jclouds.rackspace.cloudfiles.domain.internal.MutableObjectInfoWithMetadataImpl;
@ -12,11 +15,17 @@ import com.google.common.base.Function;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class BlobToObjectInfo implements Function<BlobMetadata, MutableObjectInfoWithMetadata> { public class ResourceToObjectInfo implements Function<ResourceMetadata, MutableObjectInfoWithMetadata> {
public MutableObjectInfoWithMetadata apply(BlobMetadata base) { public MutableObjectInfoWithMetadata apply(ResourceMetadata base) {
MutableObjectInfoWithMetadata to = new MutableObjectInfoWithMetadataImpl(); MutableObjectInfoWithMetadata to = new MutableObjectInfoWithMetadataImpl();
to.setContentType(base.getContentType()); if (base.getType() == ResourceType.BLOB){
to.setHash(base.getContentMD5()); to.setContentType(((BlobMetadata)base).getContentType());
to.setHash(((BlobMetadata)base).getContentMD5());
} else if (base.getType() == ResourceType.RELATIVE_PATH){
to.setContentType("application/directory");
}
if (base.getETag() != null && to.getHash() == null)
to.setHash(HttpUtils.fromHexString(base.getETag()));
to.setName(base.getName()); to.setName(base.getName());
to.setLastModified(base.getLastModified()); to.setLastModified(base.getLastModified());
if (base.getSize() != null) if (base.getSize() != null)

View File

@ -0,0 +1,62 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore.functions;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.blobstore.domain.BoundedSortedSet;
import org.jclouds.blobstore.domain.ResourceMetadata;
import org.jclouds.blobstore.domain.internal.BoundedTreeSet;
import org.jclouds.rackspace.cloudfiles.domain.ObjectInfo;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
/**
* @author Adrian Cole
*/
@Singleton
public class ResourceToObjectList implements
Function<BoundedSortedSet<? extends ResourceMetadata>, BoundedSortedSet<ObjectInfo>> {
private final ResourceToObjectInfo resource2ObjectMd;
@Inject
public ResourceToObjectList(ResourceToObjectInfo resource2ObjectMd) {
this.resource2ObjectMd = resource2ObjectMd;
}
public BoundedSortedSet<ObjectInfo> apply(BoundedSortedSet<? extends ResourceMetadata> list) {
return new BoundedTreeSet<ObjectInfo>(Iterables.transform(list,
new Function<ResourceMetadata, ObjectInfo>() {
public ObjectInfo apply(ResourceMetadata from) {
return resource2ObjectMd.apply(from);
}
}), list.getPath(), list.getMarker(), list.getMaxResults(), list.size() == list
.getMaxResults());
}
}

View File

@ -23,23 +23,28 @@
*/ */
package org.jclouds.rackspace.cloudfiles.domain; package org.jclouds.rackspace.cloudfiles.domain;
import org.jclouds.blobstore.domain.internal.MutableResourceMetadataImpl; import java.net.URI;
/** /**
* *
* @author James Murty * @author James Murty
* *
*/ */
public class ContainerCDNMetadata extends MutableResourceMetadataImpl { public class ContainerCDNMetadata implements Comparable<ContainerCDNMetadata> {
/** The serialVersionUID */ /** The serialVersionUID */
private static final long serialVersionUID = 8373435988423605652L; private static final long serialVersionUID = 8373435988423605652L;
private long ttl; private String name;
private boolean cdn_enabled; private boolean cdn_enabled;
private String cdn_uri; private long ttl;
private URI cdn_uri;
private String referrer_acl;
private String useragent_acl;
private boolean log_retention;
public ContainerCDNMetadata(boolean cdnEnabled, long ttl, String cdnUri) { public ContainerCDNMetadata(String name, boolean cdnEnabled, long ttl, URI cdnUri) {
super(); this.name = name;
this.cdn_enabled = cdnEnabled; this.cdn_enabled = cdnEnabled;
this.ttl = ttl; this.ttl = ttl;
this.cdn_uri = cdnUri; this.cdn_uri = cdnUri;
@ -52,41 +57,36 @@ public class ContainerCDNMetadata extends MutableResourceMetadataImpl {
* Beware: The container name is not available from HEAD CDN responses and will be null. return * Beware: The container name is not available from HEAD CDN responses and will be null. return
* the name of the container to which these CDN settings apply. * the name of the container to which these CDN settings apply.
*/ */
@Override
public String getName() { public String getName() {
return super.getName(); return name;
} }
public void setCdnUri(String cdnUri) { public URI getCDNUri() {
this.cdn_uri = cdnUri;
}
public String getCdnUri() {
return cdn_uri; return cdn_uri;
} }
public void setTtl(long ttl) { public long getTTL() {
this.ttl = ttl;
}
public long getTtl() {
return ttl; return ttl;
} }
public void setCdnEnabled(boolean cdnEnabled) { public boolean isCDNEnabled() {
this.cdn_enabled = cdnEnabled; return cdn_enabled;
} }
public boolean isCdnEnabled() { public int compareTo(ContainerCDNMetadata o) {
return cdn_enabled; if (getName() == null)
return -1;
return (this == o) ? 0 : getName().compareTo(o.getName());
} }
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = super.hashCode(); int result = 1;
result = prime * result + (cdn_enabled ? 1231 : 1237); result = prime * result + (cdn_enabled ? 1231 : 1237);
result = prime * result + ((cdn_uri == null) ? 0 : cdn_uri.hashCode()); result = prime * result + ((cdn_uri == null) ? 0 : cdn_uri.hashCode());
result = prime * result + (log_retention ? 1231 : 1237);
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + (int) (ttl ^ (ttl >>> 32)); result = prime * result + (int) (ttl ^ (ttl >>> 32));
return result; return result;
} }
@ -95,7 +95,7 @@ public class ContainerCDNMetadata extends MutableResourceMetadataImpl {
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj)
return true; return true;
if (!super.equals(obj)) if (obj == null)
return false; return false;
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
@ -107,9 +107,25 @@ public class ContainerCDNMetadata extends MutableResourceMetadataImpl {
return false; return false;
} else if (!cdn_uri.equals(other.cdn_uri)) } else if (!cdn_uri.equals(other.cdn_uri))
return false; return false;
if (ttl != other.ttl) if (log_retention != other.log_retention)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false; return false;
return true; return true;
} }
public String getReferrerACL() {
return referrer_acl;
}
public String getUseragentACL() {
return useragent_acl;
}
public boolean isLogRetention() {
return log_retention;
}
} }

View File

@ -25,6 +25,8 @@ package org.jclouds.rackspace.cloudfiles.functions;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata; import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata;
import org.jclouds.rackspace.cloudfiles.reference.CloudFilesHeaders; import org.jclouds.rackspace.cloudfiles.reference.CloudFilesHeaders;
@ -36,16 +38,14 @@ import com.google.common.base.Function;
* *
* @author James Murty * @author James Murty
*/ */
public class ParseCdnUriFromHeaders implements public class ParseCdnUriFromHeaders implements Function<HttpResponse, URI> {
Function<HttpResponse, String> {
/** /**
* parses the http response headers to provide the CDN URI string. * parses the http response headers to provide the CDN URI string.
*/ */
public String apply(final HttpResponse from) { public URI apply(final HttpResponse from) {
String cdnUri = checkNotNull( String cdnUri = checkNotNull(from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_URI),
from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_URI),
CloudFilesHeaders.CDN_URI); CloudFilesHeaders.CDN_URI);
return cdnUri; return URI.create(cdnUri);
} }
} }

View File

@ -25,10 +25,14 @@ package org.jclouds.rackspace.cloudfiles.functions;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata; import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata;
import org.jclouds.rackspace.cloudfiles.domain.ContainerCDNMetadata; import org.jclouds.rackspace.cloudfiles.domain.ContainerCDNMetadata;
import org.jclouds.rackspace.cloudfiles.reference.CloudFilesHeaders; import org.jclouds.rackspace.cloudfiles.reference.CloudFilesHeaders;
import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -38,14 +42,14 @@ import com.google.common.base.Function;
* @author James Murty * @author James Murty
*/ */
public class ParseContainerCDNMetadataFromHeaders implements public class ParseContainerCDNMetadataFromHeaders implements
Function<HttpResponse, ContainerCDNMetadata> { Function<HttpResponse, ContainerCDNMetadata>, InvocationContext {
private GeneratedHttpRequest<?> request;
/** /**
* parses the http response headers to create a new {@link ContainerCDNMetadata} object. * parses the http response headers to create a new {@link ContainerCDNMetadata} object.
*/ */
public ContainerCDNMetadata apply(final HttpResponse from) { public ContainerCDNMetadata apply(final HttpResponse from) {
// TODO: The container name is not returned as a header, hopefully one day it will be
String cdnUri = checkNotNull(from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_URI), String cdnUri = checkNotNull(from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_URI),
CloudFilesHeaders.CDN_URI); CloudFilesHeaders.CDN_URI);
String cdnTTL = checkNotNull(from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_TTL), String cdnTTL = checkNotNull(from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_TTL),
@ -56,8 +60,12 @@ public class ParseContainerCDNMetadataFromHeaders implements
// CDN is not, and has never, been enabled for this container. // CDN is not, and has never, been enabled for this container.
return null; return null;
} else { } else {
return new ContainerCDNMetadata(Boolean.parseBoolean(cdnEnabled), Long.parseLong(cdnTTL), return new ContainerCDNMetadata(request.getEndpoint().getPath(), Boolean
cdnUri); .parseBoolean(cdnEnabled), Long.parseLong(cdnTTL), URI.create(cdnUri));
} }
} }
public void setContext(GeneratedHttpRequest<?> request) {
this.request = request;
}
} }

View File

@ -23,6 +23,7 @@
*/ */
package org.jclouds.rackspace.cloudfiles.functions; package org.jclouds.rackspace.cloudfiles.functions;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
@ -31,6 +32,7 @@ import java.util.SortedSet;
import javax.inject.Inject; import javax.inject.Inject;
import org.apache.commons.io.IOUtils;
import org.jclouds.http.functions.ParseJson; import org.jclouds.http.functions.ParseJson;
import org.jclouds.rackspace.cloudfiles.domain.ContainerCDNMetadata; import org.jclouds.rackspace.cloudfiles.domain.ContainerCDNMetadata;
@ -42,15 +44,23 @@ import com.google.gson.reflect.TypeToken;
* *
* @author James Murty * @author James Murty
*/ */
public class ParseContainerCDNMetadataListFromGsonResponse extends ParseJson<SortedSet<ContainerCDNMetadata>> public class ParseContainerCDNMetadataListFromJsonResponse extends ParseJson<SortedSet<ContainerCDNMetadata>>
{ {
@Inject @Inject
public ParseContainerCDNMetadataListFromGsonResponse(Gson gson) { public ParseContainerCDNMetadataListFromJsonResponse(Gson gson) {
super(gson); super(gson);
} }
public SortedSet<ContainerCDNMetadata> apply(InputStream stream) { public SortedSet<ContainerCDNMetadata> apply(InputStream stream) {
String toParse;
try {
toParse = IOUtils.toString(stream);
} catch (IOException e1) {
throw new RuntimeException(e1);
}
// Ticket #1871 bad quoting on cdn uri
stream = IOUtils.toInputStream(toParse.replaceAll("m,","m\","));
Type listType = new TypeToken<SortedSet<ContainerCDNMetadata>>() { Type listType = new TypeToken<SortedSet<ContainerCDNMetadata>>() {
}.getType(); }.getType();
try { try {

View File

@ -45,11 +45,11 @@ import com.google.common.base.Function;
public class ParseObjectFromHeadersAndHttpContent implements Function<HttpResponse, CFObject>, public class ParseObjectFromHeadersAndHttpContent implements Function<HttpResponse, CFObject>,
InvocationContext { InvocationContext {
private final ParseObjectMetadataFromHeaders infoParser; private final ParseObjectInfoFromHeaders infoParser;
private final CFObject.Factory objectProvider; private final CFObject.Factory objectProvider;
@Inject @Inject
public ParseObjectFromHeadersAndHttpContent(ParseObjectMetadataFromHeaders infoParser, public ParseObjectFromHeadersAndHttpContent(ParseObjectInfoFromHeaders infoParser,
CFObject.Factory objectProvider) { CFObject.Factory objectProvider) {
this.infoParser = infoParser; this.infoParser = infoParser;
this.objectProvider = objectProvider; this.objectProvider = objectProvider;

View File

@ -29,7 +29,7 @@ import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.functions.ParseSystemAndUserMetadataFromHeaders; import org.jclouds.blobstore.functions.ParseSystemAndUserMetadataFromHeaders;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpUtils; import org.jclouds.http.HttpUtils;
import org.jclouds.rackspace.cloudfiles.blobstore.functions.BlobToObjectInfo; import org.jclouds.rackspace.cloudfiles.blobstore.functions.ResourceToObjectInfo;
import org.jclouds.rackspace.cloudfiles.domain.MutableObjectInfoWithMetadata; import org.jclouds.rackspace.cloudfiles.domain.MutableObjectInfoWithMetadata;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
@ -41,16 +41,16 @@ import com.google.common.base.Function;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class ParseObjectMetadataFromHeaders implements public class ParseObjectInfoFromHeaders implements
Function<HttpResponse, MutableObjectInfoWithMetadata>, InvocationContext { Function<HttpResponse, MutableObjectInfoWithMetadata>, InvocationContext {
private final ParseSystemAndUserMetadataFromHeaders blobMetadataParser; private final ParseSystemAndUserMetadataFromHeaders blobMetadataParser;
private final BlobToObjectInfo blobToObjectInfo; private final ResourceToObjectInfo blobToObjectInfo;
@Inject @Inject
public ParseObjectMetadataFromHeaders(ParseSystemAndUserMetadataFromHeaders blobMetadataParser, public ParseObjectInfoFromHeaders(ParseSystemAndUserMetadataFromHeaders blobMetadataParser,
BlobToObjectInfo blobToObjectMetadata) { ResourceToObjectInfo blobToObjectInfo) {
this.blobMetadataParser = blobMetadataParser; this.blobMetadataParser = blobMetadataParser;
this.blobToObjectInfo = blobToObjectMetadata; this.blobToObjectInfo = blobToObjectInfo;
} }
/** /**

View File

@ -32,6 +32,7 @@ import static org.testng.Assert.fail;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URI;
import java.util.Map; import java.util.Map;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -46,7 +47,6 @@ import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
import org.jclouds.http.HttpUtils; import org.jclouds.http.HttpUtils;
import org.jclouds.http.options.GetOptions; import org.jclouds.http.options.GetOptions;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata; import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata;
import org.jclouds.rackspace.cloudfiles.domain.CFObject; import org.jclouds.rackspace.cloudfiles.domain.CFObject;
import org.jclouds.rackspace.cloudfiles.domain.ContainerCDNMetadata; import org.jclouds.rackspace.cloudfiles.domain.ContainerCDNMetadata;
@ -55,7 +55,6 @@ import org.jclouds.rackspace.cloudfiles.domain.MutableObjectInfoWithMetadata;
import org.jclouds.rackspace.cloudfiles.domain.ObjectInfo; import org.jclouds.rackspace.cloudfiles.domain.ObjectInfo;
import org.jclouds.rackspace.cloudfiles.options.ListCdnContainerOptions; import org.jclouds.rackspace.cloudfiles.options.ListCdnContainerOptions;
import org.jclouds.rackspace.cloudfiles.options.ListContainerOptions; import org.jclouds.rackspace.cloudfiles.options.ListContainerOptions;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
@ -68,25 +67,14 @@ import com.google.common.collect.Maps;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "live", testName = "cloudfiles.CloudFilesClientLiveTest") @Test(groups = "live", testName = "cloudfiles.CloudFilesClientLiveTest")
public class CloudFilesClientLiveTest { public class CloudFilesClientLiveTest extends BaseBlobStoreIntegrationTest<CloudFilesClient> {
private String bucketPrefix = BaseBlobStoreIntegrationTest.CONTAINER_PREFIX;
CloudFilesClient connection;
@BeforeGroups(groups = { "live" })
public void setupClient() {
String account = System.getProperty("jclouds.test.user");
String key = System.getProperty("jclouds.test.key");
connection = CloudFilesContextFactory.createContext(account, key, new Log4JLoggingModule())
.getApi();
}
/** /**
* this method overrides containerName to ensure it isn't found * this method overrides containerName to ensure it isn't found
*/ */
@Test(groups = { "integration", "live" }) @Test(groups = { "integration", "live" })
public void deleteContainerIfEmptyNotFound() throws Exception { public void deleteContainerIfEmptyNotFound() throws Exception {
assert connection.deleteContainerIfEmpty("dbienf").get(10, TimeUnit.SECONDS); assert context.getApi().deleteContainerIfEmpty("dbienf").get(10, TimeUnit.SECONDS);
} }
@Test @Test
@ -94,325 +82,329 @@ public class CloudFilesClientLiveTest {
final long minimumTTL = 60 * 60; // The minimum TTL is 1 hour final long minimumTTL = 60 * 60; // The minimum TTL is 1 hour
// Create two new containers for testing // Create two new containers for testing
final String containerNameWithCDN = bucketPrefix + ".testCDNOperationsContainerWithCDN"; final String containerNameWithCDN = getContainerName();
final String containerNameWithoutCDN = bucketPrefix + ".testCDNOperationsContainerWithoutCDN"; final String containerNameWithoutCDN = getContainerName();
assertTrue(connection.createContainer(containerNameWithCDN).get(10, TimeUnit.SECONDS));
assertTrue(connection.createContainer(containerNameWithoutCDN).get(10, TimeUnit.SECONDS));
ContainerCDNMetadata cdnMetadata = null;
// Enable CDN with PUT for one container
final String cdnUri = connection.enableCDN(containerNameWithCDN);
assertTrue(cdnUri != null);
assertTrue(cdnUri.startsWith("http://"));
// Confirm CDN is enabled via HEAD request and has default TTL
cdnMetadata = connection.getCDNMetadata(containerNameWithCDN);
assertTrue(cdnMetadata.isCdnEnabled());
assertEquals(cdnMetadata.getCdnUri(), cdnUri);
final long initialTTL = cdnMetadata.getTtl();
try { try {
cdnMetadata = connection.getCDNMetadata(containerNameWithoutCDN);
assert false : "should not exist";
} catch (ContainerNotFoundException e) {
}
try { ContainerCDNMetadata cdnMetadata = null;
cdnMetadata = connection.getCDNMetadata("DoesNotExist");
assert false : "should not exist";
} catch (ContainerNotFoundException e) {
}
// List CDN metadata for containers, and ensure all CDN info is available for enabled // Enable CDN with PUT for one container
// container final URI cdnUri = context.getApi().enableCDN(containerNameWithCDN);
SortedSet<ContainerCDNMetadata> cdnMetadataList = connection.listCDNContainers(); assertTrue(cdnUri != null);
assertTrue(cdnMetadataList.size() >= 1);
assertTrue(Iterables.any(cdnMetadataList, new Predicate<ContainerCDNMetadata>() { // Confirm CDN is enabled via HEAD request and has default TTL
public boolean apply(ContainerCDNMetadata cdnMetadata) { cdnMetadata = context.getApi().getCDNMetadata(containerNameWithCDN);
return (cdnMetadata.getName().equals(containerNameWithCDN) assertTrue(cdnMetadata.isCDNEnabled());
&& cdnMetadata.isCdnEnabled() && cdnMetadata.getTtl() == initialTTL && cdnMetadata assertEquals(cdnMetadata.getCDNUri(), cdnUri);
.getCdnUri().equals(cdnUri)); final long initialTTL = cdnMetadata.getTTL();
try {
cdnMetadata = context.getApi().getCDNMetadata(containerNameWithoutCDN);
assert false : "should not exist";
} catch (ContainerNotFoundException e) {
} }
}));
// Test listing with options try {
cdnMetadataList = connection.listCDNContainers(ListCdnContainerOptions.Builder.enabledOnly()); cdnMetadata = context.getApi().getCDNMetadata("DoesNotExist");
assertTrue(Iterables.all(cdnMetadataList, new Predicate<ContainerCDNMetadata>() { assert false : "should not exist";
public boolean apply(ContainerCDNMetadata cdnMetadata) { } catch (ContainerNotFoundException e) {
return cdnMetadata.isCdnEnabled();
} }
}));
cdnMetadataList = connection.listCDNContainers(ListCdnContainerOptions.Builder.afterMarker( // List CDN metadata for containers, and ensure all CDN info is available for enabled
containerNameWithCDN.substring(0, containerNameWithCDN.length() - 1)).maxResults(1)); // container
assertEquals(cdnMetadataList.size(), 1); SortedSet<ContainerCDNMetadata> cdnMetadataList = context.getApi().listCDNContainers();
assertEquals(cdnMetadataList.first().getName(), containerNameWithCDN); assertTrue(cdnMetadataList.size() >= 1);
// Enable CDN with PUT for the same container, this time with a custom TTL assertTrue(cdnMetadataList.contains(new ContainerCDNMetadata(containerNameWithCDN, true,
long ttl = 4000; initialTTL, cdnUri)));
connection.enableCDN(containerNameWithCDN, ttl);
cdnMetadata = connection.getCDNMetadata(containerNameWithCDN); // Test listing with options
assertTrue(cdnMetadata.isCdnEnabled()); cdnMetadataList = context.getApi().listCDNContainers(
assertEquals(cdnMetadata.getTtl(), ttl); ListCdnContainerOptions.Builder.enabledOnly());
assertTrue(Iterables.all(cdnMetadataList, new Predicate<ContainerCDNMetadata>() {
public boolean apply(ContainerCDNMetadata cdnMetadata) {
return cdnMetadata.isCDNEnabled();
}
}));
// Check POST by updating TTL settings cdnMetadataList = context.getApi().listCDNContainers(
ttl = minimumTTL; ListCdnContainerOptions.Builder.afterMarker(
connection.updateCDN(containerNameWithCDN, minimumTTL); containerNameWithCDN.substring(0, containerNameWithCDN.length() - 1))
.maxResults(1));
assertEquals(cdnMetadataList.size(), 1);
cdnMetadata = connection.getCDNMetadata(containerNameWithCDN); // Enable CDN with PUT for the same container, this time with a custom TTL
assertTrue(cdnMetadata.isCdnEnabled()); long ttl = 4000;
assertEquals(cdnMetadata.getTtl(), minimumTTL); context.getApi().enableCDN(containerNameWithCDN, ttl);
// Confirm that minimum allowed value for TTL is 3600, lower values are ignored. cdnMetadata = context.getApi().getCDNMetadata(containerNameWithCDN);
connection.updateCDN(containerNameWithCDN, 3599L); assertTrue(cdnMetadata.isCDNEnabled());
cdnMetadata = connection.getCDNMetadata(containerNameWithCDN); assertEquals(cdnMetadata.getTTL(), ttl);
assertEquals(cdnMetadata.getTtl(), minimumTTL); // Note that TTL is 3600 here, not 3599
// Disable CDN with POST // Check POST by updating TTL settings
assertTrue(connection.disableCDN(containerNameWithCDN)); ttl = minimumTTL;
context.getApi().updateCDN(containerNameWithCDN, minimumTTL);
cdnMetadata = connection.getCDNMetadata(containerNameWithCDN); cdnMetadata = context.getApi().getCDNMetadata(containerNameWithCDN);
assertEquals(cdnMetadata.isCdnEnabled(), false); assertTrue(cdnMetadata.isCDNEnabled());
assertEquals(cdnMetadata.getTTL(), minimumTTL);
// Delete test containers // Confirm that minimum allowed value for TTL is 3600, lower values are ignored.
assertTrue(connection.deleteContainerIfEmpty(containerNameWithCDN).get(10, TimeUnit.SECONDS)); context.getApi().updateCDN(containerNameWithCDN, 3599L);
assertTrue(connection.deleteContainerIfEmpty(containerNameWithoutCDN).get(10, cdnMetadata = context.getApi().getCDNMetadata(containerNameWithCDN);
TimeUnit.SECONDS)); assertEquals(cdnMetadata.getTTL(), minimumTTL); // Note that TTL is 3600 here, not 3599
// Disable CDN with POST
assertTrue(context.getApi().disableCDN(containerNameWithCDN));
cdnMetadata = context.getApi().getCDNMetadata(containerNameWithCDN);
assertEquals(cdnMetadata.isCDNEnabled(), false);
} finally {
recycleContainer(containerNameWithCDN);
recycleContainer(containerNameWithoutCDN);
}
} }
@Test @Test
public void testListOwnedContainers() throws Exception { public void testListOwnedContainers() throws Exception {
SortedSet<ContainerMetadata> response = connection.listContainers(); String containerPrefix = getContainerName();
assertNotNull(response); try {
long initialContainerCount = response.size(); SortedSet<ContainerMetadata> response = context.getApi().listContainers().get(10,
assertTrue(initialContainerCount >= 0); TimeUnit.SECONDS);
assertNotNull(response);
long initialContainerCount = response.size();
assertTrue(initialContainerCount >= 0);
// Create test containers // Create test containers
String[] containerJsr330 = new String[] { bucketPrefix + ".testListOwnedContainers1", String[] containerJsr330 = new String[] { containerPrefix + ".testListOwnedContainers1",
bucketPrefix + ".testListOwnedContainers2" }; containerPrefix + ".testListOwnedContainers2" };
assertTrue(connection.createContainer(containerJsr330[0]).get(10, TimeUnit.SECONDS)); assertTrue(context.getApi().createContainer(containerJsr330[0]).get(10, TimeUnit.SECONDS));
assertTrue(connection.createContainer(containerJsr330[1]).get(10, TimeUnit.SECONDS)); assertTrue(context.getApi().createContainer(containerJsr330[1]).get(10, TimeUnit.SECONDS));
// Test default listing // Test default listing
response = connection.listContainers(); response = context.getApi().listContainers().get(10, TimeUnit.SECONDS);
// assertEquals(response.size(), initialContainerCount + 2);// if the containers already // assertEquals(response.size(), initialContainerCount + 2);// if the containers already
// exist, this will fail // exist, this will fail
// Test listing with options // Test listing with options
response = connection.listContainers(ListContainerOptions.Builder.afterMarker( response = context.getApi().listContainers(
containerJsr330[0].substring(0, containerJsr330[0].length() - 1)).maxResults(1)); ListContainerOptions.Builder.afterMarker(
assertEquals(response.size(), 1); containerJsr330[0].substring(0, containerJsr330[0].length() - 1))
assertEquals(response.first().getName(), containerJsr330[0]); .maxResults(1)).get(10, TimeUnit.SECONDS);
assertEquals(response.size(), 1);
assertEquals(response.first().getName(), containerJsr330[0]);
response = connection.listContainers(ListContainerOptions.Builder.afterMarker( response = context.getApi().listContainers(
containerJsr330[0]).maxResults(1)); ListContainerOptions.Builder.afterMarker(containerJsr330[0]).maxResults(1)).get(
assertEquals(response.size(), 1); 10, TimeUnit.SECONDS);
assertEquals(response.first().getName(), containerJsr330[1]); assertEquals(response.size(), 1);
assertEquals(response.first().getName(), containerJsr330[1]);
// Cleanup and test containers have been removed // Cleanup and test containers have been removed
assertTrue(connection.deleteContainerIfEmpty(containerJsr330[0]).get(10, TimeUnit.SECONDS)); assertTrue(context.getApi().deleteContainerIfEmpty(containerJsr330[0]).get(10,
assertTrue(connection.deleteContainerIfEmpty(containerJsr330[1]).get(10, TimeUnit.SECONDS)); TimeUnit.SECONDS));
response = connection.listContainers(); assertTrue(context.getApi().deleteContainerIfEmpty(containerJsr330[1]).get(10,
// assertEquals(response.size(), initialContainerCount + 2);// if the containers already TimeUnit.SECONDS));
// exist, this will fail response = context.getApi().listContainers().get(10, TimeUnit.SECONDS);
// assertEquals(response.size(), initialContainerCount + 2);// if the containers already
// exist, this will fail
} finally {
returnContainer(containerPrefix);
}
} }
@Test @Test
public void testHeadAccountMetadata() throws Exception { public void testHeadAccountMetadata() throws Exception {
AccountMetadata metadata = connection.getAccountStatistics(); String containerPrefix = getContainerName();
assertNotNull(metadata); String containerName = containerPrefix + ".testHeadAccountMetadata";
long initialContainerCount = metadata.getContainerCount(); try {
AccountMetadata metadata = context.getApi().getAccountStatistics();
assertNotNull(metadata);
long initialContainerCount = metadata.getContainerCount();
String containerName = bucketPrefix + ".testHeadAccountMetadata"; assertTrue(context.getApi().createContainer(containerName).get(10, TimeUnit.SECONDS));
assertTrue(connection.createContainer(containerName).get(10, TimeUnit.SECONDS));
metadata = connection.getAccountStatistics(); metadata = context.getApi().getAccountStatistics();
assertNotNull(metadata); assertNotNull(metadata);
assertTrue(metadata.getContainerCount() >= initialContainerCount); assertTrue(metadata.getContainerCount() >= initialContainerCount);
assertTrue(connection.deleteContainerIfEmpty(containerName).get(10, TimeUnit.SECONDS)); assertTrue(context.getApi().deleteContainerIfEmpty(containerName)
} .get(10, TimeUnit.SECONDS));
} finally {
@Test returnContainer(containerPrefix);
public void testDeleteContainer() throws Exception { }
assertTrue(connection.deleteContainerIfEmpty("does-not-exist").get(10, TimeUnit.SECONDS));
String containerName = bucketPrefix + ".testDeleteContainer";
assertTrue(connection.createContainer(containerName).get(10, TimeUnit.SECONDS));
assertTrue(connection.deleteContainerIfEmpty(containerName).get(10, TimeUnit.SECONDS));
} }
@Test @Test
public void testPutContainers() throws Exception { public void testPutContainers() throws Exception {
String containerName1 = bucketPrefix + ".hello"; String containerName = getContainerName();
assertTrue(connection.createContainer(containerName1).get(10, TimeUnit.SECONDS));
// List only the container just created, using a marker with the container name less 1 char
SortedSet<ContainerMetadata> response = connection
.listContainers(ListContainerOptions.Builder.afterMarker(
containerName1.substring(0, containerName1.length() - 1)).maxResults(1));
assertNotNull(response);
assertEquals(response.size(), 1);
assertEquals(response.first().getName(), bucketPrefix + ".hello");
String containerName2 = bucketPrefix + "?should-be-illegal-question-char";
try { try {
connection.createContainer(containerName2).get(10, TimeUnit.MILLISECONDS); String containerName1 = containerName + ".hello";
fail("Should not be able to create container with illegal '?' character"); assertTrue(context.getApi().createContainer(containerName1).get(10, TimeUnit.SECONDS));
} catch (Exception e) { // List only the container just created, using a marker with the container name less 1 char
} SortedSet<ContainerMetadata> response = context.getApi().listContainers(
ListContainerOptions.Builder.afterMarker(
containerName1.substring(0, containerName1.length() - 1)).maxResults(1))
.get(10, TimeUnit.SECONDS);
assertNotNull(response);
assertEquals(response.size(), 1);
assertEquals(response.first().getName(), containerName + ".hello");
// TODO: Should throw a specific exception, not UndeclaredThrowableException String containerName2 = containerName + "?should-be-illegal-question-char";
try { try {
connection.createContainer(bucketPrefix + "/illegal-slash-char").get(10, context.getApi().createContainer(containerName2).get(10, TimeUnit.MILLISECONDS);
TimeUnit.MILLISECONDS); fail("Should not be able to create container with illegal '?' character");
fail("Should not be able to create container with illegal '/' character"); } catch (Exception e) {
} catch (Exception e) { }
}
assertTrue(connection.deleteContainerIfEmpty(containerName1).get(10, TimeUnit.SECONDS)); // TODO: Should throw a specific exception, not UndeclaredThrowableException
assertTrue(connection.deleteContainerIfEmpty(containerName2).get(10, TimeUnit.SECONDS)); try {
context.getApi().createContainer(containerName + "/illegal-slash-char").get(10,
TimeUnit.MILLISECONDS);
fail("Should not be able to create container with illegal '/' character");
} catch (Exception e) {
}
assertTrue(context.getApi().deleteContainerIfEmpty(containerName1).get(10,
TimeUnit.SECONDS));
assertTrue(context.getApi().deleteContainerIfEmpty(containerName2).get(10,
TimeUnit.SECONDS));
} finally {
returnContainer(containerName);
}
} }
public void testListContainerPath() throws InterruptedException, ExecutionException, public void testListContainerPath() throws InterruptedException, ExecutionException,
TimeoutException, IOException { TimeoutException, IOException {
String containerName = bucketPrefix + ".testList"; String containerName = getContainerName();
try { try {
assertTrue(connection.createContainer(containerName).get(10, TimeUnit.SECONDS));
String data = "foo"; String data = "foo";
connection.putObject(containerName, newCFObject(data, "foo")).get(10, TimeUnit.SECONDS); context.getApi().putObject(containerName, newCFObject(data, "foo")).get(10,
connection.putObject(containerName, newCFObject(data, "path/bar")).get(10, TimeUnit.SECONDS); TimeUnit.SECONDS);
context.getApi().putObject(containerName, newCFObject(data, "path/bar")).get(10,
TimeUnit.SECONDS);
BoundedSortedSet<ObjectInfo> container = connection.listObjects(containerName, BoundedSortedSet<ObjectInfo> container = context.getApi().listObjects(containerName,
underPath("")).get(10, TimeUnit.SECONDS); underPath("")).get(10, TimeUnit.SECONDS);
assert !container.isTruncated(); assert !container.isTruncated();
assertEquals(container.size(), 1); assertEquals(container.size(), 1);
assertEquals(container.first().getName(), "foo"); assertEquals(container.first().getName(), "foo");
container = connection.listObjects(containerName, underPath("path")).get(10, container = context.getApi().listObjects(containerName, underPath("path")).get(10,
TimeUnit.SECONDS); TimeUnit.SECONDS);
assert !container.isTruncated(); assert !container.isTruncated();
assertEquals(container.size(), 1); assertEquals(container.size(), 1);
assertEquals(container.first().getName(), "path/bar"); assertEquals(container.first().getName(), "path/bar");
} finally { } finally {
connection.removeObject(containerName, "foo").get(10, TimeUnit.SECONDS); returnContainer(containerName);
connection.removeObject(containerName, "apps/foo").get(10, TimeUnit.SECONDS);
connection.deleteContainerIfEmpty(containerName).get(10, TimeUnit.SECONDS);
} }
} }
@Test @Test
public void testObjectOperations() throws Exception { public void testObjectOperations() throws Exception {
String containerName = bucketPrefix + ".testObjectOperations"; String containerName = getContainerName();
assertTrue(connection.createContainer(containerName).get(10, TimeUnit.SECONDS));
// Test PUT with string data, ETag hash, and a piece of metadata
String data = "Here is my data";
String key = "object";
CFObject object = newCFObject(data, key);
byte[] md5 = object.getInfo().getHash();
String newEtag = connection.putObject(containerName, object).get(10, TimeUnit.SECONDS);
assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(object.getInfo()
.getHash()));
// Test HEAD of missing object
try { try {
connection.getObjectInfo(containerName, "non-existent-object"); // Test PUT with string data, ETag hash, and a piece of metadata
assert false; String data = "Here is my data";
} catch (KeyNotFoundException e) { String key = "object";
CFObject object = newCFObject(data, key);
byte[] md5 = object.getInfo().getHash();
String newEtag = context.getApi().putObject(containerName, object).get(10,
TimeUnit.SECONDS);
assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(object.getInfo().getHash()));
// Test HEAD of missing object
try {
context.getApi().getObjectInfo(containerName, "non-existent-object");
assert false;
} catch (KeyNotFoundException e) {
}
// Test HEAD of object
MutableObjectInfoWithMetadata metadata = context.getApi().getObjectInfo(containerName,
object.getInfo().getName());
// TODO assertEquals(metadata.getName(), object.getMetadata().getName());
assertEquals(metadata.getBytes(), new Long(data.length()));
assertEquals(metadata.getContentType(), "text/plain");
assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(object.getInfo().getHash()));
assertEquals(metadata.getHash(), HttpUtils.fromHexString(newEtag));
assertEquals(metadata.getMetadata().entrySet().size(), 1);
assertEquals(metadata.getMetadata().get("metadata"), "metadata-value");
// // Test POST to update object's metadata
Map<String, String> userMetadata = Maps.newHashMap();
userMetadata.put("New-Metadata-1", "value-1");
userMetadata.put("New-Metadata-2", "value-2");
assertTrue(context.getApi().setObjectInfo(containerName, object.getInfo().getName(),
userMetadata));
// Test GET of missing object
try {
context.getApi().getObject(containerName, "non-existent-object").get(10,
TimeUnit.SECONDS);
assert false;
} catch (KeyNotFoundException e) {
}
// Test GET of object (including updated metadata)
CFObject getBlob = context.getApi().getObject(containerName, object.getInfo().getName())
.get(120, TimeUnit.SECONDS);
assertEquals(IOUtils.toString((InputStream) getBlob.getData()), data);
// TODO assertEquals(getBlob.getName(), object.getMetadata().getName());
assertEquals(getBlob.getContentLength(), new Long(data.length()));
assertEquals(getBlob.getInfo().getContentType(), "text/plain");
assertEquals(HttpUtils.toHexString(md5), HttpUtils
.toHexString(getBlob.getInfo().getHash()));
assertEquals(HttpUtils.fromHexString(newEtag), getBlob.getInfo().getHash());
assertEquals(getBlob.getInfo().getMetadata().entrySet().size(), 2);
assertEquals(getBlob.getInfo().getMetadata().get("new-metadata-1"), "value-1");
assertEquals(getBlob.getInfo().getMetadata().get("new-metadata-2"), "value-2");
// Test PUT with invalid ETag (as if object's data was corrupted in transit)
String correctEtag = newEtag;
String incorrectEtag = "0" + correctEtag.substring(1);
object.getInfo().setHash(HttpUtils.fromHexString(incorrectEtag));
try {
context.getApi().putObject(containerName, object).get(10, TimeUnit.SECONDS);
} catch (Throwable e) {
assertEquals(e.getCause().getClass(), HttpResponseException.class);
assertEquals(((HttpResponseException) e.getCause()).getResponse().getStatusCode(), 422);
}
// Test PUT chunked/streamed upload with data of "unknown" length
ByteArrayInputStream bais = new ByteArrayInputStream(data.getBytes("UTF-8"));
CFObject blob = context.getApi().newCFObject();
blob.getInfo().setName("chunked-object");
blob.setData(bais);
newEtag = context.getApi().putObject(containerName, blob).get(10, TimeUnit.SECONDS);
assertEquals(HttpUtils.toHexString(md5), HttpUtils
.toHexString(getBlob.getInfo().getHash()));
// Test GET with options
// Non-matching ETag
try {
context.getApi().getObject(containerName, object.getInfo().getName(),
GetOptions.Builder.ifETagDoesntMatch(newEtag)).get(120, TimeUnit.SECONDS);
} catch (Exception e) {
assertEquals(e.getCause().getClass(), HttpResponseException.class);
assertEquals(((HttpResponseException) e.getCause()).getResponse().getStatusCode(), 304);
}
// Matching ETag
getBlob = context.getApi().getObject(containerName, object.getInfo().getName(),
GetOptions.Builder.ifETagMatches(newEtag)).get(120, TimeUnit.SECONDS);
assertEquals(getBlob.getInfo().getHash(), HttpUtils.fromHexString(newEtag));
getBlob = context.getApi().getObject(containerName, object.getInfo().getName(),
GetOptions.Builder.startAt(8)).get(120, TimeUnit.SECONDS);
assertEquals(IOUtils.toString((InputStream) getBlob.getData()), data.substring(8));
} finally {
returnContainer(containerName);
} }
// Test HEAD of object
MutableObjectInfoWithMetadata metadata = connection.getObjectInfo(containerName, object.getInfo()
.getName());
// TODO assertEquals(metadata.getName(), object.getMetadata().getName());
assertEquals(metadata.getBytes(), new Long(data.length()));
assertEquals(metadata.getContentType(), "text/plain");
assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(object.getInfo()
.getHash()));
assertEquals(metadata.getHash(), HttpUtils.fromHexString(newEtag));
assertEquals(metadata.getMetadata().entrySet().size(), 1);
assertEquals(metadata.getMetadata().get("metadata"), "metadata-value");
// // Test POST to update object's metadata
Map<String, String> userMetadata = Maps.newHashMap();
userMetadata.put("New-Metadata-1", "value-1");
userMetadata.put("New-Metadata-2", "value-2");
assertTrue(connection.setObjectMetadata(containerName, object.getInfo().getName(),
userMetadata));
// Test GET of missing object
try {
connection.getObject(containerName, "non-existent-object").get(10, TimeUnit.SECONDS);
assert false;
} catch (KeyNotFoundException e) {
}
// Test GET of object (including updated metadata)
CFObject getBlob = connection.getObject(containerName, object.getInfo().getName()).get(120,
TimeUnit.SECONDS);
assertEquals(IOUtils.toString((InputStream) getBlob.getData()), data);
// TODO assertEquals(getBlob.getName(), object.getMetadata().getName());
assertEquals(getBlob.getContentLength(), new Long(data.length()));
assertEquals(getBlob.getInfo().getContentType(), "text/plain");
assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(getBlob.getInfo()
.getHash()));
assertEquals(HttpUtils.fromHexString(newEtag), getBlob.getInfo().getHash());
assertEquals(getBlob.getInfo().getMetadata().entrySet().size(), 2);
assertEquals(getBlob.getInfo().getMetadata().get("new-metadata-1"), "value-1");
assertEquals(getBlob.getInfo().getMetadata().get("new-metadata-2"), "value-2");
// Test PUT with invalid ETag (as if object's data was corrupted in transit)
String correctEtag = newEtag;
String incorrectEtag = "0" + correctEtag.substring(1);
object.getInfo().setHash(HttpUtils.fromHexString(incorrectEtag));
try {
connection.putObject(containerName, object).get(10, TimeUnit.SECONDS);
} catch (Throwable e) {
assertEquals(e.getCause().getClass(), HttpResponseException.class);
assertEquals(((HttpResponseException) e.getCause()).getResponse().getStatusCode(), 422);
}
// Test PUT chunked/streamed upload with data of "unknown" length
ByteArrayInputStream bais = new ByteArrayInputStream(data.getBytes("UTF-8"));
CFObject blob = connection.newCFObject();
blob.getInfo().setName("chunked-object");
blob.setData(bais);
newEtag = connection.putObject(containerName, blob).get(10, TimeUnit.SECONDS);
assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(getBlob.getInfo()
.getHash()));
// Test GET with options
// Non-matching ETag
try {
connection.getObject(containerName, object.getInfo().getName(),
GetOptions.Builder.ifETagDoesntMatch(newEtag)).get(120, TimeUnit.SECONDS);
} catch (Exception e) {
assertEquals(e.getCause().getClass(), HttpResponseException.class);
assertEquals(((HttpResponseException) e.getCause()).getResponse().getStatusCode(), 304);
}
// Matching ETag
getBlob = connection.getObject(containerName, object.getInfo().getName(),
GetOptions.Builder.ifETagMatches(newEtag)).get(120, TimeUnit.SECONDS);
assertEquals(getBlob.getInfo().getHash(), HttpUtils.fromHexString(newEtag));
getBlob = connection.getObject(containerName, object.getInfo().getName(),
GetOptions.Builder.startAt(8)).get(120, TimeUnit.SECONDS);
assertEquals(IOUtils.toString((InputStream) getBlob.getData()), data.substring(8));
connection.removeObject(containerName, "object").get(10, TimeUnit.SECONDS);
connection.removeObject(containerName, "chunked-object").get(10, TimeUnit.SECONDS);
assertTrue(connection.deleteContainerIfEmpty(containerName).get(10, TimeUnit.SECONDS));
} }
private CFObject newCFObject(String data, String key) throws IOException { private CFObject newCFObject(String data, String key) throws IOException {
CFObject object = connection.newCFObject(); CFObject object = context.getApi().newCFObject();
object.getInfo().setName(key); object.getInfo().setName(key);
object.setData(data); object.setData(data);
object.generateMD5(); object.generateMD5();

View File

@ -30,7 +30,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.jclouds.rackspace.StubRackspaceAuthenticationModule; import org.jclouds.rackspace.StubRackspaceAuthenticationModule;
import org.jclouds.rackspace.cloudfiles.config.StubCloudFilesClientModule; import org.jclouds.rackspace.cloudfiles.config.CloudFilesStubClientModule;
import org.jclouds.rackspace.cloudfiles.internal.StubCloudFilesClient; import org.jclouds.rackspace.cloudfiles.internal.StubCloudFilesClient;
import org.jclouds.rackspace.cloudfiles.reference.CloudFilesConstants; import org.jclouds.rackspace.cloudfiles.reference.CloudFilesConstants;
import org.jclouds.rackspace.config.RackspaceAuthenticationRestModule; import org.jclouds.rackspace.config.RackspaceAuthenticationRestModule;
@ -72,7 +72,7 @@ public class CloudFilesContextBuilderTest {
public void testBuildContext() { public void testBuildContext() {
RestContext<CloudFilesClient> context = newBuilder().withModules( RestContext<CloudFilesClient> context = newBuilder().withModules(
new StubCloudFilesClientModule(), new StubRackspaceAuthenticationModule()) new CloudFilesStubClientModule(), new StubRackspaceAuthenticationModule())
.buildContext(); .buildContext();
assertEquals(context.getClass(), RestContextImpl.class); assertEquals(context.getClass(), RestContextImpl.class);
assertEquals(context.getApi().getClass(), StubCloudFilesClient.class); assertEquals(context.getApi().getClass(), StubCloudFilesClient.class);
@ -81,7 +81,7 @@ public class CloudFilesContextBuilderTest {
} }
public void testBuildInjector() { public void testBuildInjector() {
Injector i = newBuilder().withModules(new StubCloudFilesClientModule(), Injector i = newBuilder().withModules(new CloudFilesStubClientModule(),
new StubRackspaceAuthenticationModule()).buildInjector(); new StubRackspaceAuthenticationModule()).buildInjector();
assert i.getInstance(Key.get(new TypeLiteral<RestContext<CloudFilesClient>>() { assert i.getInstance(Key.get(new TypeLiteral<RestContext<CloudFilesClient>>() {
})) != null; })) != null;

View File

@ -27,9 +27,10 @@ import static org.testng.Assert.assertEquals;
import org.jclouds.concurrent.WithinThreadExecutorService; import org.jclouds.concurrent.WithinThreadExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule; import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import org.jclouds.rackspace.StubRackspaceAuthenticationModule; import org.jclouds.rackspace.StubRackspaceAuthenticationModule;
import org.jclouds.rackspace.cloudfiles.config.CloudFilesContextModule; import org.jclouds.rackspace.cloudfiles.config.CloudFilesContextModule;
import org.jclouds.rackspace.cloudfiles.config.StubCloudFilesClientModule; import org.jclouds.rackspace.cloudfiles.config.CloudFilesStubClientModule;
import org.jclouds.rackspace.cloudfiles.reference.CloudFilesConstants; import org.jclouds.rackspace.cloudfiles.reference.CloudFilesConstants;
import org.jclouds.rest.RestContext; import org.jclouds.rest.RestContext;
import org.jclouds.rest.internal.RestContextImpl; import org.jclouds.rest.internal.RestContextImpl;
@ -49,8 +50,8 @@ public class CloudFilesContextModuleTest {
Injector createInjector() { Injector createInjector() {
return Guice.createInjector(new ExecutorServiceModule(new WithinThreadExecutorService()), return Guice.createInjector(new ExecutorServiceModule(new WithinThreadExecutorService()),
new StubCloudFilesClientModule(), new StubRackspaceAuthenticationModule(), new CloudFilesStubClientModule(), new JDKLoggingModule(),
new CloudFilesContextModule() { new StubRackspaceAuthenticationModule(), new CloudFilesContextModule() {
@Override @Override
protected void configure() { protected void configure() {
bindConstant().annotatedWith( bindConstant().annotatedWith(

View File

@ -0,0 +1,112 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore;
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.internal.BlobImpl;
import org.jclouds.blobstore.internal.BlobStoreContextImpl;
import org.jclouds.rackspace.StubRackspaceAuthenticationModule;
import org.jclouds.rackspace.cloudfiles.CloudFilesClient;
import org.jclouds.rackspace.cloudfiles.blobstore.config.CloudFilesBlobStoreContextModule;
import org.jclouds.rackspace.cloudfiles.config.CloudFilesRestClientModule;
import org.jclouds.rackspace.cloudfiles.config.CloudFilesStubClientModule;
import org.jclouds.rackspace.cloudfiles.domain.CFObject;
import org.jclouds.rackspace.cloudfiles.domain.internal.CFObjectImpl;
import org.jclouds.rackspace.cloudfiles.internal.StubCloudFilesClient;
import org.jclouds.rackspace.reference.RackspaceConstants;
import org.testng.annotations.Test;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/**
* Tests behavior of modules configured in CloudFilesContextBuilder
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "cloudfiles.CloudFilesContextBuilderTest")
public class CloudFilesBlobStoreContextBuilderTest {
public void testNewBuilder() {
CloudFilesBlobStoreContextBuilder builder = newBuilder();
assertEquals(builder.getProperties().getProperty(PROPERTY_USER_METADATA_PREFIX),
"X-Object-Meta-");
assertEquals(builder.getProperties().getProperty(RackspaceConstants.PROPERTY_RACKSPACE_USER),
"id");
assertEquals(builder.getProperties().getProperty(RackspaceConstants.PROPERTY_RACKSPACE_KEY),
"secret");
}
private CloudFilesBlobStoreContextBuilder newBuilder() {
return new CloudFilesBlobStoreContextBuilder(new CloudFilesBlobStorePropertiesBuilder("id",
"secret").build()).withModules(new CloudFilesStubClientModule(),
new StubRackspaceAuthenticationModule());
}
public void testBuildContext() {
BlobStoreContext<CloudFilesClient> context = newBuilder().buildContext();
assertEquals(context.getClass(), BlobStoreContextImpl.class);
assertEquals(context.getApi().getClass(), StubCloudFilesClient.class);
assertEquals(context.getBlobStore().getClass(), CloudFilesBlobStore.class);
assertEquals(context.getApi().newCFObject().getClass(), CFObjectImpl.class);
assertEquals(context.getBlobStore().newBlob().getClass(), BlobImpl.class);
assertEquals(context.getAccount(), "id");
assertEquals(context.getEndPoint(), URI.create("http://localhost/rackspacestub/cloudfiles"));
}
public void testBuildInjector() {
Injector i = newBuilder().buildInjector();
assert i.getInstance(Key.get(new TypeLiteral<BlobStoreContext<CloudFilesClient>>() {
})) != null;
assert i.getInstance(CFObject.class) != null;
assert i.getInstance(Blob.class) != null;
}
protected void testAddContextModule() {
List<Module> modules = new ArrayList<Module>();
CloudFilesBlobStoreContextBuilder builder = newBuilder();
builder.addContextModule(modules);
assertEquals(modules.size(), 1);
assertEquals(modules.get(0).getClass(), CloudFilesBlobStoreContextModule.class);
}
protected void addClientModule() {
List<Module> modules = new ArrayList<Module>();
CloudFilesBlobStoreContextBuilder builder = newBuilder();
builder.addClientModule(modules);
assertEquals(modules.size(), 1);
assertEquals(modules.get(0).getClass(), CloudFilesRestClientModule.class);
}
}

View File

@ -0,0 +1,77 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore.config;
import static org.testng.Assert.assertEquals;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.internal.BlobStoreContextImpl;
import org.jclouds.concurrent.WithinThreadExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import org.jclouds.rackspace.StubRackspaceAuthenticationModule;
import org.jclouds.rackspace.cloudfiles.CloudFilesClient;
import org.jclouds.rackspace.cloudfiles.config.CloudFilesStubClientModule;
import org.jclouds.rackspace.reference.RackspaceConstants;
import org.jclouds.util.Jsr330;
import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "cloudfiles.CloudFilesBlobStoreModuleTest")
public class CloudFilesBlobStoreModuleTest {
Injector createInjector() {
return Guice.createInjector(new ExecutorServiceModule(new WithinThreadExecutorService()),
new JDKLoggingModule(), new CloudFilesStubClientModule(),
new StubRackspaceAuthenticationModule(), new CloudFilesBlobStoreContextModule() {
@Override
protected void configure() {
bindConstant().annotatedWith(
Jsr330.named(RackspaceConstants.PROPERTY_RACKSPACE_USER)).to("user");
bindConstant().annotatedWith(
Jsr330.named(RackspaceConstants.PROPERTY_RACKSPACE_KEY)).to("key");
bindConstant().annotatedWith(
Jsr330.named(RackspaceConstants.PROPERTY_RACKSPACE_ENDPOINT)).to(
"http://localhost");
super.configure();
}
});
}
@Test
void testContextImpl() {
BlobStoreContext<CloudFilesClient> context = createInjector().getInstance(
Key.get(new TypeLiteral<BlobStoreContext<CloudFilesClient>>() {
}));
assertEquals(context.getClass(), BlobStoreContextImpl.class);
}
}

View File

@ -0,0 +1,49 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore.integration;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import org.jclouds.blobstore.integration.internal.BaseBlobIntegrationTest;
import org.jclouds.rackspace.cloudfiles.CloudFilesClient;
import org.testng.annotations.Test;
/**
*
* @author James Murty
* @author Adrian Cole
*/
@Test(groups = { "integration", "live" }, testName = "cloudfiles.CloudFilesBlobIntegrationTest")
public class CloudFilesBlobIntegrationTest extends BaseBlobIntegrationTest<CloudFilesClient> {
@Override
@Test(enabled = false)
public void testGetTwoRanges() throws InterruptedException, ExecutionException,
TimeoutException, IOException {
// not supported in cloud files
}
}

View File

@ -0,0 +1,38 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore.integration;
import org.jclouds.blobstore.integration.internal.BaseBlobLiveTest;
import org.jclouds.rackspace.cloudfiles.CloudFilesClient;
import org.testng.annotations.Test;
/**
*
* @author James Murty
* @author Adrian Cole
*/
@Test(groups = { "live" }, testName = "cloudfiles.CloudFilesBlobLiveTest")
public class CloudFilesBlobLiveTest extends BaseBlobLiveTest<CloudFilesClient> {
}

View File

@ -0,0 +1,36 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore.integration;
import org.jclouds.blobstore.integration.internal.BaseBlobMapIntegrationTest;
import org.jclouds.rackspace.cloudfiles.CloudFilesClient;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = { "integration", "live" }, testName = "cloudfiles.CloudFilesBlobMapIntegrationTest")
public class CloudFilesBlobMapIntegrationTest extends BaseBlobMapIntegrationTest<CloudFilesClient> {
}

View File

@ -0,0 +1,37 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore.integration;
import org.jclouds.blobstore.integration.internal.BaseContainerIntegrationTest;
import org.jclouds.rackspace.cloudfiles.CloudFilesClient;
import org.testng.annotations.Test;
/**
* @author James Murty
* @author Adrian Cole
*/
@Test(groups = { "integration", "live" }, testName = "cloudfiles.CloudFilesContainerIntegrationTest")
public class CloudFilesContainerIntegrationTest extends BaseContainerIntegrationTest<CloudFilesClient> {
}

View File

@ -0,0 +1,37 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore.integration;
import org.jclouds.blobstore.integration.internal.BaseContainerLiveTest;
import org.jclouds.rackspace.cloudfiles.CloudFilesClient;
import org.testng.annotations.Test;
/**
* @author James Murty
* @author Adrian Cole
*/
@Test(groups = { "live" }, testName = "cloudfiles.CloudFilesContainerLiveTest")
public class CloudFilesContainerLiveTest extends BaseContainerLiveTest<CloudFilesClient> {
}

View File

@ -0,0 +1,37 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore.integration;
import org.jclouds.blobstore.integration.internal.BaseInputStreamMapIntegrationTest;
import org.jclouds.rackspace.cloudfiles.CloudFilesClient;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = { "integration", "live" }, testName = "cloudfiles.CloudFilesInputStreamMapIntegrationTest")
public class CloudFilesInputStreamMapIntegrationTest extends
BaseInputStreamMapIntegrationTest<CloudFilesClient> {
}

View File

@ -0,0 +1,36 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore.integration;
import org.jclouds.blobstore.integration.internal.BaseServiceIntegrationTest;
import org.jclouds.rackspace.cloudfiles.CloudFilesClient;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = { "integration", "live" }, testName = "cloudfiles.CloudFilesServiceIntegrationTest")
public class CloudFilesServiceIntegrationTest extends BaseServiceIntegrationTest<CloudFilesClient> {
}

View File

@ -0,0 +1,58 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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.blobstore.integration;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.integration.internal.BaseTestInitializer;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rackspace.StubRackspaceAuthenticationModule;
import org.jclouds.rackspace.cloudfiles.CloudFilesClient;
import org.jclouds.rackspace.cloudfiles.blobstore.CloudFilesBlobStoreContextBuilder;
import org.jclouds.rackspace.cloudfiles.blobstore.CloudFilesBlobStoreContextFactory;
import org.jclouds.rackspace.cloudfiles.blobstore.CloudFilesBlobStorePropertiesBuilder;
import org.jclouds.rackspace.cloudfiles.config.CloudFilesStubClientModule;
import com.google.inject.Module;
/**
*
* @author Adrian Cole
*/
public class CloudFilesTestInitializer extends BaseTestInitializer<CloudFilesClient> {
@Override
protected BlobStoreContext<CloudFilesClient> createLiveContext(Module configurationModule,
String url, String app, String account, String key) {
return new CloudFilesBlobStoreContextBuilder(new CloudFilesBlobStorePropertiesBuilder(
account, key).relaxSSLHostname().build()).withModules(configurationModule,
new Log4JLoggingModule()).buildContext();
}
@Override
protected BlobStoreContext<CloudFilesClient> createStubContext() {
return CloudFilesBlobStoreContextFactory.createContext("user", "pass",
new StubRackspaceAuthenticationModule(), new CloudFilesStubClientModule());
}
}

View File

@ -35,7 +35,7 @@ import com.google.inject.AbstractModule;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
@ConfiguresRestClient @ConfiguresRestClient
public class StubCloudFilesClientModule extends AbstractModule { public class CloudFilesStubClientModule extends AbstractModule {
// must be singleton for all threads and all objects or tests may fail; // must be singleton for all threads and all objects or tests may fail;
static final ConcurrentHashMap<String, ConcurrentMap<String, Blob>> map = new ConcurrentHashMap<String, ConcurrentMap<String, Blob>>(); static final ConcurrentHashMap<String, ConcurrentMap<String, Blob>> map = new ConcurrentHashMap<String, ConcurrentMap<String, Blob>>();
@ -44,7 +44,6 @@ public class StubCloudFilesClientModule extends AbstractModule {
bind(new TypeLiteral<ConcurrentMap<String, ConcurrentMap<String, Blob>>>() { bind(new TypeLiteral<ConcurrentMap<String, ConcurrentMap<String, Blob>>>() {
}).toInstance(map); }).toInstance(map);
bind(new TypeLiteral<CloudFilesClient>() { bind(new TypeLiteral<CloudFilesClient>() {
}).to(new TypeLiteral<StubCloudFilesClient>() { }).to(new TypeLiteral<StubCloudFilesClient>() {
}).asEagerSingleton(); }).asEagerSingleton();

View File

@ -0,0 +1,68 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.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 org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.URI;
import java.util.List;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.rackspace.cloudfiles.domain.ContainerCDNMetadata;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.gson.Gson;
import com.google.inject.Guice;
import com.google.inject.Injector;
/**
* Tests behavior of {@code ParseContainerCDNMetadataListFromJsonResponse}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "cloudfiles.ParseContainerCDNMetadataListFromJsonResponseTest")
public class ParseContainerCDNMetadataListFromJsonResponseTest {
Injector i = Guice.createInjector(new ParserModule());
@Test
public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/test_list_cdn.json");
List<ContainerCDNMetadata> expects = ImmutableList.of(
new ContainerCDNMetadata("adriancole-blobstore.testCDNOperationsContainerWithCDN", false,
3600, URI.create("http://c0354712.cdn.cloudfiles.rackspacecloud.com")),
new ContainerCDNMetadata("adriancole-blobstore5", true, 28800, URI
.create("http://c0404671.cdn.cloudfiles.rackspacecloud.com")),
new ContainerCDNMetadata("adriancole-cfcdnint.testCDNOperationsContainerWithCDN",
false, 3600, URI
.create("http://c0320431.cdn.cloudfiles.rackspacecloud.com")));
ParseContainerCDNMetadataListFromJsonResponse parser = new ParseContainerCDNMetadataListFromJsonResponse(
i.getInstance(Gson.class));
assertEquals(parser.apply(is), expects);
}
}

View File

@ -47,8 +47,8 @@ import com.google.inject.util.Jsr330;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", testName = "cloudfiles.ParseObjectMetadataFromHeadersTest") @Test(groups = "unit", testName = "cloudfiles.ParseObjectInfoFromHeadersTest")
public class ParseObjectMetadataFromHeadersTest { public class ParseObjectInfoFromHeadersTest {
Injector i = Guice.createInjector(new ParserModule(), new AbstractModule() { Injector i = Guice.createInjector(new ParserModule(), new AbstractModule() {
@Override @Override
@ -60,7 +60,7 @@ public class ParseObjectMetadataFromHeadersTest {
}); });
public void testEtagCaseIssue() { public void testEtagCaseIssue() {
ParseObjectMetadataFromHeaders parser = i.getInstance(ParseObjectMetadataFromHeaders.class); ParseObjectInfoFromHeaders parser = i.getInstance(ParseObjectInfoFromHeaders.class);
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/test")).atLeastOnce(); expect(request.getEndpoint()).andReturn(URI.create("http://localhost/test")).atLeastOnce();
replay(request); replay(request);

View File

@ -44,12 +44,12 @@ import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
/** /**
* Tests behavior of {@code ParseBlobMetadataListFromJsonResponseTest} * Tests behavior of {@code ParseObjectInfoListFromJsonResponseTest}
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", testName = "cloudfiles.ParseBlobMetadataListFromJsonResponseTest") @Test(groups = "unit", testName = "cloudfiles.ParseObjectInfoListFromJsonResponseTest")
public class ParseBlobMetadataListFromJsonResponseTest { public class ParseObjectInfoListFromJsonResponseTest {
Injector i = Guice.createInjector(new ParserModule()); Injector i = Guice.createInjector(new ParserModule());

View File

@ -23,13 +23,32 @@
*/ */
package org.jclouds.rackspace.cloudfiles.internal; package org.jclouds.rackspace.cloudfiles.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI;
import java.util.Map; import java.util.Map;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import javax.inject.Inject;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BoundedSortedSet; import org.jclouds.blobstore.domain.BoundedSortedSet;
import org.jclouds.blobstore.functions.HttpGetOptionsListToGetOptions;
import org.jclouds.blobstore.integration.internal.StubBlobStore;
import org.jclouds.blobstore.integration.internal.StubBlobStore.FutureBase;
import org.jclouds.blobstore.options.ListOptions;
import org.jclouds.concurrent.FutureFunctionWrapper;
import org.jclouds.http.options.GetOptions; import org.jclouds.http.options.GetOptions;
import org.jclouds.logging.Logger.LoggerFactory;
import org.jclouds.rackspace.cloudfiles.CloudFilesClient; import org.jclouds.rackspace.cloudfiles.CloudFilesClient;
import org.jclouds.rackspace.cloudfiles.blobstore.functions.BlobToObject;
import org.jclouds.rackspace.cloudfiles.blobstore.functions.ListContainerOptionsToListOptions;
import org.jclouds.rackspace.cloudfiles.blobstore.functions.ObjectToBlob;
import org.jclouds.rackspace.cloudfiles.blobstore.functions.ResourceToObjectInfo;
import org.jclouds.rackspace.cloudfiles.blobstore.functions.ResourceToObjectList;
import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata; import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata;
import org.jclouds.rackspace.cloudfiles.domain.CFObject; import org.jclouds.rackspace.cloudfiles.domain.CFObject;
import org.jclouds.rackspace.cloudfiles.domain.ContainerCDNMetadata; import org.jclouds.rackspace.cloudfiles.domain.ContainerCDNMetadata;
@ -39,34 +58,72 @@ import org.jclouds.rackspace.cloudfiles.domain.ObjectInfo;
import org.jclouds.rackspace.cloudfiles.options.ListCdnContainerOptions; import org.jclouds.rackspace.cloudfiles.options.ListCdnContainerOptions;
import org.jclouds.rackspace.cloudfiles.options.ListContainerOptions; import org.jclouds.rackspace.cloudfiles.options.ListContainerOptions;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
/** /**
* Implementation of {@link CloudFilesClient} which keeps all data in a local Map object. * Implementation of {@link CloudFilesClient} which keeps all data in a local Map object.
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class StubCloudFilesClient implements CloudFilesClient { public class StubCloudFilesClient implements CloudFilesClient {
private final HttpGetOptionsListToGetOptions httpGetOptionsConverter;
private final StubBlobStore blobStore;
private final LoggerFactory logFactory;
private final CFObject.Factory objectProvider;
private final ObjectToBlob object2Blob;
private final BlobToObject blob2Object;
private final ResourceToObjectInfo blob2ObjectInfo;
private final ListContainerOptionsToListOptions container2ContainerListOptions;
private final ResourceToObjectList resource2ObjectList;
@Inject
private StubCloudFilesClient(StubBlobStore blobStore, LoggerFactory logFactory,
ConcurrentMap<String, ConcurrentMap<String, Blob>> containerToBlobs,
CFObject.Factory objectProvider,
HttpGetOptionsListToGetOptions httpGetOptionsConverter, ObjectToBlob object2Blob,
BlobToObject blob2Object, ResourceToObjectInfo blob2ObjectInfo,
ListContainerOptionsToListOptions container2ContainerListOptions,
ResourceToObjectList resource2ContainerList) {
this.blobStore = blobStore;
this.logFactory = logFactory;
this.objectProvider = objectProvider;
this.httpGetOptionsConverter = httpGetOptionsConverter;
this.object2Blob = checkNotNull(object2Blob, "object2Blob");
this.blob2Object = checkNotNull(blob2Object, "blob2Object");
this.blob2ObjectInfo = checkNotNull(blob2ObjectInfo, "blob2ObjectInfo");
this.container2ContainerListOptions = checkNotNull(container2ContainerListOptions,
"container2ContainerListOptions");
this.resource2ObjectList = checkNotNull(resource2ContainerList, "resource2ContainerList");
}
protected <F, T> Future<T> wrapFuture(Future<? extends F> future, Function<F, T> function) {
return new FutureFunctionWrapper<F, T>(future, function, logFactory.getLogger(function
.getClass().getName()));
}
public boolean containerExists(String container) { public boolean containerExists(String container) {
throw new UnsupportedOperationException(); return blobStore.getContainerToBlobs().containsKey(container);
} }
public Future<Boolean> createContainer(String container) { public Future<Boolean> createContainer(String container) {
throw new UnsupportedOperationException(); return blobStore.createContainer(container);
} }
public Future<Boolean> deleteContainerIfEmpty(String container) { public Future<Boolean> deleteContainerIfEmpty(String container) {
throw new UnsupportedOperationException(); return blobStore.deleteContainerImpl(container);
} }
public boolean disableCDN(String container) { public boolean disableCDN(String container) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public String enableCDN(String container, Long ttl) { public URI enableCDN(String container, Long ttl) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public String enableCDN(String container) { public URI enableCDN(String container) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -79,44 +136,58 @@ public class StubCloudFilesClient implements CloudFilesClient {
} }
public Future<CFObject> getObject(String container, String key, GetOptions... options) { public Future<CFObject> getObject(String container, String key, GetOptions... options) {
throw new UnsupportedOperationException(); org.jclouds.blobstore.options.GetOptions getOptions = httpGetOptionsConverter.apply(options);
return wrapFuture(blobStore.getBlob(container, key, getOptions), blob2Object);
} }
public MutableObjectInfoWithMetadata getObjectInfo(String container, String key) { public MutableObjectInfoWithMetadata getObjectInfo(String container, String key) {
throw new UnsupportedOperationException(); return blob2ObjectInfo.apply(blobStore.blobMetadata(container, key));
} }
public SortedSet<ContainerCDNMetadata> listCDNContainers(ListCdnContainerOptions... options) { public SortedSet<ContainerCDNMetadata> listCDNContainers(ListCdnContainerOptions... options) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public SortedSet<ContainerMetadata> listContainers(ListContainerOptions... options) { public Future<? extends SortedSet<ContainerMetadata>> listContainers(
throw new UnsupportedOperationException(); ListContainerOptions... options) {
return new FutureBase<SortedSet<ContainerMetadata>>() {
public SortedSet<ContainerMetadata> get() throws InterruptedException, ExecutionException {
return Sets.newTreeSet(Iterables.transform(blobStore.getContainerToBlobs().keySet(),
new Function<String, ContainerMetadata>() {
public ContainerMetadata apply(String name) {
return new ContainerMetadata(name, -1, -1);
}
}));
}
};
} }
public Future<BoundedSortedSet<ObjectInfo>> listObjects(String container, public Future<BoundedSortedSet<ObjectInfo>> listObjects(String container,
ListContainerOptions... options) { ListContainerOptions... optionsList) {
throw new UnsupportedOperationException(); ListOptions options = container2ContainerListOptions.apply(optionsList);
return wrapFuture(blobStore.list(container, options), resource2ObjectList);
} }
public Future<String> putObject(String container, CFObject object) { public Future<String> putObject(String container, CFObject object) {
throw new UnsupportedOperationException(); return blobStore.putBlob(container, object2Blob.apply(object));
} }
public Future<Void> removeObject(String container, String key) { public Future<Void> removeObject(String container, String key) {
return blobStore.removeBlob(container, key);
}
public boolean setObjectInfo(String container, String key, Map<String, String> userMetadata) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public boolean setObjectMetadata(String container, String key, Map<String, String> userMetadata) { public URI updateCDN(String container, Long ttl) {
throw new UnsupportedOperationException();
}
public String updateCDN(String container, Long ttl) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public CFObject newCFObject() { public CFObject newCFObject() {
throw new UnsupportedOperationException(); return objectProvider.create(null);
} }
} }

View File

@ -0,0 +1,5 @@
[
{"name":"adriancole-blobstore.testCDNOperationsContainerWithCDN","cdn_enabled":"false","ttl":3600,"cdn_uri":"http://c0354712.cdn.cloudfiles.rackspacecloud.com,"referrer_acl":"","useragent_acl":"", "log_retention":"false"},
{"name":"adriancole-blobstore5","cdn_enabled":"true","ttl":28800,"cdn_uri":"http://c0404671.cdn.cloudfiles.rackspacecloud.com,"referrer_acl":"","useragent_acl":"", "log_retention":"false"},
{"name":"adriancole-cfcdnint.testCDNOperationsContainerWithCDN","cdn_enabled":"false","ttl":3600,"cdn_uri":"http://c0320431.cdn.cloudfiles.rackspacecloud.com,"referrer_acl":"","useragent_acl":"", "log_retention":"false"}
]

View File

@ -40,7 +40,7 @@
<module>core</module> <module>core</module>
</modules> </modules>
<properties> <properties>
<jclouds.test.initializer>org.jclouds.rackspace.cloudfiles.integration.CloudFilesTestInitializer</jclouds.test.initializer> <jclouds.test.initializer>org.jclouds.rackspace.cloudfiles.blobstore.integration.CloudFilesTestInitializer</jclouds.test.initializer>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>