Issue 97: first blobstore support for Mezeo

git-svn-id: http://jclouds.googlecode.com/svn/trunk@1939 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2009-09-30 21:11:19 +00:00
parent c2b62a0a03
commit 9cfc6b0420
60 changed files with 4713 additions and 17 deletions

View File

@ -0,0 +1,162 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2;
import java.util.List;
import java.util.concurrent.Future;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.functions.ReturnTrueOnNotFoundOr404;
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.http.options.GetOptions;
import org.jclouds.mezeo.pcs2.binders.CreateContainerBinder;
import org.jclouds.mezeo.pcs2.binders.PCSFileAsMultipartFormBinder;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.mezeo.pcs2.endpoints.RootContainer;
import org.jclouds.mezeo.pcs2.functions.AddMetadataAndParseResourceIdIntoBytes;
import org.jclouds.mezeo.pcs2.functions.AssembleBlobFromContentAndMetadataCache;
import org.jclouds.mezeo.pcs2.functions.ContainerAndFileNameToResourceId;
import org.jclouds.mezeo.pcs2.functions.ContainerNameToResourceId;
import org.jclouds.mezeo.pcs2.functions.InvalidateContainerNameCacheAndReturnTrueIf2xx;
import org.jclouds.mezeo.pcs2.functions.InvalidatePCSKeyCacheAndReturnTrueIf2xx;
import org.jclouds.mezeo.pcs2.functions.ReturnFalseIfContainerNotFound;
import org.jclouds.mezeo.pcs2.functions.ReturnTrueIfContainerAlreadyExists;
import org.jclouds.mezeo.pcs2.functions.ReturnTrueIfContainerNotFound;
import org.jclouds.mezeo.pcs2.xml.FileListToContainerMetadataListHandler;
import org.jclouds.mezeo.pcs2.xml.FileListToFileMetadataListHandler;
import org.jclouds.mezeo.pcs2.xml.FileMetadataHandler;
import org.jclouds.rest.Endpoint;
import org.jclouds.rest.EntityParam;
import org.jclouds.rest.ExceptionParser;
import org.jclouds.rest.Headers;
import org.jclouds.rest.ParamParser;
import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.ResponseParser;
import org.jclouds.rest.SkipEncoding;
import org.jclouds.rest.XMLResponseParser;
/**
* Provides access to Mezeo PCS v2 via their REST API.
* <p/>
*
* @see <a href=
* "http://developer.mezeo.com/mezeo-developer-center/documentation/howto-using-curl-to-access-api"
* />
* @author Adrian Cole
*/
@SkipEncoding('/')
@RequestFilters(BasicAuthentication.class)
public interface PCSBlobStore extends BlobStore<ContainerMetadata, FileMetadata, PCSFile> {
@GET
@XMLResponseParser(FileListToContainerMetadataListHandler.class)
@Headers(keys = "X-Cloud-Depth", values = "2")
@Path("/contents")
@Endpoint(RootContainer.class)
List<ContainerMetadata> listContainers();
@GET
@ExceptionParser(ReturnFalseIfContainerNotFound.class)
@Path("/containers/{containerResourceId}")
@Endpoint(PCS.class)
boolean containerExists(
@PathParam("containerResourceId") @ParamParser(ContainerNameToResourceId.class) String containerName);
@POST
@Path("/contents")
@Endpoint(RootContainer.class)
@ExceptionParser(ReturnTrueIfContainerAlreadyExists.class)
Future<Boolean> createContainer(@EntityParam(CreateContainerBinder.class) String container);
@DELETE
@ExceptionParser(ReturnTrueIfContainerNotFound.class)
@Path("/containers/{containerResourceId}")
@Endpoint(PCS.class)
@ResponseParser(InvalidateContainerNameCacheAndReturnTrueIf2xx.class)
Future<Boolean> deleteContainer(
@PathParam("containerResourceId") @ParamParser(ContainerNameToResourceId.class) String containerName);
@GET
@XMLResponseParser(FileListToFileMetadataListHandler.class)
@Headers(keys = "X-Cloud-Depth", values = "2")
@Path("/containers/{containerResourceId}/contents")
@Endpoint(PCS.class)
Future<? extends List<FileMetadata>> listBlobs(
@PathParam("containerResourceId") @ParamParser(ContainerNameToResourceId.class) String containerName);
@POST
@Path("/containers/{containerResourceId}/contents")
@Endpoint(PCS.class)
@ResponseParser(AddMetadataAndParseResourceIdIntoBytes.class)
Future<byte[]> putBlob(
@PathParam("containerResourceId") @ParamParser(ContainerNameToResourceId.class) String containerName,
@EntityParam(PCSFileAsMultipartFormBinder.class) PCSFile object);
@DELETE
@ExceptionParser(ReturnTrueOnNotFoundOr404.class)
@Path("/files/{resourceId}")
@PathParam("resourceId")
@Endpoint(PCS.class)
@ResponseParser(InvalidatePCSKeyCacheAndReturnTrueIf2xx.class)
@ParamParser(ContainerAndFileNameToResourceId.class)
Future<Boolean> removeBlob(String container, String key);
@GET
@ExceptionParser(ThrowKeyNotFoundOn404.class)
@Path("/files/{resourceId}/content")
@PathParam("resourceId")
@Endpoint(PCS.class)
@ParamParser(ContainerAndFileNameToResourceId.class)
@ResponseParser(AssembleBlobFromContentAndMetadataCache.class)
Future<PCSFile> getBlob(String container, String key);
@GET
@ExceptionParser(ThrowKeyNotFoundOn404.class)
@Path("/files/{resourceId}/content")
@PathParam("resourceId")
@Endpoint(PCS.class)
@ParamParser(ContainerAndFileNameToResourceId.class)
@ResponseParser(AssembleBlobFromContentAndMetadataCache.class)
Future<PCSFile> getBlob(String container, String key, GetOptions options);
@GET
@ExceptionParser(ThrowKeyNotFoundOn404.class)
@Path("/files/{resourceId}")
@PathParam("resourceId")
@Headers(keys = "X-Cloud-Depth", values = "2")
@Endpoint(PCS.class)
@ParamParser(ContainerAndFileNameToResourceId.class)
@XMLResponseParser(FileMetadataHandler.class)
FileMetadata blobMetadata(String container, String key);
}

View File

@ -0,0 +1,43 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.cloud.CloudContext;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
/**
* Represents an authenticated context to PCS.
*
* @see PCSBlobStore
* @see CloudContext
* @author Adrian Cole
*
*/
public interface PCSContext extends
BlobStoreContext<PCSBlobStore, ContainerMetadata, FileMetadata, PCSFile> {
}

View File

@ -25,34 +25,136 @@ package org.jclouds.mezeo.pcs2;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import org.jclouds.cloud.CloudContext;
import org.jclouds.cloud.CloudContextBuilder;
import org.jclouds.mezeo.pcs2.config.RestPCSCloudModule;
import org.jclouds.blobstore.BlobStoreContextBuilder;
import org.jclouds.mezeo.pcs2.config.PCSContextModule;
import org.jclouds.mezeo.pcs2.config.RestPCSBlobStoreModule;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.mezeo.pcs2.reference.PCSConstants;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/**
*
* @author Adrian Cole
*/
public abstract class PCSContextBuilder<X extends CloudContext<?>> extends CloudContextBuilder<X> {
public class PCSContextBuilder extends
BlobStoreContextBuilder<PCSBlobStore, ContainerMetadata, FileMetadata, PCSFile> {
public PCSContextBuilder(Properties props) {
super(props);
super(new TypeLiteral<PCSBlobStore>() {
}, new TypeLiteral<ContainerMetadata>() {
}, new TypeLiteral<FileMetadata>() {
}, new TypeLiteral<PCSFile>() {
}, props);
checkNotNull(properties.getProperty(PCSConstants.PROPERTY_PCS2_ENDPOINT));
}
public void authenticate(String id, String secret) {
checkNotNull(properties.getProperty(PCSConstants.PROPERTY_PCS2_ENDPOINT));
public PCSContextBuilder(URI endpoint, String id, String secret) {
this(addEndpointTo(endpoint, new Properties()));
properties.setProperty(PCSConstants.PROPERTY_PCS2_USER, checkNotNull(id, "user"));
properties.setProperty(PCSConstants.PROPERTY_PCS2_PASSWORD, checkNotNull(secret, "key"));
}
protected void addApiModule(List<Module> modules) {
modules.add(new RestPCSCloudModule());
private static Properties addEndpointTo(URI endpoint, Properties properties) {
properties.setProperty(PCSConstants.PROPERTY_PCS2_ENDPOINT,
checkNotNull(endpoint, "endpoint").toString());
return properties;
}
protected void addConnectionModule(List<Module> modules) {
modules.add(new RestPCSBlobStoreModule());
}
@Override
protected void addContextModule(List<Module> modules) {
modules.add(new PCSContextModule());
}
@Override
public PCSContextBuilder withEndpoint(URI endpoint) {
addEndpointTo(endpoint, properties);
return this;
}
// below is to cast the builder to the correct type so that chained builder methods end correctly
@Override
public PCSContext buildContext() {
Injector injector = buildInjector();
return injector.getInstance(PCSContext.class);
}
@Override
public PCSContextBuilder relaxSSLHostname() {
return (PCSContextBuilder) super.relaxSSLHostname();
}
@Override
public PCSContextBuilder withExecutorService(ExecutorService service) {
return (PCSContextBuilder) super.withExecutorService(service);
}
@Override
public PCSContextBuilder withHttpMaxRedirects(int httpMaxRedirects) {
return (PCSContextBuilder) super.withHttpMaxRedirects(httpMaxRedirects);
}
@Override
public PCSContextBuilder withHttpMaxRetries(int httpMaxRetries) {
return (PCSContextBuilder) super.withHttpMaxRetries(httpMaxRetries);
}
@Override
public PCSContextBuilder withJsonDebug() {
return (PCSContextBuilder) super.withJsonDebug();
}
@Override
public PCSContextBuilder withModule(Module module) {
return (PCSContextBuilder) super.withModule(module);
}
@Override
public PCSContextBuilder withModules(Module... modules) {
return (PCSContextBuilder) super.withModules(modules);
}
@Override
public PCSContextBuilder withPoolIoWorkerThreads(int poolIoWorkerThreads) {
return (PCSContextBuilder) super.withPoolIoWorkerThreads(poolIoWorkerThreads);
}
@Override
public PCSContextBuilder withPoolMaxConnectionReuse(int poolMaxConnectionReuse) {
return (PCSContextBuilder) super.withPoolMaxConnectionReuse(poolMaxConnectionReuse);
}
@Override
public PCSContextBuilder withPoolMaxConnections(int poolMaxConnections) {
return (PCSContextBuilder) super.withPoolMaxConnections(poolMaxConnections);
}
@Override
public PCSContextBuilder withPoolMaxSessionFailures(int poolMaxSessionFailures) {
return (PCSContextBuilder) super.withPoolMaxSessionFailures(poolMaxSessionFailures);
}
@Override
public PCSContextBuilder withPoolRequestInvokerThreads(int poolRequestInvokerThreads) {
return (PCSContextBuilder) super.withPoolRequestInvokerThreads(poolRequestInvokerThreads);
}
@Override
public PCSContextBuilder withSaxDebug() {
return (PCSContextBuilder) super.withSaxDebug();
}
}

View File

@ -0,0 +1,51 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2;
import java.net.URI;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import com.google.inject.Module;
/**
* Creates {@link PCSContext} 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
* @see PCSContext
*/
public class PCSContextFactory {
public static PCSContext createContext(URI endpoint, String user, String key, Module... modules) {
return new PCSContextBuilder(endpoint, user, key).withEndpoint(endpoint).withModules(modules)
.buildContext();
}
}

View File

@ -0,0 +1,59 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2;
import java.net.URI;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.http.functions.ReturnFalseOn404;
import org.jclouds.rest.Endpoint;
import org.jclouds.rest.EntityParam;
import org.jclouds.rest.ExceptionParser;
import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.SkipEncoding;
/**
* Provides access to Mezeo PCS v2 via their REST API.
* <p/>
*
* @see <a href=
* "http://developer.mezeo.com/mezeo-developer-center/documentation/howto-using-curl-to-access-api"
* />
* @author Adrian Cole
*/
@SkipEncoding('/')
@RequestFilters(BasicAuthentication.class)
public interface PCSUtil {
@PUT
@ExceptionParser(ReturnFalseOn404.class)
boolean put(@Endpoint URI resource, @EntityParam String value);
@GET
String get(@Endpoint URI resource);
}

View File

@ -0,0 +1,48 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.binders;
import java.util.Collections;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.binders.EntityBinder;
/**
*
* @author Adrian Cole
*
*/
public class CreateContainerBinder implements EntityBinder {
public void addEntityToRequest(Object toBind, HttpRequest request) {
String container = String.format("<container><name>%s</name></container>", toBind);
request.setEntity(container);
request.getHeaders().replaceValues(HttpHeaders.CONTENT_LENGTH,
Collections.singletonList(container.getBytes().length + ""));
request.getHeaders().replaceValues(HttpHeaders.CONTENT_TYPE,
Collections.singletonList("application/vnd.csp.container-info+xml"));
}
}

View File

@ -0,0 +1,88 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.binders;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.MultipartForm;
import org.jclouds.http.MultipartForm.Part;
import org.jclouds.rest.binders.EntityBinder;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
/**
*
* @author Adrian Cole
*/
public class PCSFileAsMultipartFormBinder implements EntityBinder {
public static final String BOUNDARY = "--PCS--";
public void addEntityToRequest(Object entity, HttpRequest request) {
Blob<?> object = (Blob<?>) entity;
Multimap<String, String> partHeaders = ImmutableMultimap.of("Content-Disposition",
String.format("form-data; name=\"%s\"; filename=\"%s\"", object.getKey(), object
.getKey()), HttpHeaders.CONTENT_TYPE, checkNotNull(object.getMetadata()
.getContentType(), "object.metadata.contentType()"));
Object data = checkNotNull(object.getData(), "object.getData()");
Part part;
try {
if (data instanceof byte[]) {
part = new Part(partHeaders, (byte[]) data);
} else if (data instanceof String) {
part = new Part(partHeaders, (String) data);
} else if (data instanceof File) {
part = new Part(partHeaders, (File) data);
} else if (data instanceof InputStream) {
part = new Part(partHeaders, (InputStream) data, object.getContentLength());
} else {
throw new IllegalArgumentException("type of part not supported: "
+ data.getClass().getCanonicalName() + "; " + object);
}
} catch (FileNotFoundException e) {
throw new IllegalArgumentException("file for part not found: " + object);
}
MultipartForm form = new MultipartForm(BOUNDARY, part);
request.setEntity(form.getData());
request.getHeaders().put(HttpHeaders.CONTENT_TYPE,
"multipart/form-data; boundary=" + BOUNDARY);
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, form.getSize() + "");
}
}

View File

@ -0,0 +1,104 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.config;
import java.net.URI;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.blobstore.BlobStoreContextImpl;
import org.jclouds.blobstore.BlobMap.Factory;
import org.jclouds.lifecycle.Closer;
import org.jclouds.mezeo.pcs2.PCS;
import org.jclouds.mezeo.pcs2.PCSBlobStore;
import org.jclouds.mezeo.pcs2.PCSContext;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.mezeo.pcs2.functions.FindIdInContainerList;
import org.jclouds.mezeo.pcs2.functions.FindIdInFileList;
import org.jclouds.mezeo.pcs2.functions.Key;
import org.jclouds.mezeo.pcs2.reference.PCSConstants;
import com.google.common.base.Function;
import com.google.common.collect.MapMaker;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Scopes;
/**
* Configures the PCS connection, including logging and http transport.
*
* @author Adrian Cole
*/
public class PCSContextModule extends AbstractModule {
@Override
protected void configure() {
bind(PCSContext.class).to(PCSContextImpl.class).in(Scopes.SINGLETON);
}
public static class PCSContextImpl extends
BlobStoreContextImpl<PCSBlobStore, ContainerMetadata, FileMetadata, PCSFile> implements
PCSContext {
@Inject
PCSContextImpl(Factory<FileMetadata, PCSFile> blobMapFactory,
org.jclouds.blobstore.InputStreamMap.Factory<FileMetadata> inputStreamMapFactory,
Closer closer, Provider<PCSFile> blobProvider, PCSBlobStore defaultApi,
@PCS URI endPoint, @Named(PCSConstants.PROPERTY_PCS2_USER) String account) {
super(blobMapFactory, inputStreamMapFactory, closer, blobProvider, defaultApi, endPoint,
account);
}
}
@Provides
@Singleton
public ConcurrentMap<Key, String> provideConcurrentMap(FindIdInFileList finder) {
return new MapMaker().expiration(30, TimeUnit.SECONDS).makeComputingMap(finder);
}
@Provides
@Singleton
public ConcurrentMap<String, String> provideConcurrentMap(FindIdInContainerList finder) {
return new MapMaker().concurrencyLevel(32).expiration(30, TimeUnit.SECONDS).makeComputingMap(
finder);
}
@Provides
@Singleton
public ConcurrentMap<Key, FileMetadata> provideConcurrentMap(final PCSBlobStore connection) {
return new MapMaker().expiration(30, TimeUnit.SECONDS).makeComputingMap(
new Function<Key, FileMetadata>() {
public FileMetadata apply(Key from) {
return connection.blobMetadata(from.getContainer(), from.getKey());
}
});
}
}

View File

@ -23,14 +23,22 @@
*/
package org.jclouds.mezeo.pcs2.config;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.cloud.ConfiguresCloudConnection;
import org.jclouds.concurrent.SingleThreaded;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.mezeo.pcs2.PCS;
import org.jclouds.mezeo.pcs2.PCSBlobStore;
import org.jclouds.mezeo.pcs2.PCSCloud;
import org.jclouds.mezeo.pcs2.PCSUtil;
import org.jclouds.mezeo.pcs2.PCSCloud.Response;
import org.jclouds.mezeo.pcs2.endpoints.Contacts;
import org.jclouds.mezeo.pcs2.endpoints.Metacontainers;
@ -39,9 +47,9 @@ import org.jclouds.mezeo.pcs2.endpoints.Recyclebin;
import org.jclouds.mezeo.pcs2.endpoints.RootContainer;
import org.jclouds.mezeo.pcs2.endpoints.Shares;
import org.jclouds.mezeo.pcs2.endpoints.Tags;
import org.jclouds.mezeo.pcs2.handlers.PCSClientErrorRetryHandler;
import org.jclouds.mezeo.pcs2.reference.PCSConstants;
import org.jclouds.rest.RestClientFactory;
import org.jclouds.rest.config.JaxrsModule;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
@ -52,21 +60,44 @@ import com.google.inject.Provides;
* @author Adrian Cole
*/
@RequiresHttp
public class RestPCSCloudModule extends AbstractModule {
@ConfiguresCloudConnection
@SingleThreaded
// http://code.google.com/p/jclouds/issues/detail?id=104
public class RestPCSBlobStoreModule extends AbstractModule {
@Override
protected void configure() {
install(new JaxrsModule());
bindErrorHandlers();
bindRetryHandlers();
}
@Provides
@Singleton
public BasicAuthentication provideBasicAuthentication(
@Named(PCSConstants.PROPERTY_PCS2_USER) String user,
@Named(PCSConstants.PROPERTY_PCS2_PASSWORD) String password)
throws UnsupportedEncodingException {
return new BasicAuthentication(user, password);
}
@Provides
@Singleton
protected Response provideCloudResponse(RestClientFactory factory, @PCS URI authenticationUri) {
return factory.create(PCSCloud.class).authenticate();
}
@Provides
@Singleton
protected PCSBlobStore provideConnection(RestClientFactory factory) {
return factory.create(PCSBlobStore.class);
}
@Provides
@Singleton
protected PCSUtil providePCSUtil(RestClientFactory factory) {
return factory.create(PCSUtil.class);
}
@Provides
@Singleton
@PCS
@ -129,7 +160,8 @@ public class RestPCSCloudModule extends AbstractModule {
}
protected void bindRetryHandlers() {
// TODO retry on 401 by AuthenticateRequest.update()
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(
PCSClientErrorRetryHandler.class);
}
}

View File

@ -0,0 +1,171 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.domain;
import java.net.URI;
import org.joda.time.DateTime;
/**
*
* @author Adrian Cole
*
*/
public class ContainerMetadata extends org.jclouds.blobstore.domain.ContainerMetadata implements
PCSObject {
private URI url;
private DateTime created;
private DateTime lastModified;
private DateTime accessed;
private String owner;
private boolean isShared;
private boolean isInProject;
private int version;
private long bytes;
@Override
public String toString() {
return "ContainerMetadata [name=" + name + ", url=" + url + ", accessed=" + accessed
+ ", bytes=" + bytes + ", created=" + created + ", isInProject=" + isInProject
+ ", isShared=" + isShared + ", lastModified=" + lastModified + ", owner=" + owner
+ ", version=" + version + "]";
}
@Override
public int hashCode() {
int prime = 31;
int result = super.hashCode();
result = prime * result + ((accessed == null) ? 0 : accessed.hashCode());
result = prime * result + (int) (bytes ^ (bytes >>> 32));
result = prime * result + ((created == null) ? 0 : created.hashCode());
result = prime * result + (isInProject ? 1231 : 1237);
result = prime * result + (isShared ? 1231 : 1237);
result = prime * result + ((lastModified == null) ? 0 : lastModified.hashCode());
result = prime * result + ((owner == null) ? 0 : owner.hashCode());
result = prime * result + ((url == null) ? 0 : url.hashCode());
result = prime * result + version;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
ContainerMetadata other = (ContainerMetadata) obj;
if (accessed == null) {
if (other.accessed != null)
return false;
} else if (!accessed.equals(other.accessed))
return false;
if (bytes != other.bytes)
return false;
if (created == null) {
if (other.created != null)
return false;
} else if (!created.equals(other.created))
return false;
if (isInProject != other.isInProject)
return false;
if (isShared != other.isShared)
return false;
if (lastModified == null) {
if (other.lastModified != null)
return false;
} else if (!lastModified.equals(other.lastModified))
return false;
if (owner == null) {
if (other.owner != null)
return false;
} else if (!owner.equals(other.owner))
return false;
if (url == null) {
if (other.url != null)
return false;
} else if (!url.equals(other.url))
return false;
if (version != other.version)
return false;
return true;
}
public ContainerMetadata() {
super();
}
public ContainerMetadata(String name, URI url, DateTime created, DateTime lastModified,
DateTime accessed, String owner, boolean isShared, boolean isInProject, int version,
long bytes) {
super(name);
this.url = url;
this.created = created;
this.lastModified = lastModified;
this.accessed = accessed;
this.owner = owner;
this.isShared = isShared;
this.isInProject = isInProject;
this.version = version;
this.bytes = bytes;
}
public URI getUrl() {
return url;
}
public DateTime getCreated() {
return created;
}
public DateTime getLastModified() {
return lastModified;
}
public DateTime getAccessed() {
return accessed;
}
public String getOwner() {
return owner;
}
public boolean isShared() {
return isShared;
}
public boolean isInProject() {
return isInProject;
}
public int getVersion() {
return version;
}
public long getSize() {
return bytes;
}
}

View File

@ -0,0 +1,189 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.domain;
import java.net.URI;
import java.util.Arrays;
import org.jclouds.mezeo.pcs2.util.PCSUtils;
import org.joda.time.DateTime;
/**
*
* @author Adrian Cole
*
*/
public class FileMetadata extends org.jclouds.blobstore.domain.BlobMetadata {
/** The serialVersionUID */
private static final long serialVersionUID = 1L;
private URI url;
private DateTime created;
private DateTime accessed;
private String owner;
private Boolean isShared;
private Boolean isInProject;
private Integer version;
private Boolean isPublic;
@Override
public String toString() {
return "FileMetadata [key=" + key + ", created=" + created + ", isInProject=" + isInProject
+ ", isPublic=" + isPublic + ", isShared=" + isShared + ", owner=" + owner
+ ", url=" + url + ", version=" + version + ", allHeaders=" + allHeaders
+ ", dataType=" + dataType + ", eTag=" + Arrays.toString(eTag) + ", accessed="
+ accessed + ", lastModified=" + lastModified + ", size=" + size + ", userMetadata="
+ userMetadata + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((accessed == null) ? 0 : accessed.hashCode());
result = prime * result + ((created == null) ? 0 : created.hashCode());
result = prime * result + ((isInProject == null) ? 0 : isInProject.hashCode());
result = prime * result + ((isPublic == null) ? 0 : isPublic.hashCode());
result = prime * result + ((isShared == null) ? 0 : isShared.hashCode());
result = prime * result + ((owner == null) ? 0 : owner.hashCode());
result = prime * result + ((url == null) ? 0 : url.hashCode());
result = prime * result + ((version == null) ? 0 : version.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
FileMetadata other = (FileMetadata) obj;
if (accessed == null) {
if (other.accessed != null)
return false;
} else if (!accessed.equals(other.accessed))
return false;
if (created == null) {
if (other.created != null)
return false;
} else if (!created.equals(other.created))
return false;
if (isInProject == null) {
if (other.isInProject != null)
return false;
} else if (!isInProject.equals(other.isInProject))
return false;
if (isPublic == null) {
if (other.isPublic != null)
return false;
} else if (!isPublic.equals(other.isPublic))
return false;
if (isShared == null) {
if (other.isShared != null)
return false;
} else if (!isShared.equals(other.isShared))
return false;
if (owner == null) {
if (other.owner != null)
return false;
} else if (!owner.equals(other.owner))
return false;
if (url == null) {
if (other.url != null)
return false;
} else if (!url.equals(other.url))
return false;
if (version == null) {
if (other.version != null)
return false;
} else if (!version.equals(other.version))
return false;
return true;
}
public FileMetadata(String name, URI url, DateTime created, DateTime lastModified,
DateTime accessed, String owner, boolean isShared, boolean isInProject, int version,
long bytes, String contentType, boolean isPublic) {
super(name);
setLastModified(lastModified);
setSize(bytes);
setContentType(contentType);
this.url = url;
this.created = created;
this.accessed = accessed;
this.owner = owner;
this.isShared = isShared;
this.isInProject = isInProject;
this.version = version;
this.isPublic = isPublic;
byte[] eTag = PCSUtils.getEtag(url);
setETag(eTag);
}
public FileMetadata(String key) {
super(key);
}
public FileMetadata() {
super();
}
public URI getUrl() {
return url;
}
public DateTime getCreated() {
return created;
}
public DateTime getLastModified() {
return lastModified;
}
public DateTime getAccessed() {
return accessed;
}
public String getOwner() {
return owner;
}
public Boolean isShared() {
return isShared;
}
public Boolean isInProject() {
return isInProject;
}
public Integer getVersion() {
return version;
}
public Boolean isPublic() {
return isPublic;
}
}

View File

@ -0,0 +1,51 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.domain;
/**
* @author Adrian Cole
*/
public class PCSFile extends org.jclouds.blobstore.domain.Blob<FileMetadata> {
public PCSFile(FileMetadata metadata, FileMetadata data) {
super(metadata, data);
}
public PCSFile(FileMetadata metadata) {
super(metadata);
}
public PCSFile(String key, FileMetadata data) {
this(new FileMetadata(key), data);
}
public PCSFile(String key) {
this(new FileMetadata(key));
}
public PCSFile() {
this(new FileMetadata());
}
}

View File

@ -0,0 +1,57 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.domain;
import java.net.URI;
import org.joda.time.DateTime;
/**
*
* @author Adrian Cole
*
*/
public interface PCSObject {
URI getUrl();
String getName();
DateTime getCreated();
DateTime getLastModified();
DateTime getAccessed();
String getOwner();
boolean isShared();
boolean isInProject();
int getVersion();
long getSize();
}

View File

@ -0,0 +1,104 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.functions;
import static com.google.common.base.Preconditions.checkState;
import java.io.IOException;
import java.net.URI;
import java.util.Map.Entry;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException;
import org.jclouds.logging.Logger;
import org.jclouds.mezeo.pcs2.PCSUtil;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.mezeo.pcs2.util.PCSUtils;
import org.jclouds.rest.RestContext;
import org.jclouds.util.Utils;
import com.google.common.base.Function;
/**
* PCS does not return an eTag header. As such, we'll make one out of the object id.
*
* @author Adrian Cole
*/
public class AddMetadataAndParseResourceIdIntoBytes implements Function<HttpResponse, byte[]>,
RestContext {
private final PCSUtil util;
@Resource
protected Logger logger = Logger.NULL;
private Object[] args;
private HttpRequest request;
@Inject
public AddMetadataAndParseResourceIdIntoBytes(PCSUtil util) {
this.util = util;
}
public byte[] apply(HttpResponse from) {
checkState(args != null, "args should be initialized at this point");
PCSFile file = null;
for (Object arg : args) {
if (arg instanceof PCSFile)
file = (PCSFile) arg;
}
checkState(file != null, "No PCSFile found in args, improper method declarations");
checkState(request != null, "request should be initialized at this point");
try {
String toParse = Utils.toStringAndClose(from.getContent());
logger.trace("%s: received the following response: %s", from, toParse);
URI uri = URI.create(toParse.trim());
for (Entry<String, String> entry : file.getMetadata().getUserMetadata().entries()) {
URI key = UriBuilder.fromUri(uri).path(String.format("metadata/%s", entry.getKey()))
.build();
util.put(key, entry.getValue());
}
return PCSUtils.getEtag(uri);
} catch (IOException e) {
throw new HttpResponseException("couldn't parse url from response", null, from, e);
}
}
public Object[] getArgs() {
return args;
}
public HttpRequest getRequest() {
return request;
}
public void setContext(HttpRequest request, Object[] args) {
this.request = request;
this.args = args;
}
}

View File

@ -0,0 +1,78 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.functions;
import java.util.concurrent.ConcurrentMap;
import javax.inject.Inject;
import org.jclouds.blobstore.functions.ParseContentTypeFromHeaders;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.rest.RestContext;
import com.google.common.base.Function;
/**
* Parses response headers and creates a new PCSFile from them and the HTTP content.
*
* @see ParseContentTypeFromHeaders
* @author Adrian Cole
*/
public class AssembleBlobFromContentAndMetadataCache implements Function<HttpResponse, PCSFile>,
RestContext {
private final ConcurrentMap<Key, FileMetadata> cache;
private HttpRequest request;
private Object[] args;
@Inject
public AssembleBlobFromContentAndMetadataCache(ConcurrentMap<Key, FileMetadata> cache) {
this.cache = cache;
}
public PCSFile apply(HttpResponse from) {
FileMetadata metadata = cache.get(new Key(getArgs()[0].toString(), this.getArgs()[1].toString()));
PCSFile blob = new PCSFile(metadata);
blob.setData(from.getContent());
blob.setContentLength(metadata.getSize());
return blob;
}
public Object[] getArgs() {
return args;
}
public HttpRequest getRequest() {
return request;
}
public void setContext(HttpRequest request, Object[] args) {
this.args = args;
this.request = request;
}
}

View File

@ -0,0 +1,74 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.functions;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.util.concurrent.ConcurrentMap;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.util.Utils;
import com.google.common.base.Function;
import com.google.common.collect.ComputationException;
/**
*
* @author Adrian Cole
*/
@Singleton
public class ContainerAndFileNameToResourceId implements Function<Object, String> {
private ConcurrentMap<Key, String> cachedFinder;
@Inject
public ContainerAndFileNameToResourceId(ConcurrentMap<Key, String> cachedFinder) {
this.cachedFinder = cachedFinder;
}
public String apply(Object from) {
checkState(checkNotNull(from, "args") instanceof Object[],
"this must be applied to a method!");
Object[] args = (Object[]) from;
checkArgument(args[0] instanceof String, "arg[0] must be a container name");
checkArgument(args[1] instanceof String, "arg[1] must be a pcsfile name (key)");
String container = args[0].toString();
String key = args[1].toString();
try {
return cachedFinder.get(new Key(container, key));
} catch (ComputationException e) {
Utils.<ContainerNotFoundException> rethrowIfRuntimeOrSameType(e);
Utils.<KeyNotFoundException> rethrowIfRuntimeOrSameType(e);
throw e;
}
}
}

View File

@ -0,0 +1,63 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.concurrent.ConcurrentMap;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.util.Utils;
import com.google.common.base.Function;
import com.google.common.collect.ComputationException;
/**
*
* @author Adrian Cole
*/
@Singleton
public class ContainerNameToResourceId implements Function<Object, String> {
private final ConcurrentMap<String, String> finder;
@Inject
public ContainerNameToResourceId(ConcurrentMap<String, String> finder) {
this.finder = finder;
}
public String apply(Object from) {
String toFind = checkNotNull(from, "name").toString();
try {
return finder.get(toFind);
} catch (ComputationException e) {
Utils.<ContainerNotFoundException> rethrowIfRuntimeOrSameType(e);
throw e;
}
}
}

View File

@ -0,0 +1,39 @@
package org.jclouds.mezeo.pcs2.functions;
import java.util.List;
import javax.inject.Inject;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.mezeo.pcs2.PCSBlobStore;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
public class FindIdInContainerList implements Function<String, String> {
private PCSBlobStore connection;
@Inject
public FindIdInContainerList(PCSBlobStore connection) {
this.connection = connection;
}
public String apply(String key) {
List<ContainerMetadata> response = connection.listContainers();
return idForNameInListOrException(key, response);
}
@VisibleForTesting
String idForNameInListOrException(String toFind, List<ContainerMetadata> containerMetadataList) {
for (ContainerMetadata data : containerMetadataList) {
if (toFind.equals(data.getName())) {
String path = data.getUrl().getPath();
int indexAfterContainersSlash = path.indexOf("containers/") + "containers/".length();
return path.substring(indexAfterContainersSlash);
}
}
throw new ContainerNotFoundException(toFind);
}
}

View File

@ -0,0 +1,50 @@
package org.jclouds.mezeo.pcs2.functions;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.http.HttpException;
import org.jclouds.mezeo.pcs2.PCSBlobStore;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.util.Utils;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
public class FindIdInFileList implements Function<Key, String> {
private PCSBlobStore connection;
@Inject
public FindIdInFileList(PCSBlobStore connection) {
this.connection = connection;
}
public String apply(Key key) {
List<FileMetadata> response;
try {
response = connection.listBlobs(key.getContainer()).get(10, TimeUnit.SECONDS);
} catch (Exception e) {
Utils.<ContainerNotFoundException> rethrowIfRuntimeOrSameType(e);
throw new HttpException("could not list blobs for " + Arrays.asList(key.getContainer()), e);
}
return idForNameInListOrException(key.getContainer(), key.getKey(), response);
}
@VisibleForTesting
String idForNameInListOrException(String container, String toFind, List<FileMetadata> response) {
for (FileMetadata data : response) {
if (toFind.equals(data.getKey())) {
String path = data.getUrl().getPath();
int indexAfterContainersSlash = path.indexOf("files/") + "files/".length();
return path.substring(indexAfterContainersSlash);
}
}
throw new KeyNotFoundException(container, toFind);
}
}

View File

@ -0,0 +1,53 @@
package org.jclouds.mezeo.pcs2.functions;
import java.util.concurrent.ConcurrentMap;
import javax.inject.Inject;
import org.apache.commons.io.IOUtils;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.rest.RestContext;
import com.google.common.base.Function;
/**
* invalidates cache and returns true when the http response code is in the range 200-299.
*
* @author Adrian Cole
*/
public class InvalidateContainerNameCacheAndReturnTrueIf2xx implements Function<HttpResponse, Boolean>,
RestContext {
private final ConcurrentMap<String, String> cache;
private HttpRequest request;
private Object[] args;
@Inject
public InvalidateContainerNameCacheAndReturnTrueIf2xx(ConcurrentMap<String, String> cache) {
this.cache = cache;
}
public Boolean apply(HttpResponse from) {
IOUtils.closeQuietly(from.getContent());
int code = from.getStatusCode();
if (code >= 300 || code < 200) {
throw new IllegalStateException("incorrect code for this operation: " + from);
}
cache.remove(getArgs()[0]);
return true;
}
public Object[] getArgs() {
return args;
}
public HttpRequest getRequest() {
return request;
}
public void setContext(HttpRequest request, Object[] args) {
this.args = args;
this.request = request;
}
}

View File

@ -0,0 +1,59 @@
package org.jclouds.mezeo.pcs2.functions;
import java.util.concurrent.ConcurrentMap;
import javax.inject.Inject;
import org.apache.commons.io.IOUtils;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.rest.RestContext;
import com.google.common.base.Function;
/**
* invalidates cache and returns true when the http response code is in the range 200-299.
*
* @author Adrian Cole
*/
public class InvalidatePCSKeyCacheAndReturnTrueIf2xx implements Function<HttpResponse, Boolean>,
RestContext {
private final ConcurrentMap<Key, String> cache;
private final ConcurrentMap<Key, FileMetadata> mdCache;
private HttpRequest request;
private Object[] args;
@Inject
public InvalidatePCSKeyCacheAndReturnTrueIf2xx(ConcurrentMap<Key, String> cache,
ConcurrentMap<Key, FileMetadata> mdCache) {
this.cache = cache;
this.mdCache = mdCache;
}
public Boolean apply(HttpResponse from) {
IOUtils.closeQuietly(from.getContent());
int code = from.getStatusCode();
if (code >= 300 || code < 200) {
throw new IllegalStateException("incorrect code for this operation: " + from);
}
Key key = new Key(getArgs()[0].toString(), getArgs()[1].toString());
cache.remove(key);
mdCache.remove(key);
return true;
}
public Object[] getArgs() {
return args;
}
public HttpRequest getRequest() {
return request;
}
public void setContext(HttpRequest request, Object[] args) {
this.args = args;
this.request = request;
}
}

View File

@ -0,0 +1,51 @@
package org.jclouds.mezeo.pcs2.functions;
public class Key {
private final String container;
private final String key;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((getContainer() == null) ? 0 : getContainer().hashCode());
result = prime * result + ((getKey() == null) ? 0 : getKey().hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Key other = (Key) obj;
if (getContainer() == null) {
if (other.getContainer() != null)
return false;
} else if (!getContainer().equals(other.getContainer()))
return false;
if (getKey() == null) {
if (other.getKey() != null)
return false;
} else if (!getKey().equals(other.getKey()))
return false;
return true;
}
public Key(String container, String key) {
super();
this.container = container;
this.key = key;
}
public String getContainer() {
return container;
}
public String getKey() {
return key;
}
}

View File

@ -0,0 +1,43 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.functions;
import org.jclouds.blobstore.ContainerNotFoundException;
import com.google.common.base.Function;
/**
*
* @author Adrian Cole
*/
public class ReturnFalseIfContainerNotFound implements Function<Exception, Boolean> {
public Boolean apply(Exception from) {
if (from instanceof ContainerNotFoundException) {
return false;
}
return null;
}
}

View File

@ -0,0 +1,46 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.functions;
import org.jclouds.http.HttpResponseException;
import com.google.common.base.Function;
/**
*
* @author Adrian Cole
*/
public class ReturnTrueIfContainerAlreadyExists implements Function<Exception, Boolean> {
public Boolean apply(Exception from) {
if (from instanceof HttpResponseException) {
HttpResponseException responseException = (HttpResponseException) from;
if ("The directory already exists.".equals(responseException.getContent())) {
return true;
}
}
return null;
}
}

View File

@ -0,0 +1,43 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.functions;
import org.jclouds.blobstore.ContainerNotFoundException;
import com.google.common.base.Function;
/**
*
* @author Adrian Cole
*/
public class ReturnTrueIfContainerNotFound implements Function<Exception, Boolean> {
public Boolean apply(Exception from) {
if (from instanceof ContainerNotFoundException) {
return true;
}
return null;
}
}

View File

@ -0,0 +1,36 @@
package org.jclouds.mezeo.pcs2.handlers;
import javax.annotation.Resource;
import javax.inject.Inject;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
import org.jclouds.logging.Logger;
/**
* Handles Retryable responses with error codes in the 4xx range
*
* @author Adrian Cole
*/
public class PCSClientErrorRetryHandler implements HttpRetryHandler {
private final BackoffLimitedRetryHandler backoffHandler;
@Inject
public PCSClientErrorRetryHandler(BackoffLimitedRetryHandler backoffHandler) {
this.backoffHandler = backoffHandler;
}
@Resource
protected Logger logger = Logger.NULL;
public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
if (response.getStatusCode() == 400) {
return backoffHandler.shouldRetryRequest(command, response);
}
return false;
}
}

View File

@ -0,0 +1,47 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.util;
import java.net.URI;
import org.jclouds.http.HttpUtils;
/**
* Utilities for PCS connections.
*
* @author Adrian Cole
*/
public class PCSUtils {
/**
* converts the object id into something we can use as an etag
*/
public static byte[] getEtag(URI url) {
String id = url.getPath().substring(url.getPath().lastIndexOf('/') + 1);
id = id.replaceAll("-", "");
// parse url to create an "etag"
byte[] eTag = HttpUtils.fromHexString(id);
return eTag;
}
}

View File

@ -0,0 +1,112 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.xml;
import java.net.URI;
import javax.inject.Inject;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.util.DateService;
import org.joda.time.DateTime;
/**
* @author Adrian Cole
*/
public abstract class BaseFileMetadataHandler<T> extends ParseSax.HandlerWithResult<T> {
protected URI currentUrl;
private String currentName;
private DateTime currentCreated;
private boolean currentInproject;
private DateTime currentModified;
private String currentOwner;
private int currentVersion;
private boolean currentShared;
private DateTime currentAccessed;
private long currentBytes;
private String currentMimeType;
private boolean currentPublic;
protected StringBuilder currentText = new StringBuilder();
private final DateService dateParser;
@Inject
public BaseFileMetadataHandler(DateService dateParser) {
this.dateParser = dateParser;
}
@Override
public void endElement(String uri, String name, String qName) {
if (qName.equals("name")) {
currentName = currentText.toString().trim();
} else if (qName.equals("created")) {
currentCreated = dateParser.fromSeconds(Long.parseLong(currentText.toString().trim()));
} else if (qName.equals("inproject")) {
currentInproject = Boolean.parseBoolean(currentText.toString().trim());
} else if (qName.equals("modified")) {
currentModified = dateParser.fromSeconds(Long.parseLong(currentText.toString().trim()));
} else if (qName.equals("owner")) {
currentOwner = currentText.toString().trim();
} else if (qName.equals("version")) {
currentVersion = Integer.parseInt(currentText.toString().trim());
} else if (qName.equals("shared")) {
currentShared = Boolean.parseBoolean(currentText.toString().trim());
} else if (qName.equals("accessed")) {
currentAccessed = dateParser.fromSeconds(Long.parseLong(currentText.toString().trim()));
} else if (qName.equals("bytes")) {
currentBytes = Long.parseLong(currentText.toString().trim());
} else if (qName.equals("mime_type")) {
currentMimeType = currentText.toString().trim();
} else if (qName.equals("public")) {
currentPublic = Boolean.parseBoolean(currentText.toString().trim());
} else if (qName.equals("file")) {
FileMetadata metadata = new FileMetadata(currentName, currentUrl, currentCreated,
currentModified, currentAccessed, currentOwner, currentShared, currentInproject,
currentVersion, currentBytes, currentMimeType, currentPublic);
addFileMetadata(metadata);
currentUrl = null;
currentName = null;
currentCreated = null;
currentInproject = false;
currentModified = null;
currentOwner = null;
currentVersion = 0;
currentShared = false;
currentAccessed = null;
currentBytes = 0;
currentMimeType = null;
currentPublic = false;
}
currentText = new StringBuilder();
}
protected abstract void addFileMetadata(FileMetadata metadata);
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,123 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.xml;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.util.DateService;
import org.joda.time.DateTime;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/**
* @author Adrian Cole
*/
public class FileListToContainerMetadataListHandler extends
ParseSax.HandlerWithResult<List<ContainerMetadata>> {
private List<ContainerMetadata> containerMetadata = new ArrayList<ContainerMetadata>();
private URI currentUrl;
private String currentName;
private DateTime currentCreated;
private boolean currentInproject;
private DateTime currentModified;
private String currentOwner;
private int currentVersion;
private boolean currentShared;
private DateTime currentAccessed;
private long currentBytes;
private StringBuilder currentText = new StringBuilder();
private final DateService dateParser;
@Inject
public FileListToContainerMetadataListHandler(DateService dateParser) {
this.dateParser = dateParser;
}
public List<ContainerMetadata> getResult() {
return containerMetadata;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (qName.equals("container")) {
int index = attributes.getIndex("xlink:href");
if (index != -1) {
currentUrl = URI.create(attributes.getValue(index));
}
}
}
@Override
public void endElement(String uri, String name, String qName) {
if (qName.equals("name")) {
currentName = currentText.toString().trim();
} else if (qName.equals("created")) {
currentCreated = dateParser.fromSeconds(Long.parseLong(currentText.toString().trim()));
} else if (qName.equals("inproject")) {
currentInproject = Boolean.parseBoolean(currentText.toString().trim());
} else if (qName.equals("modified")) {
currentModified = dateParser.fromSeconds(Long.parseLong(currentText.toString().trim()));
} else if (qName.equals("owner")) {
currentOwner = currentText.toString().trim();
} else if (qName.equals("version")) {
currentVersion = Integer.parseInt(currentText.toString().trim());
} else if (qName.equals("shared")) {
currentShared = Boolean.parseBoolean(currentText.toString().trim());
} else if (qName.equals("accessed")) {
currentAccessed = dateParser.fromSeconds(Long.parseLong(currentText.toString().trim()));
} else if (qName.equals("bytes")) {
currentBytes = Long.parseLong(currentText.toString().trim());
} else if (qName.equals("container")) {
containerMetadata.add(new ContainerMetadata(currentName, currentUrl, currentCreated,
currentModified, currentAccessed, currentOwner, currentShared, currentInproject,
currentVersion, currentBytes));
currentUrl = null;
currentName = null;
currentCreated = null;
currentInproject = false;
currentModified = null;
currentOwner = null;
currentVersion = 0;
currentShared = false;
currentAccessed = null;
currentBytes = 0;
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,68 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.xml;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.util.DateService;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/**
* @author Adrian Cole
*/
public class FileListToFileMetadataListHandler extends
BaseFileMetadataHandler<List<FileMetadata>> {
private List<FileMetadata> containerMetadata = new ArrayList<FileMetadata>();
@Inject
public FileListToFileMetadataListHandler(DateService dateParser) {
super(dateParser);
}
public List<FileMetadata> getResult() {
return containerMetadata;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (qName.equals("file")) {
int index = attributes.getIndex("xlink:href");
if (index != -1) {
currentUrl = URI.create(attributes.getValue(index));
}
}
}
protected void addFileMetadata(FileMetadata metadata) {
containerMetadata.add(metadata);
}
}

View File

@ -0,0 +1,79 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.xml;
import java.net.URI;
import javax.inject.Inject;
import org.jclouds.mezeo.pcs2.PCSUtil;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.util.DateService;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
/**
* @author Adrian Cole
*/
public class FileMetadataHandler extends BaseFileMetadataHandler<FileMetadata> {
private final PCSUtil util;
private FileMetadata fileMetadata = null;
protected Multimap<String, String> userMetadata = HashMultimap.create();
@Inject
public FileMetadataHandler(PCSUtil util, DateService dateParser) {
super(dateParser);
this.util = util;
}
public FileMetadata getResult() {
return fileMetadata;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (qName.equals("content")) {
int index = attributes.getIndex("xlink:href");
if (index != -1) {
currentUrl = URI.create(attributes.getValue(index).replaceAll("/content", ""));
}
} else if (qName.equals("metadata-item")) {
int index = attributes.getIndex("xlink:href");
if (index != -1) {
String key = attributes.getValue(index).replaceAll(".*/metadata/", "");
String value = util.get(URI.create(attributes.getValue(index))).trim();
userMetadata.put(key.toLowerCase(), value);
}
}
}
protected void addFileMetadata(FileMetadata metadata) {
this.fileMetadata = metadata;
this.fileMetadata.setUserMetadata(userMetadata);
}
}

View File

@ -0,0 +1,203 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.io.InputStream;
import java.net.URI;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.blobstore.integration.internal.BaseBlobStoreIntegrationTest;
import org.jclouds.http.HttpResponseException;
import org.jclouds.http.HttpUtils;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.collect.Iterables;
/**
* Tests behavior of {@code PCSDiscovery}
*
* @author Adrian Cole
*/
@Test(groups = "live", testName = "pcs2.PCSConnectionLiveTest")
public class PCSBlobStoreLiveTest {
private PCSBlobStore connection;
@BeforeGroups(groups = { "live" })
public void setupConnection() {
String user = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user");
String password = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key");
URI endpoint = URI.create(checkNotNull(System.getProperty("jclouds.test.endpoint"),
"jclouds.test.endpoint"));
connection = PCSContextFactory.createContext(endpoint, user, password,
new Log4JLoggingModule()).getApi();
}
private String containerPrefix = BaseBlobStoreIntegrationTest.CONTAINER_PREFIX;
@Test
public void testListContainers() throws Exception {
List<ContainerMetadata> response = connection.listContainers();
assertNotNull(response);
long initialContainerCount = response.size();
assertTrue(initialContainerCount >= 0);
// Create test containers
String[] containerJsr330 = new String[] { containerPrefix + ".testListOwnedContainers1",
containerPrefix + ".testListOwnedContainers2" };
assertTrue(connection.createContainer(containerJsr330[0]).get(10, TimeUnit.SECONDS));
assertTrue(connection.createContainer(containerJsr330[1]).get(10, TimeUnit.SECONDS));
assertTrue(connection.containerExists(containerJsr330[1]));
// Test default listing
response = connection.listContainers();
// Map<String, String> nameToId = Maps.newHashMap();
//
// for (ContainerMetadata data : response) {
// String path = data.getUrl().getPath();
// int indexAfterContainersSlash = path.indexOf("containers/") + "containers/".length();
// String id = path.substring(indexAfterContainersSlash);
// nameToId.put(data.getName(), id);
// }
// assert nameToId.size() >= 2 : nameToId;
// assertEquals(response.size(), initialContainerCount + 2);// if the containers already
// exist, this will fail
// Cleanup and test containers have been removed
// assertTrue(connection.deleteContainer(nameToId.get(containerJsr330[0])).get(10,
// TimeUnit.SECONDS));
// assertTrue(connection.deleteContainer(nameToId.get(containerJsr330[1])).get(10,
// TimeUnit.SECONDS));
connection.listBlobs(containerJsr330[0]).get(10, TimeUnit.SECONDS);
connection.listBlobs(containerJsr330[1]).get(10, TimeUnit.SECONDS);
assertTrue(connection.deleteContainer(containerJsr330[0]).get(10, TimeUnit.SECONDS));
assertTrue(connection.deleteContainer(containerJsr330[1]).get(10, TimeUnit.SECONDS));
assertTrue(!connection.containerExists(containerJsr330[0]));
response = connection.listContainers();
// assertEquals(response.size(), initialContainerCount + 2);// if the containers already
// exist, this will fail
}
@Test
public void testObjectOperations() throws Exception {
String containerName = containerPrefix + ".testObjectOperations";
String data = "Here is my data";
assertTrue(connection.createContainer(containerName).get(10, TimeUnit.SECONDS));
// Test PUT with string data, ETag hash, and a piece of metadata
PCSFile object = new PCSFile("object");
object.setData(data);
object.setContentLength(data.length());
object.generateMD5();
object.getMetadata().setContentType("text/plain");
object.getMetadata().getUserMetadata().put("Metadata", "metadata-value");
byte[] md5 = object.getMetadata().getContentMD5();
// etag support by end of the year
assertNotNull(connection.putBlob(containerName, object).get(10, TimeUnit.SECONDS));
assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(object.getMetadata()
.getContentMD5()));
// Test HEAD of missing object
try {
connection.blobMetadata(containerName, "non-existent-object");
assert false;
} catch (KeyNotFoundException e) {
}
// Test HEAD of object
FileMetadata metadata = connection.blobMetadata(containerName, object.getKey());
// TODO assertEquals(metadata.getKey(), object.getKey());
assertEquals(metadata.getSize(), data.length());
assertEquals(metadata.getContentType(), "text/plain");
// assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(object.getMetadata()
// .getContentMD5()));
// assertEquals(metadata.getETag(), newEtag);
assertEquals(metadata.getUserMetadata().entries().size(), 1);
assertEquals(Iterables.getLast(metadata.getUserMetadata().get("metadata")), "metadata-value");
// // Test POST to update object's metadata
// Multimap<String, String> userMetadata = HashMultimap.create();
// userMetadata.put("New-Metadata-1", "value-1");
// userMetadata.put("New-Metadata-2", "value-2");
// assertTrue(connection.setObjectMetadata(containerName, object.getKey(), userMetadata));
// Test GET of missing object
try {
connection.getBlob(containerName, "non-existent-object").get(10, TimeUnit.SECONDS);
assert false;
} catch (KeyNotFoundException e) {
}
// Test GET of object (including updated metadata)
PCSFile getBlob = connection.getBlob(containerName, object.getKey()).get(120,
TimeUnit.SECONDS);
assertEquals(IOUtils.toString((InputStream) getBlob.getData()), data);
assertEquals(getBlob.getKey(), object.getKey());
assertEquals(getBlob.getContentLength(), data.length());
assertEquals(getBlob.getMetadata().getContentType(), "text/plain");
// assertEquals(HttpUtils.toHexString(md5), HttpUtils.toHexString(getBlob.getMetadata()
// .getContentMD5()));
// assertEquals(newEtag, getBlob.getMetadata().getETag());
// assertEquals(getBlob.getMetadata().getUserMetadata().entries().size(), 2);
// assertEquals(
// Iterables.getLast(getBlob.getMetadata().getUserMetadata().get("new-metadata-1")),
// "value-1");
// assertEquals(
// Iterables.getLast(getBlob.getMetadata().getUserMetadata().get("new-metadata-2")),
// "value-2");
// Test PUT with invalid ETag (as if object's data was corrupted in transit)
// String correctEtag = HttpUtils.toHexString(newEtag);
// String incorrectEtag = "0" + correctEtag.substring(1);
// object.getMetadata().setETag(HttpUtils.fromHexString(incorrectEtag));
try {
connection.putBlob(containerName, object).get(10, TimeUnit.SECONDS);
} catch (Throwable e) {
assertEquals(e.getCause().getClass(), HttpResponseException.class);
assertEquals(((HttpResponseException) e.getCause()).getResponse().getStatusCode(), 422);
}
assertTrue(connection.removeBlob(containerName, "object").get(10, TimeUnit.SECONDS));
assertTrue(connection.removeBlob(containerName, "chunked-object").get(10, TimeUnit.SECONDS));
assertTrue(connection.deleteContainer(containerName).get(10, TimeUnit.SECONDS));
}
}

View File

@ -0,0 +1,448 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import org.jclouds.blobstore.BlobStoreMapsModule;
import org.jclouds.blobstore.functions.ReturnTrueOnNotFoundOr404;
import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
import org.jclouds.blobstore.integration.internal.StubBlobStore;
import org.jclouds.concurrent.WithinThreadExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ReturnFalseOn404;
import org.jclouds.http.functions.ReturnStringIf200;
import org.jclouds.http.functions.ReturnTrueIf2xx;
import org.jclouds.http.options.GetOptions;
import org.jclouds.mezeo.pcs2.binders.PCSFileAsMultipartFormBinderTest;
import org.jclouds.mezeo.pcs2.config.PCSContextModule;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.mezeo.pcs2.endpoints.RootContainer;
import org.jclouds.mezeo.pcs2.functions.AddMetadataAndParseResourceIdIntoBytes;
import org.jclouds.mezeo.pcs2.functions.AssembleBlobFromContentAndMetadataCache;
import org.jclouds.mezeo.pcs2.functions.InvalidateContainerNameCacheAndReturnTrueIf2xx;
import org.jclouds.mezeo.pcs2.functions.InvalidatePCSKeyCacheAndReturnTrueIf2xx;
import org.jclouds.mezeo.pcs2.functions.ReturnFalseIfContainerNotFound;
import org.jclouds.mezeo.pcs2.functions.ReturnTrueIfContainerNotFound;
import org.jclouds.mezeo.pcs2.reference.PCSConstants;
import org.jclouds.rest.JaxrsAnnotationProcessor;
import org.jclouds.rest.config.JaxrsModule;
import org.jclouds.util.DateService;
import org.jclouds.util.Jsr330;
import org.jclouds.util.Utils;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
import com.google.inject.internal.ImmutableList;
/**
* Tests behavior of {@code PCSConnection}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "pcs2.PCSConnectionTest")
public class PCSBlobStoreTest {
public static final class StubPCSConnection implements PCSBlobStore {
DateService dateService = new DateService();
public Future<Boolean> createContainer(String container) {
return null;
}
public Future<Boolean> deleteContainer(String containerName) {
return null;
}
public Future<? extends List<FileMetadata>> listBlobs(String containerName) {
return new StubBlobStore.FutureBase<List<FileMetadata>>() {
public List<FileMetadata> get() throws InterruptedException, ExecutionException {
return ImmutableList
.of(
new FileMetadata(
"more",
URI
.create("https://pcsbeta.mezeo.net/v2/files/5C81DADC-AAEE-11DE-9D55-B39340AEFF3A"),
dateService.fromSeconds(1254005157), dateService
.fromSeconds(1254005158), dateService
.fromSeconds(1254005159), "adrian@jclouds.org",
false, false, 1, 254288,
MediaType.APPLICATION_OCTET_STREAM, true),
new FileMetadata(
"testfile.txt",
URI
.create("https://pcsbeta.mezeo.net/v2/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3"),
dateService.fromSeconds(1254000180), dateService
.fromSeconds(1254000181), dateService
.fromSeconds(1254000182), "adrian@jclouds.org",
false, true, 3, 5, MediaType.TEXT_PLAIN, false));
}
};
}
public List<ContainerMetadata> listContainers() {
return ImmutableList
.of(new ContainerMetadata(
"mycontainer",
URI
.create("https://pcsbeta.mezeo.net/v2/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B"),
dateService.fromSeconds(1254008225),
dateService.fromSeconds(1254008226),
dateService.fromSeconds(1254008227), "adrian@jclouds.org", true, false,
1, 1024));
}
public Future<byte[]> putBlob(String containerName, PCSFile object) {
return null;
}
public Future<Boolean> removeBlob(String container, String key) {
return null;
}
public Future<PCSFile> getBlob(String container, String key) {
return null;
}
public FileMetadata blobMetadata(String container, String key) {
return null;
}
public Future<PCSFile> getBlob(String container, String key, GetOptions options) {
return null;
}
public boolean containerExists(String containerName) {
return false;
}
}
public void testListContainers() throws SecurityException, NoSuchMethodException {
Method method = PCSBlobStore.class.getMethod("listContainers");
HttpRequest httpMethod = processor.createRequest(method, new Object[] {});
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/root/contents");
assertEquals(httpMethod.getEndpoint().getQuery(), null);
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 1);
assertEquals(httpMethod.getHeaders().get("X-Cloud-Depth"), Collections.singletonList("2"));
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
ParseSax.class);
// TODO check generic type of response parser
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
}
public void testCreateContainer() throws SecurityException, NoSuchMethodException, IOException {
Method method = PCSBlobStore.class.getMethod("createContainer", String.class);
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "container" });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/root/contents");
assertEquals(httpMethod.getEndpoint().getQuery(), null);
assertEquals(httpMethod.getMethod(), HttpMethod.POST);
assertEquals(httpMethod.getHeaders().size(), 2);
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_LENGTH), Collections
.singletonList("45"));
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_TYPE), Collections
.singletonList("application/vnd.csp.container-info+xml"));
assertEquals(httpMethod.getEntity(), "<container><name>container</name></container>");
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
ReturnTrueIf2xx.class);
// TODO check generic type of response parser
}
public void testDeleteContainer() throws SecurityException, NoSuchMethodException {
Method method = PCSBlobStore.class.getMethod("deleteContainer", String.class);
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "mycontainer" });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(),
"/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B");
assertEquals(httpMethod.getEndpoint().getQuery(), null);
assertEquals(httpMethod.getMethod(), HttpMethod.DELETE);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
InvalidateContainerNameCacheAndReturnTrueIf2xx.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
ReturnTrueIfContainerNotFound.class);
}
public void testContainerExists() throws SecurityException, NoSuchMethodException {
Method method = PCSBlobStore.class.getMethod("containerExists", String.class);
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "mycontainer" });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(),
"/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B");
assertEquals(httpMethod.getEndpoint().getQuery(), null);
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
ReturnTrueIf2xx.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
ReturnFalseIfContainerNotFound.class);
}
public void testListBlobs() throws SecurityException, NoSuchMethodException {
Method method = PCSBlobStore.class.getMethod("listBlobs", String.class);
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "mycontainer" });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(),
"/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B/contents");
assertEquals(httpMethod.getEndpoint().getQuery(), null);
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 1);
assertEquals(httpMethod.getHeaders().get("X-Cloud-Depth"), Collections.singletonList("2"));
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
ParseSax.class);
// TODO check generic type of response parser
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
}
public void testPutBlob() throws SecurityException, NoSuchMethodException, IOException {
Method method = PCSBlobStore.class.getMethod("putBlob", String.class, PCSFile.class);
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "mycontainer",
PCSFileAsMultipartFormBinderTest.TEST_BLOB });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(),
"/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B/contents");
assertEquals(httpMethod.getEndpoint().getQuery(), null);
assertEquals(httpMethod.getMethod(), HttpMethod.POST);
assertEquals(httpMethod.getHeaders().size(), 2);
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_LENGTH), Collections
.singletonList(PCSFileAsMultipartFormBinderTest.EXPECTS.length() + ""));
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_TYPE), Collections
.singletonList("multipart/form-data; boundary="
+ PCSFileAsMultipartFormBinderTest.BOUNDRY));
assertEquals(Utils.toStringAndClose((InputStream) httpMethod.getEntity()),
PCSFileAsMultipartFormBinderTest.EXPECTS);
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
AddMetadataAndParseResourceIdIntoBytes.class);
}
public void testRemoveBlob() throws SecurityException, NoSuchMethodException, IOException {
Method method = PCSBlobStore.class.getMethod("removeBlob", String.class, String.class);
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "mycontainer",
"testfile.txt" });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(),
"/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3");
assertEquals(httpMethod.getEndpoint().getQuery(), null);
assertEquals(httpMethod.getMethod(), HttpMethod.DELETE);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
InvalidatePCSKeyCacheAndReturnTrueIf2xx.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
ReturnTrueOnNotFoundOr404.class);
}
public void testGetBlob() throws SecurityException, NoSuchMethodException, IOException {
Method method = PCSBlobStore.class.getMethod("getBlob", String.class, String.class);
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "mycontainer",
"testfile.txt" });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(),
"/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3/content");
assertEquals(httpMethod.getEndpoint().getQuery(), null);
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
AssembleBlobFromContentAndMetadataCache.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
ThrowKeyNotFoundOn404.class);
}
public void testGetBlobOptios() throws SecurityException, NoSuchMethodException, IOException {
Method method = PCSBlobStore.class.getMethod("getBlob", String.class, String.class,
GetOptions.class);
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "mycontainer",
"testfile.txt", new GetOptions() });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(),
"/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3/content");
assertEquals(httpMethod.getEndpoint().getQuery(), null);
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
AssembleBlobFromContentAndMetadataCache.class);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
ThrowKeyNotFoundOn404.class);
}
public void testGetBlobMetadata() throws SecurityException, NoSuchMethodException, IOException {
Method method = PCSBlobStore.class.getMethod("blobMetadata", String.class, String.class);
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "mycontainer",
"testfile.txt" });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(),
"/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3");
assertEquals(httpMethod.getEndpoint().getQuery(), null);
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
ParseSax.class);
assertEquals(httpMethod.getHeaders().size(), 1);
assertEquals(httpMethod.getHeaders().get("X-Cloud-Depth"), Collections.singletonList("2"));
// TODO check generic type of response parser
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
ThrowKeyNotFoundOn404.class);
}
public void testPutMetadata() throws SecurityException, NoSuchMethodException {
Method method = PCSUtil.class.getMethod("put", URI.class, String.class);
HttpRequest httpMethod = utilProcessor.createRequest(method, new Object[] {
URI.create("http://localhost/pow"), "bar" });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/pow");
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
assertEquals(httpMethod.getHeaders().size(), 2);
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_LENGTH), Collections
.singletonList(httpMethod.getEntity().toString().getBytes().length + ""));
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_TYPE), Collections
.singletonList("application/unknown"));
assertEquals("bar", httpMethod.getEntity());
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(),
ReturnFalseOn404.class);
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
ReturnTrueIf2xx.class);
}
public void testGetMetadata() throws SecurityException, NoSuchMethodException {
Method method = PCSUtil.class.getMethod("get", URI.class);
HttpRequest httpMethod = utilProcessor.createRequest(method, new Object[] {
URI.create("http://localhost/pow"), "foo" });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/pow");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
ReturnStringIf200.class);
}
JaxrsAnnotationProcessor<PCSBlobStore> processor;
private JaxrsAnnotationProcessor<PCSUtil> utilProcessor;
@SuppressWarnings("unchecked")
@BeforeClass
void setupFactory() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(URI.class).annotatedWith(PCS.class)
.toInstance(URI.create("http://localhost:8080"));
bind(URI.class).annotatedWith(RootContainer.class).toInstance(
URI.create("http://localhost:8080/root"));
bindConstant().annotatedWith(Jsr330.named(PCSConstants.PROPERTY_PCS2_USER)).to("user");
bindConstant().annotatedWith(Jsr330.named(PCSConstants.PROPERTY_PCS2_PASSWORD)).to(
"password");
}
@SuppressWarnings("unused")
@Provides
@Singleton
public PCSBlobStore getPCSConnection() {
return new StubPCSConnection();
}
@SuppressWarnings("unused")
@Provides
@Singleton
public PCSUtil getPCSUtil() {
return new PCSUtil() {
public String get(URI resource) {
return null;
}
public boolean put(URI resource, String value) {
return true;
}
};
}
@SuppressWarnings("unused")
@Provides
@Singleton
public BasicAuthentication provideBasicAuthentication(
@Named(PCSConstants.PROPERTY_PCS2_USER) String user,
@Named(PCSConstants.PROPERTY_PCS2_PASSWORD) String password)
throws UnsupportedEncodingException {
return new BasicAuthentication(user, password);
}
}, new JaxrsModule(), new BlobStoreMapsModule(new TypeLiteral<PCSBlobStore>() {
}, new TypeLiteral<ContainerMetadata>() {
}, new TypeLiteral<FileMetadata>() {
}, new TypeLiteral<PCSFile>() {
}), new PCSContextModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
new JavaUrlHttpCommandExecutorServiceModule());
processor = injector.getInstance(Key
.get(new TypeLiteral<JaxrsAnnotationProcessor<PCSBlobStore>>() {
}));
utilProcessor = injector.getInstance(Key
.get(new TypeLiteral<JaxrsAnnotationProcessor<PCSUtil>>() {
}));
}
}

View File

@ -1,5 +1,29 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.testng.Assert.assertNotNull;
import java.io.UnsupportedEncodingException;
@ -30,8 +54,10 @@ import com.google.inject.Provides;
@Test(groups = "live", testName = "pcs2.PCSCloudLiveTest")
public class PCSCloudLiveTest {
String user = System.getProperty("jclouds.test.user");
String password = System.getProperty("jclouds.test.key");
String user = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user");
String password = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key");
URI endpoint = URI.create(checkNotNull(System.getProperty("jclouds.test.endpoint"),
"jclouds.test.endpoint"));
private Injector injector;
@ -54,8 +80,7 @@ public class PCSCloudLiveTest {
injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(URI.class).annotatedWith(PCS.class).toInstance(
URI.create("https://pcsbeta.mezeo.net/v2"));
bind(URI.class).annotatedWith(PCS.class).toInstance(endpoint);
}
@SuppressWarnings("unused")

View File

@ -0,0 +1,93 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.jclouds.cloud.CloudContext;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.mezeo.pcs2.config.RestPCSBlobStoreModule;
import org.jclouds.mezeo.pcs2.config.PCSContextModule.PCSContextImpl;
import org.jclouds.mezeo.pcs2.reference.PCSConstants;
import org.testng.annotations.Test;
import com.google.inject.Injector;
import com.google.inject.Module;
/**
* Tests behavior of modules configured in PCSContextBuilder
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "cloudfiles.PCSContextBuilderTest")
public class PCSContextBuilderTest {
public void testNewBuilder() {
PCSContextBuilder builder = new PCSContextBuilder(URI.create("https://localhost:8080"), "id",
"secret");
assertEquals(builder.getProperties().getProperty(PCSConstants.PROPERTY_PCS2_ENDPOINT),
"https://localhost:8080");
assertEquals(builder.getProperties().getProperty(PCSConstants.PROPERTY_PCS2_USER), "id");
assertEquals(builder.getProperties().getProperty(PCSConstants.PROPERTY_PCS2_PASSWORD),
"secret");
}
public void testBuildContext() {
CloudContext<PCSBlobStore> context = new PCSContextBuilder(URI
.create("https://localhost:8080"), "id", "secret").buildContext();
assertEquals(context.getClass(), PCSContextImpl.class);
assertEquals(context.getAccount(), "id");
assertEquals(context.getEndPoint(), URI.create("https://localhost:8080"));
}
public void testBuildInjector() {
Injector i = new PCSContextBuilder(URI.create("https://localhost:8080"), "id", "secret")
.buildInjector();
assert i.getInstance(PCSContext.class) != null;
assert i.getInstance(BasicAuthentication.class) != null;
}
protected void testAddContextModule() {
List<Module> modules = new ArrayList<Module>();
PCSContextBuilder builder = new PCSContextBuilder(URI.create("https://localhost:8080"), "id",
"secret");
builder.addContextModule(modules);
assertEquals(modules.size(), 1);
assertEquals(modules.get(0).getClass(), RestPCSBlobStoreModule.class);
}
protected void addConnectionModule() {
List<Module> modules = new ArrayList<Module>();
PCSContextBuilder builder = new PCSContextBuilder(URI.create("https://localhost:8080"), "id",
"secret");
builder.addConnectionModule(modules);
assertEquals(modules.size(), 1);
assertEquals(modules.get(0).getClass(), RestPCSBlobStoreModule.class);
}
}

View File

@ -0,0 +1,54 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.binders;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.http.HttpRequest;
import org.testng.annotations.Test;
/**
* Tests behavior of {@code ParseFlavorListFromGsonResponseTest}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "pcs2.CreateContainerBinderTest")
public class CreateContainerBinderTest {
public void test() {
CreateContainerBinder binder = new CreateContainerBinder();
HttpRequest request = new HttpRequest("GET", URI.create("http://localhost"));
binder.addEntityToRequest("foo", request);
assertEquals(request.getEntity(), "<container><name>foo</name></container>");
assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH),
"<container><name>foo</name></container>".getBytes().length + "");
assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE),
"application/vnd.csp.container-info+xml");
}
}

View File

@ -0,0 +1,87 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.binders;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import org.jclouds.http.HttpRequest;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.util.Utils;
import org.testng.annotations.Test;
/**
* Tests parsing of a request
*
* @author Adrian Cole
*/
@Test(testName = "pcs2.PCSFileAsMultipartFormBinderTest")
public class PCSFileAsMultipartFormBinderTest {
public static String BOUNDRY = PCSFileAsMultipartFormBinder.BOUNDARY;
public static final String EXPECTS;
public static final PCSFile TEST_BLOB;
static {
StringBuilder builder = new StringBuilder("--");
addData(BOUNDRY, "hello", builder);
builder.append("--").append(BOUNDRY).append("--").append("\r\n");
EXPECTS = builder.toString();
TEST_BLOB = new PCSFile("hello");
TEST_BLOB.setData("hello");
TEST_BLOB.getMetadata().setContentType(MediaType.TEXT_PLAIN);
}
public void testSinglePart() throws IOException {
assertEquals(EXPECTS.length(), 123);
PCSFileAsMultipartFormBinder binder = new PCSFileAsMultipartFormBinder();
HttpRequest request = new HttpRequest("GET", URI.create("http://localhost:8001"));
binder.addEntityToRequest(TEST_BLOB, request);
assertEquals(Utils.toStringAndClose((InputStream) request.getEntity()), EXPECTS);
assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH), 123 + "");
assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE),
"multipart/form-data; boundary=" + BOUNDRY);
}
private static void addData(String boundary, String data, StringBuilder builder) {
builder.append(boundary).append("\r\n");
builder.append("Content-Disposition").append(": ").append(
"form-data; name=\"hello\"; filename=\"hello\"").append("\r\n");
builder.append("Content-Type").append(": ").append("text/plain").append("\r\n");
builder.append("\r\n");
builder.append(data).append("\r\n");
}
}

View File

@ -0,0 +1,84 @@
package org.jclouds.mezeo.pcs2.config;
import static org.testng.Assert.assertEquals;
import org.jclouds.blobstore.BlobStoreMapsModule;
import org.jclouds.concurrent.WithinThreadExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.http.handlers.CloseContentAndSetExceptionErrorHandler;
import org.jclouds.http.handlers.DelegatingErrorHandler;
import org.jclouds.http.handlers.DelegatingRetryHandler;
import org.jclouds.http.handlers.RedirectionRetryHandler;
import org.jclouds.mezeo.pcs2.PCSBlobStore;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.mezeo.pcs2.handlers.PCSClientErrorRetryHandler;
import org.jclouds.mezeo.pcs2.reference.PCSConstants;
import org.jclouds.util.Jsr330;
import org.testng.annotations.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.TypeLiteral;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "pcs2.PCSContextModuleTest")
public class PCSContextModuleTest {
Injector createInjector() {
return Guice.createInjector(new RestPCSBlobStoreModule(),
new BlobStoreMapsModule<PCSBlobStore, ContainerMetadata, FileMetadata, PCSFile>(
new TypeLiteral<PCSBlobStore>() {
}, new TypeLiteral<ContainerMetadata>() {
}, new TypeLiteral<FileMetadata>() {
}, new TypeLiteral<PCSFile>() {
}), new PCSContextModule() {
@Override
protected void configure() {
bindConstant().annotatedWith(Jsr330.named(PCSConstants.PROPERTY_PCS2_USER))
.to("user");
bindConstant()
.annotatedWith(Jsr330.named(PCSConstants.PROPERTY_PCS2_PASSWORD)).to(
"key");
bindConstant()
.annotatedWith(Jsr330.named(PCSConstants.PROPERTY_PCS2_ENDPOINT)).to(
"http://localhost");
super.configure();
}
}, new ParserModule(), new JavaUrlHttpCommandExecutorServiceModule(),
new ExecutorServiceModule(new WithinThreadExecutorService()));
}
@Test
void testServerErrorHandler() {
DelegatingErrorHandler handler = createInjector().getInstance(DelegatingErrorHandler.class);
assertEquals(handler.getServerErrorHandler().getClass(),
CloseContentAndSetExceptionErrorHandler.class);
}
@Test
void testClientErrorHandler() {
DelegatingErrorHandler handler = createInjector().getInstance(DelegatingErrorHandler.class);
assertEquals(handler.getClientErrorHandler().getClass(),
CloseContentAndSetExceptionErrorHandler.class);
}
@Test
void testClientRetryHandler() {
DelegatingRetryHandler handler = createInjector().getInstance(DelegatingRetryHandler.class);
assertEquals(handler.getClientErrorRetryHandler().getClass(),
PCSClientErrorRetryHandler.class);
}
@Test
void testRedirectionRetryHandler() {
DelegatingRetryHandler handler = createInjector().getInstance(DelegatingRetryHandler.class);
assertEquals(handler.getRedirectionRetryHandler().getClass(), RedirectionRetryHandler.class);
}
}

View File

@ -0,0 +1,58 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.config;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.jclouds.cloud.ConfiguresCloudConnection;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.mezeo.pcs2.PCS;
import org.jclouds.mezeo.pcs2.PCSBlobStore;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.mezeo.pcs2.internal.StubPCSBlobStore;
import com.google.inject.AbstractModule;
import com.google.inject.TypeLiteral;
/**
* adds a stub alternative to invoking PCSBlob
*
* @author Adrian Cole
*/
@ConfiguresCloudConnection
public class StubPCSBlobStoreModule extends AbstractModule {
static final ConcurrentHashMap<String, Map<String, PCSFile>> map = new ConcurrentHashMap<String, Map<String, PCSFile>>();
protected void configure() {
install(new ParserModule());
bind(new TypeLiteral<Map<String, Map<String, PCSFile>>>() {
}).toInstance(map);
bind(PCSBlobStore.class).to(StubPCSBlobStore.class).asEagerSingleton();
bind(URI.class).annotatedWith(PCS.class).toInstance(URI.create("https://localhost/pcsblob"));
}
}

View File

@ -0,0 +1,125 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.functions;
import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import javax.ws.rs.ext.RuntimeDelegate;
import org.apache.commons.io.IOUtils;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpUtils;
import org.jclouds.mezeo.pcs2.PCSUtil;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.rest.RuntimeDelegateImpl;
import org.testng.annotations.Test;
/**
* Tests behavior of {@code UseResourceIdAsETag}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "pcs2.AddMetadataAndParseResourceIdIntoBytesTest")
public class AddMetadataAndParseResourceIdIntoBytesTest {
static {
RuntimeDelegate.setInstance(new RuntimeDelegateImpl());
}
HttpResponse response = new HttpResponse();
PCSUtil createPCSUtil() {
PCSUtil connection = createMock(PCSUtil.class);
expect(
connection
.put(
eq(URI
.create("http://localhost/contents/7F143552-AAF5-11DE-BBB0-0BC388ED913B/metadata/foo")),
eq("bar"))).andReturn(true);
expect(
connection
.put(
eq(URI
.create("http://localhost/contents/7F143552-AAF5-11DE-BBB0-0BC388ED913B/metadata/biz")),
eq("baz"))).andReturn(true);
replay(connection);
return connection;
}
@Test(expectedExceptions = IllegalStateException.class)
public void testNoArgs() {
AddMetadataAndParseResourceIdIntoBytes function = new AddMetadataAndParseResourceIdIntoBytes(
createPCSUtil());
function.apply(response);
}
@Test(expectedExceptions = IllegalStateException.class)
public void testNoRequest() {
AddMetadataAndParseResourceIdIntoBytes function = new AddMetadataAndParseResourceIdIntoBytes(
createPCSUtil());
function.setContext(null, new Object[] { new PCSFile("key") });
function.apply(response);
}
public void testGetEtag() {
PCSUtil connection = createPCSUtil();
AddMetadataAndParseResourceIdIntoBytes function = new AddMetadataAndParseResourceIdIntoBytes(
connection);
function.setContext(new HttpRequest("GET", URI.create("http://localhost:8080")),
new Object[] { new PCSFile("key") });
response.setContent(IOUtils
.toInputStream("http://localhost/contents/7F143552-AAF5-11DE-BBB0-0BC388ED913B"));
byte[] eTag = function.apply(response);
byte[] expected = HttpUtils.fromHexString("7F143552AAF511DEBBB00BC388ED913B");
assertEquals(eTag, expected);
}
public void testMetadataGetEtag() {
PCSUtil connection = createPCSUtil();
AddMetadataAndParseResourceIdIntoBytes function = new AddMetadataAndParseResourceIdIntoBytes(
connection);
PCSFile pcsFile = new PCSFile("key");
pcsFile.getMetadata().getUserMetadata().put("foo", "bar");
pcsFile.getMetadata().getUserMetadata().put("biz", "baz");
function.setContext(new HttpRequest("GET", URI.create("http://localhost:8080")),
new Object[] { pcsFile });
response.setContent(IOUtils
.toInputStream("http://localhost/contents/7F143552-AAF5-11DE-BBB0-0BC388ED913B"));
byte[] eTag = function.apply(response);
byte[] expected = HttpUtils.fromHexString("7F143552AAF511DEBBB00BC388ED913B");
assertEquals(eTag, expected);
verify(connection);
}
}

View File

@ -0,0 +1,66 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.functions;
import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.util.concurrent.ConcurrentMap;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpResponse;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
public class AssembleBlobFromBlobMetadataCallTest {
@SuppressWarnings("unchecked")
@Test(expectedExceptions = NullPointerException.class)
public void testCall() throws HttpException {
FileMetadata metadata = new FileMetadata("blob");
metadata.setSize(103);
ConcurrentMap<Key, FileMetadata> mdCache = createMock(ConcurrentMap.class);
InputStream data = createMock(InputStream.class);
AssembleBlobFromContentAndMetadataCache callable = new AssembleBlobFromContentAndMetadataCache(
mdCache);
HttpResponse response = createMock(HttpResponse.class);
expect(mdCache.get(new Key("container", "blob"))).andReturn(metadata);
expect(response.getContent()).andReturn(data);
replay(mdCache);
replay(response);
PCSFile file = callable.apply(response);
assertEquals(file.getMetadata(), metadata);
assertEquals(file.getKey(), "blob");
assertEquals(file.getData(), data);
assertEquals(file.getContentLength(), metadata.getSize());
}
}

View File

@ -0,0 +1,68 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.functions;
import static org.easymock.classextension.EasyMock.createNiceMock;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.mezeo.pcs2.PCSBlobStore;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.util.DateService;
import org.testng.annotations.Test;
import com.google.inject.internal.ImmutableList;
/**
* Tests behavior of {@code ContainerResourceId}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "pcs2.FindIdInContainerList")
public class FindIdInContainerListTest {
private DateService dateService = new DateService();
private final ImmutableList<ContainerMetadata> OF = ImmutableList
.of(new ContainerMetadata(
"test1",
URI
.create("https://pcsbeta.mezeo.net/v2/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B"),
dateService.fromSeconds(1254008225), dateService.fromSeconds(1254008226),
dateService.fromSeconds(1254008227), "adrian@jclouds.org", true, false, 1,
1024));
@Test(expectedExceptions = ContainerNotFoundException.class)
public void testBad() {
FindIdInContainerList binder = new FindIdInContainerList(createNiceMock(PCSBlobStore.class));
binder.idForNameInListOrException("hello", OF);
}
public void testGood() {
FindIdInContainerList binder = new FindIdInContainerList(createNiceMock(PCSBlobStore.class));
assertEquals(binder.idForNameInListOrException("test1", OF),
"7F143552-AAF5-11DE-BBB0-0BC388ED913B");
}
}

View File

@ -0,0 +1,73 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.functions;
import static org.easymock.classextension.EasyMock.createNiceMock;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import javax.ws.rs.core.MediaType;
import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.mezeo.pcs2.PCSBlobStore;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.util.DateService;
import org.testng.annotations.Test;
import com.google.inject.internal.ImmutableList;
/**
* Tests behavior of {@code ContainerResourceId}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "pcs2.FindIdInFileListTest")
public class FindIdInFileListIdTest {
private DateService dateService = new DateService();
private final ImmutableList<FileMetadata> OF = ImmutableList.of(new FileMetadata("more", URI
.create("https://pcsbeta.mezeo.net/v2/files/5C81DADC-AAEE-11DE-9D55-B39340AEFF3A"),
dateService.fromSeconds(1254005157), dateService.fromSeconds(1254005158), dateService
.fromSeconds(1254005159), "adrian@jclouds.org", false, false, 1, 254288,
MediaType.APPLICATION_OCTET_STREAM, true),
new FileMetadata("testfile.txt", URI
.create("https://pcsbeta.mezeo.net/v2/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3"),
dateService.fromSeconds(1254000180), dateService.fromSeconds(1254000181), dateService
.fromSeconds(1254000182), "adrian@jclouds.org", false, true, 3, 5,
MediaType.TEXT_PLAIN, false));
@Test(expectedExceptions = KeyNotFoundException.class)
public void testBad() {
FindIdInFileList binder = new FindIdInFileList(createNiceMock(PCSBlobStore.class));
binder.idForNameInListOrException("bob", "hello", OF);
}
public void testGood() {
FindIdInFileList binder = new FindIdInFileList(createNiceMock(PCSBlobStore.class));
assertEquals(binder.idForNameInListOrException("bob", "testfile.txt", OF),
"9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3");
}
}

View File

@ -0,0 +1,47 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.integration;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import org.jclouds.blobstore.integration.internal.BaseBlobMapIntegrationTest;
import org.jclouds.mezeo.pcs2.PCSBlobStore;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = { "integration", "live" }, testName = "cloudfiles.PCSBlobMapIntegrationTest")
public class PCSBlobMapIntegrationTest extends
BaseBlobMapIntegrationTest<PCSBlobStore, ContainerMetadata, FileMetadata, PCSFile> {
@Override
public void testContains() throws InterruptedException, ExecutionException, TimeoutException {
// not supported
}
}

View File

@ -0,0 +1,55 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.integration;
import java.util.concurrent.TimeUnit;
import org.jclouds.blobstore.integration.internal.BaseContainerIntegrationTest;
import org.jclouds.mezeo.pcs2.PCSBlobStore;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = { "integration", "live" }, testName = "cloudfiles.PCSBlobContainerIntegrationTest")
public class PCSBlobStoreContainerIntegrationTest extends
BaseContainerIntegrationTest<PCSBlobStore, ContainerMetadata, FileMetadata, PCSFile> {
@Override
@Test(groups = { "integration", "live" })
public void deleteContainerIfEmptyButHasContents() throws Exception {
String containerName = getContainerName();
try {
addBlobToContainer(containerName, "test");
// true is returned, since we can delete containers with contents
assert context.getApi().deleteContainer(containerName).get(10, TimeUnit.SECONDS);
} finally {
returnContainer(containerName);
}
}
}

View File

@ -0,0 +1,40 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.integration;
import org.jclouds.blobstore.integration.internal.BaseContainerLiveTest;
import org.jclouds.mezeo.pcs2.PCSBlobStore;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = { "live" }, testName = "cloudfiles.PCSBlobContainerLiveTest")
public class PCSBlobStoreContainerLiveTest extends
BaseContainerLiveTest<PCSBlobStore, ContainerMetadata, FileMetadata, PCSFile> {
}

View File

@ -0,0 +1,119 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.integration;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import org.jclouds.blobstore.integration.internal.BaseBlobIntegrationTest;
import org.jclouds.mezeo.pcs2.PCSBlobStore;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = { "integration", "live" }, testName = "cloudfiles.PCSBlobIntegrationTest")
public class PCSBlobStoreIntegrationTest extends
BaseBlobIntegrationTest<PCSBlobStore, ContainerMetadata, FileMetadata, PCSFile> {
@Override
protected void validateMetadata(FileMetadata metadata) {
assertEquals(metadata.getContentType(), "text/plain");
assertEquals(metadata.getSize(), TEST_STRING.length());
assertEquals(metadata.getUserMetadata().get("adrian"), Collections
.singletonList("powderpuff"));
// Content-MD5 not supported http://code.google.com/p/jclouds/issues/detail?id=105
// assertEquals(metadata.getContentMD5(), HttpUtils.md5(TEST_STRING.getBytes()));
}
@Override
@Test(enabled = false)
public void testGetIfMatch() throws InterruptedException, ExecutionException, TimeoutException,
IOException {
// etag not supported http://code.google.com/p/jclouds/issues/detail?id=105
}
@Override
@Test(enabled = false)
public void testGetIfModifiedSince() throws InterruptedException, ExecutionException,
TimeoutException, IOException {
// unsupported
}
@Override
@Test(enabled = false)
public void testGetIfNoneMatch() throws InterruptedException, ExecutionException,
TimeoutException, IOException {
// etag not supported http://code.google.com/p/jclouds/issues/detail?id=105
}
@Override
@Test(enabled = false)
public void testGetIfUnmodifiedSince() throws InterruptedException, ExecutionException,
TimeoutException, IOException {
// unsupported
}
@Override
@Test(enabled = false)
public void testGetRange() throws InterruptedException, ExecutionException, TimeoutException,
IOException {
// unsupported http://code.google.com/p/jclouds/issues/detail?id=106
}
@Override
@Test(enabled = false)
public void testGetStartAt() throws InterruptedException, ExecutionException, TimeoutException,
IOException {
// unsupported http://code.google.com/p/jclouds/issues/detail?id=106
}
@Override
@Test(enabled = false)
public void testGetTail() throws InterruptedException, ExecutionException, TimeoutException,
IOException {
// unsupported http://code.google.com/p/jclouds/issues/detail?id=106
}
@Override
@Test(enabled = false)
public void testGetTwoRanges() throws InterruptedException, ExecutionException,
TimeoutException, IOException {
// unsupported http://code.google.com/p/jclouds/issues/detail?id=106
}
@DataProvider(name = "delete")
@Override
public Object[][] createData() {
return new Object[][] { { "normal" } };
}
}

View File

@ -0,0 +1,46 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.integration;
import org.jclouds.blobstore.integration.internal.BaseBlobLiveTest;
import org.jclouds.mezeo.pcs2.PCSBlobStore;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = { "live" }, testName = "cloudfiles.PCSBlobLiveTest")
public class PCSBlobStoreLiveTest extends
BaseBlobLiveTest<PCSBlobStore, ContainerMetadata, FileMetadata, PCSFile> {
@Override
@Test(enabled = false)
public void testCopyUrl(String httpStreamUrl, String httpStreamETag) throws Exception {
// depends on md5 which is not yet supported
}
}

View File

@ -0,0 +1,40 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.integration;
import org.jclouds.blobstore.integration.internal.BaseServiceIntegrationTest;
import org.jclouds.mezeo.pcs2.PCSBlobStore;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = { "integration", "live" }, testName = "cloudfiles.PCSBlobServiceIntegrationTest")
public class PCSBlobStoreServiceIntegrationTest extends
BaseServiceIntegrationTest<PCSBlobStore, ContainerMetadata, FileMetadata, PCSFile> {
}

View File

@ -0,0 +1,66 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.integration;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import org.jclouds.blobstore.integration.internal.BaseInputStreamMapIntegrationTest;
import org.jclouds.mezeo.pcs2.PCSBlobStore;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = { "integration", "live" }, testName = "cloudfiles.PCSBlobInputStreamMapIntegrationTest")
public class PCSInputStreamMapIntegrationTest extends
BaseInputStreamMapIntegrationTest<PCSBlobStore, ContainerMetadata, FileMetadata, PCSFile> {
@Override
public void testContainsBytesValue() throws InterruptedException, ExecutionException,
TimeoutException {
// not supported
}
@Override
public void testContainsFileValue() throws InterruptedException, ExecutionException,
TimeoutException {
// not supported
}
@Override
public void testContainsInputStreamValue() throws InterruptedException, ExecutionException,
TimeoutException {
// not supported
}
@Override
public void testContainsStringValue() throws InterruptedException, ExecutionException,
TimeoutException {
// not supported
}
}

View File

@ -0,0 +1,60 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.integration;
import java.net.URI;
import org.jclouds.blobstore.integration.internal.BaseTestInitializer;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.mezeo.pcs2.PCSBlobStore;
import org.jclouds.mezeo.pcs2.PCSContext;
import org.jclouds.mezeo.pcs2.PCSContextBuilder;
import org.jclouds.mezeo.pcs2.PCSContextFactory;
import org.jclouds.mezeo.pcs2.config.StubPCSBlobStoreModule;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import com.google.inject.Module;
/**
*
* @author Adrian Cole
*/
public class PCSTestInitializer extends
BaseTestInitializer<PCSBlobStore, ContainerMetadata, FileMetadata, PCSFile> {
@Override
protected PCSContext createLiveContext(Module configurationModule, String url, String app,
String account, String key) {
return new PCSContextBuilder(URI.create(url), account, key).relaxSSLHostname().withModules(
configurationModule, new Log4JLoggingModule()).buildContext();
}
@Override
protected PCSContext createStubContext() {
return PCSContextFactory.createContext(URI.create("http://localhost/stubpcs"), "user",
"pass", new StubPCSBlobStoreModule());
}
}

View File

@ -0,0 +1,64 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.internal;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.inject.Inject;
import javax.inject.Provider;
import org.jclouds.blobstore.integration.internal.StubBlobStore;
import org.jclouds.mezeo.pcs2.PCSBlobStore;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.util.DateService;
/**
* Implementation of {@link PCSBlobStore} which keeps all data in a local Map object.
*
* @author Adrian Cole
*/
public class StubPCSBlobStore extends StubBlobStore<ContainerMetadata, FileMetadata, PCSFile>
implements PCSBlobStore {
@Override
public Future<Boolean> deleteContainer(final String container) {
return new FutureBase<Boolean>() {
public Boolean get() throws InterruptedException, ExecutionException {
getContainerToBlobs().remove(container);
return true;
}
};
}
@Inject
protected StubPCSBlobStore(Map<String, Map<String, PCSFile>> containerToBlobs,
DateService dateService, Provider<ContainerMetadata> containerMetaProvider,
Provider<PCSFile> blobProvider) {
super(containerToBlobs, dateService, containerMetaProvider, blobProvider);
}
}

View File

@ -0,0 +1,47 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.util;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import org.jclouds.http.HttpUtils;
import org.testng.annotations.Test;
/**
* Tests behavior of {@code PCSUtils}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "pcs2.PCSUtilsTest")
public class PCSUtilsTest {
public void testGetEtag() {
byte[] expected = HttpUtils.fromHexString("7F143552AAF511DEBBB00BC388ED913B");
byte[] eTag = PCSUtils.getEtag(URI
.create("http://localhost/contents/7F143552-AAF5-11DE-BBB0-0BC388ED913B"));
assertEquals(eTag, expected);
}
}

View File

@ -1,3 +1,26 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.xml;
import static org.testng.Assert.assertEquals;

View File

@ -0,0 +1,75 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.URI;
import java.util.List;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.util.DateService;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
/**
* Tests behavior of {@code FileListToContainerMetadataListHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "pcs2.FileListToContainerMetadataListHandlerTest")
public class FileListToContainerMetadataListHandlerTest extends BaseHandlerTest {
private DateService dateService;
@BeforeTest
@Override
protected void setUpInjector() {
super.setUpInjector();
dateService = injector.getInstance(DateService.class);
assert dateService != null;
}
@SuppressWarnings("unchecked")
public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/test_file_list.xml");
List<ContainerMetadata> list = ImmutableList
.of(new ContainerMetadata(
"test1",
URI
.create("https://pcsbeta.mezeo.net/v2/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B"),
dateService.fromSeconds(1254008225), dateService.fromSeconds(1254008226),
dateService.fromSeconds(1254008227), "adrian@jclouds.org", true, false, 1,
1024));
List<ContainerMetadata> result = (List<ContainerMetadata>) factory.create(
injector.getInstance(FileListToContainerMetadataListHandler.class)).parse(is);
assertEquals(result, list);
}
}

View File

@ -0,0 +1,81 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.URI;
import java.util.List;
import javax.ws.rs.core.MediaType;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.util.DateService;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
/**
* Tests behavior of {@code FileListToFileMetadataListHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "pcs2.FileListToFileMetadataListHandlerTest")
public class FileListToFileMetadataListHandlerTest extends BaseHandlerTest {
private DateService dateService;
@BeforeTest
@Override
protected void setUpInjector() {
super.setUpInjector();
dateService = injector.getInstance(DateService.class);
assert dateService != null;
}
@SuppressWarnings("unchecked")
public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/test_file_list.xml");
List<FileMetadata> list = ImmutableList.of(new FileMetadata("more", URI
.create("https://pcsbeta.mezeo.net/v2/files/5C81DADC-AAEE-11DE-9D55-B39340AEFF3A"),
dateService.fromSeconds(1254005157), dateService.fromSeconds(1254005158),
dateService.fromSeconds(1254005159), "adrian@jclouds.org", false, false, 1, 254288,
MediaType.APPLICATION_OCTET_STREAM, true),
new FileMetadata("testfile.txt", URI
.create("https://pcsbeta.mezeo.net/v2/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3"),
dateService.fromSeconds(1254000180), dateService.fromSeconds(1254000181),
dateService.fromSeconds(1254000182), "adrian@jclouds.org", false, true, 3, 5,
MediaType.TEXT_PLAIN, false));
List<FileMetadata> result = (List<FileMetadata>) factory.create(
injector.getInstance(FileListToFileMetadataListHandler.class)).parse(is);
assertEquals(result, list);
}
}

View File

@ -0,0 +1,106 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.mezeo.pcs2.xml;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.easymock.classextension.EasyMock.createMock;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.URI;
import javax.inject.Singleton;
import javax.ws.rs.core.MediaType;
import org.jclouds.http.functions.BaseHandlerTest;
import org.jclouds.mezeo.pcs2.PCSUtil;
import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.util.DateService;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
/**
* Tests behavior of {@code FileListToFileMetadataListHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "pcs2.FileMetadataHandlerTest")
public class FileMetadataHandlerTest extends BaseHandlerTest {
private DateService dateService;
private PCSUtil util;
@BeforeTest
@Override
protected void setUpInjector() {
super.setUpInjector();
injector = injector.createChildInjector(new AbstractModule() {
@Override
protected void configure() {
}
@SuppressWarnings("unused")
@Singleton
@Provides
PCSUtil provideUtil() {
util = createMock(PCSUtil.class);
// Note that we should convert uppercase to lowercase!
expect(
util
.get(URI
.create("https://pcsbeta.mezeo.net/v2/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3/metadata/Foo")))
.andReturn("bar");
replay(util);
return util;
}
});
dateService = injector.getInstance(DateService.class);
assert dateService != null;
}
public void testFileMetadata() {
InputStream is = getClass().getResourceAsStream("/test_file_metadata.xml");
FileMetadata expects = new FileMetadata("testfile.txt", URI
.create("https://pcsbeta.mezeo.net/v2/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3"),
dateService.fromSeconds(1254000180), dateService.fromSeconds(1254000181),
dateService.fromSeconds(1254000182), "adrian@jclouds.org", false, true, 3, 5,
MediaType.TEXT_PLAIN, false);
// Note that we should convert uppercase to lowercase, since most clouds do anyway
expects.getUserMetadata().put("foo", "bar");
FileMetadata result = (FileMetadata) factory.create(
injector.getInstance(FileMetadataHandler.class)).parse(is);
verify(util);
assertEquals(result, expects);
}
}

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<file-list xmlns:xlink="http://www.w3.org/1999/xlink" count="3"
start="0" total="3">
<container
xlink:href="https://pcsbeta.mezeo.net/v2/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B"
xlink:type="simple">
<name>test1</name>
<created>1254008225</created>
<inproject>false</inproject>
<modified>1254008226</modified>
<owner>adrian@jclouds.org</owner>
<version>1</version>
<shared>true</shared>
<accessed>1254008227</accessed>
<bytes>1024</bytes>
<contents
xlink:href="https://pcsbeta.mezeo.net/v2/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B/contents"
xlink:type="simple" count="0" start="0" total="0" />
<tags
xlink:href="https://pcsbeta.mezeo.net/v2/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B/tags"
xlink:type="simple" />
<metadata
xlink:href="https://pcsbeta.mezeo.net/v2/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B/metadata"
xlink:type="simple" />
<parent
xlink:href="https://pcsbeta.mezeo.net/v2/containers/0B5C8F50-8E72-11DE-A1D4-D73479DA6257"
xlink:type="simple" />
</container>
<file
xlink:href="https://pcsbeta.mezeo.net/v2/files/5C81DADC-AAEE-11DE-9D55-B39340AEFF3A"
xlink:type="simple">
<name>more</name>
<created>1254005157</created>
<inproject>false</inproject>
<modified>1254005158</modified>
<owner>adrian@jclouds.org</owner>
<version>1</version>
<shared>false</shared>
<accessed>1254005159</accessed>
<public>true</public>
<mime_type>application/octet-stream</mime_type>
<bytes>254288</bytes>
<content
xlink:href="https://pcsbeta.mezeo.net/v2/files/5C81DADC-AAEE-11DE-9D55-B39340AEFF3A/content"
xlink:type="simple" />
<parent
xlink:href="https://pcsbeta.mezeo.net/v2/containers/0B5C8F50-8E72-11DE-A1D4-D73479DA6257"
xlink:type="simple" />
<permissions
xlink:href="https://pcsbeta.mezeo.net/v2/files/5C81DADC-AAEE-11DE-9D55-B39340AEFF3A/permissions"
xlink:type="simple" />
<tags
xlink:href="https://pcsbeta.mezeo.net/v2/files/5C81DADC-AAEE-11DE-9D55-B39340AEFF3A/tags"
xlink:type="simple" />
<metadata
xlink:href="https://pcsbeta.mezeo.net/v2/files/5C81DADC-AAEE-11DE-9D55-B39340AEFF3A/metadata"
xlink:type="simple" />
<thumbnail
xlink:href="https://pcsbeta.mezeo.net/v2/files/5C81DADC-AAEE-11DE-9D55-B39340AEFF3A/thumbnail"
xlink:type="simple" />
</file>
<file
xlink:href="https://pcsbeta.mezeo.net/v2/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3"
xlink:type="simple">
<name>testfile.txt</name>
<created>1254000180</created>
<inproject>true</inproject>
<modified>1254000181</modified>
<owner>adrian@jclouds.org</owner>
<version>3</version>
<shared>false</shared>
<accessed>1254000182</accessed>
<public>false</public>
<mime_type>text/plain</mime_type>
<bytes>5</bytes>
<content
xlink:href="https://pcsbeta.mezeo.net/v2/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3/content"
xlink:type="simple" />
<parent
xlink:href="https://pcsbeta.mezeo.net/v2/containers/0B5C8F50-8E72-11DE-A1D4-D73479DA6257"
xlink:type="simple" />
<permissions
xlink:href="https://pcsbeta.mezeo.net/v2/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3/permissions"
xlink:type="simple" />
<tags
xlink:href="https://pcsbeta.mezeo.net/v2/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3/tags"
xlink:type="simple" />
<metadata
xlink:href="https://pcsbeta.mezeo.net/v2/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3/metadata"
xlink:type="simple" />
<thumbnail
xlink:href="https://pcsbeta.mezeo.net/v2/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3/thumbnail"
xlink:type="simple" />
</file>
</file-list>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<file xmlns:xlink="http://www.w3.org/1999/xlink">
<name>testfile.txt</name>
<created>1254000180</created>
<inproject>true</inproject>
<modified>1254000181</modified>
<owner>adrian@jclouds.org</owner>
<version>3</version>
<shared>False</shared>
<accessed>1254000182</accessed>
<public>false</public>
<mime_type>text/plain</mime_type>
<bytes>5</bytes>
<content xlink:href="https://pcsbeta.mezeo.net/v2/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3/content" xlink:type="simple"/>
<parent xlink:href="https://pcsbeta.mezeo.net/v2/containers/0B5C8F50-8E72-11DE-A1D4-D73479DA6257" xlink:type="simple"/>
<permissions xlink:href="https://pcsbeta.mezeo.net/v2/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3/permissions" xlink:type="simple"/>
<tags xlink:href="https://pcsbeta.mezeo.net/v2/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3/tags" xlink:type="simple"/>
<metadata xlink:href="https://pcsbeta.mezeo.net/v2/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3/metadata" xlink:type="simple">
<metadata-item xlink:href="https://pcsbeta.mezeo.net/v2/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3/metadata/Foo" xlink:type="simple"/>
</metadata>
<thumbnail xlink:href="https://pcsbeta.mezeo.net/v2/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3/thumbnail" xlink:type="simple"/>
</file>

View File

@ -43,6 +43,7 @@
<jclouds.test.initializer>org.jclouds.mezeo.pcs2.integration.PCSTestInitializer</jclouds.test.initializer>
<jclouds.test.user>${jclouds.mezeo.pcs2.user}</jclouds.test.user>
<jclouds.test.key>${jclouds.mezeo.pcs2.password}</jclouds.test.key>
<jclouds.test.endpoint>${jclouds.mezeo.pcs2.endpoint}</jclouds.test.endpoint>
</properties>
<dependencies>
<dependency>