Issue 97: webdav compatible mapping. when slashes are present in blob names, create subfolders accordingly

git-svn-id: http://jclouds.googlecode.com/svn/trunk@1949 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2009-10-08 00:08:03 +00:00
parent c228add243
commit 22e949343e
31 changed files with 814 additions and 140 deletions

View File

@ -43,15 +43,17 @@ import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata; import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile; import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.mezeo.pcs2.endpoints.RootContainer; import org.jclouds.mezeo.pcs2.endpoints.RootContainer;
import org.jclouds.mezeo.pcs2.endpoints.WebDAV;
import org.jclouds.mezeo.pcs2.functions.AddMetadataAndParseResourceIdIntoBytes; import org.jclouds.mezeo.pcs2.functions.AddMetadataAndParseResourceIdIntoBytes;
import org.jclouds.mezeo.pcs2.functions.AssembleBlobFromContentAndMetadataCache; import org.jclouds.mezeo.pcs2.functions.AssembleBlobFromContentAndMetadataCache;
import org.jclouds.mezeo.pcs2.functions.CreateSubFolderIfNotExistsAndGetResourceId;
import org.jclouds.mezeo.pcs2.functions.ContainerAndFileNameToResourceId; import org.jclouds.mezeo.pcs2.functions.ContainerAndFileNameToResourceId;
import org.jclouds.mezeo.pcs2.functions.ContainerNameToResourceId; import org.jclouds.mezeo.pcs2.functions.ContainerNameToResourceId;
import org.jclouds.mezeo.pcs2.functions.InvalidateContainerNameCacheAndReturnTrueIf2xx; import org.jclouds.mezeo.pcs2.functions.InvalidateContainerNameCacheAndReturnTrueIf2xx;
import org.jclouds.mezeo.pcs2.functions.InvalidatePCSKeyCacheAndReturnVoidIf2xx; import org.jclouds.mezeo.pcs2.functions.InvalidatePCSKeyCacheAndReturnVoidIf2xx;
import org.jclouds.mezeo.pcs2.functions.ReturnFalseIfContainerNotFound; import org.jclouds.mezeo.pcs2.functions.ReturnFalseIfContainerNotFound;
import org.jclouds.mezeo.pcs2.functions.ReturnTrueIfContainerAlreadyExists; import org.jclouds.mezeo.pcs2.functions.ReturnTrueIfContainerAlreadyExists;
import org.jclouds.mezeo.pcs2.xml.FileListToContainerMetadataListHandler; import org.jclouds.mezeo.pcs2.xml.CachingFileListToContainerMetadataListHandler;
import org.jclouds.mezeo.pcs2.xml.FileListToFileMetadataListHandler; import org.jclouds.mezeo.pcs2.xml.FileListToFileMetadataListHandler;
import org.jclouds.mezeo.pcs2.xml.FileMetadataHandler; import org.jclouds.mezeo.pcs2.xml.FileMetadataHandler;
import org.jclouds.rest.Endpoint; import org.jclouds.rest.Endpoint;
@ -78,7 +80,7 @@ import org.jclouds.rest.XMLResponseParser;
public interface PCSBlobStore extends BlobStore<ContainerMetadata, FileMetadata, PCSFile> { public interface PCSBlobStore extends BlobStore<ContainerMetadata, FileMetadata, PCSFile> {
@GET @GET
@XMLResponseParser(FileListToContainerMetadataListHandler.class) @XMLResponseParser(CachingFileListToContainerMetadataListHandler.class)
@Headers(keys = "X-Cloud-Depth", values = "2") @Headers(keys = "X-Cloud-Depth", values = "2")
@Path("/contents") @Path("/contents")
@Endpoint(RootContainer.class) @Endpoint(RootContainer.class)
@ -117,8 +119,9 @@ public interface PCSBlobStore extends BlobStore<ContainerMetadata, FileMetadata,
@Path("/containers/{containerResourceId}/contents") @Path("/containers/{containerResourceId}/contents")
@Endpoint(PCS.class) @Endpoint(PCS.class)
@ResponseParser(AddMetadataAndParseResourceIdIntoBytes.class) @ResponseParser(AddMetadataAndParseResourceIdIntoBytes.class)
Future<byte[]> putBlob( @PathParam("containerResourceId")
@PathParam("containerResourceId") @ParamParser(ContainerNameToResourceId.class) String containerName, @ParamParser(CreateSubFolderIfNotExistsAndGetResourceId.class)
Future<byte[]> putBlob(String containerName,
@EntityParam(PCSFileAsMultipartFormBinder.class) PCSFile object); @EntityParam(PCSFileAsMultipartFormBinder.class) PCSFile object);
@DELETE @DELETE
@ -132,12 +135,10 @@ public interface PCSBlobStore extends BlobStore<ContainerMetadata, FileMetadata,
@GET @GET
@ExceptionParser(ThrowKeyNotFoundOn404.class) @ExceptionParser(ThrowKeyNotFoundOn404.class)
@Path("/files/{resourceId}/content") @Path("{container}/{key}")
@PathParam("resourceId") @Endpoint(WebDAV.class)
@Endpoint(PCS.class)
@ParamParser(ContainerAndFileNameToResourceId.class)
@ResponseParser(AssembleBlobFromContentAndMetadataCache.class) @ResponseParser(AssembleBlobFromContentAndMetadataCache.class)
Future<PCSFile> getBlob(String container, String key); Future<PCSFile> getBlob(@PathParam("container") String container, @PathParam("key") String key);
@GET @GET
@ExceptionParser(ThrowKeyNotFoundOn404.class) @ExceptionParser(ThrowKeyNotFoundOn404.class)

View File

@ -77,6 +77,11 @@ public interface PCSConnection {
@Endpoint(RootContainer.class) @Endpoint(RootContainer.class)
Future<URI> createContainer(@EntityParam(CreateContainerBinder.class) String container); Future<URI> createContainer(@EntityParam(CreateContainerBinder.class) String container);
@POST
@Path("/contents")
Future<URI> createContainer(@Endpoint URI parent, @EntityParam(CreateContainerBinder.class) String container);
@DELETE @DELETE
@ExceptionParser(ReturnVoidOnNotFoundOr404.class) @ExceptionParser(ReturnVoidOnNotFoundOr404.class)
Future<Void> deleteContainer(@Endpoint URI container); Future<Void> deleteContainer(@Endpoint URI container);
@ -87,6 +92,12 @@ public interface PCSConnection {
@Path("/contents") @Path("/contents")
Future<? extends SortedSet<FileMetadata>> listFiles(@Endpoint URI container); Future<? extends SortedSet<FileMetadata>> listFiles(@Endpoint URI container);
@GET
@XMLResponseParser(FileListToContainerMetadataListHandler.class)
@Headers(keys = "X-Cloud-Depth", values = "2")
@Path("/contents")
Future<? extends SortedSet<ContainerMetadata>> listContainers(@Endpoint URI container);
@POST @POST
@Path("/contents") @Path("/contents")
Future<URI> uploadFile(@Endpoint URI container, Future<URI> uploadFile(@Endpoint URI container,

View File

@ -24,18 +24,21 @@
package org.jclouds.mezeo.pcs2; package org.jclouds.mezeo.pcs2;
import java.net.URI; import java.net.URI;
import java.util.concurrent.Future;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.PUT; import javax.ws.rs.PUT;
import org.jclouds.http.filters.BasicAuthentication; import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.http.functions.ReturnFalseOn404; import org.jclouds.mezeo.pcs2.functions.AddEntryIntoMultiMap;
import org.jclouds.rest.Endpoint; import org.jclouds.rest.Endpoint;
import org.jclouds.rest.EntityParam; import org.jclouds.rest.EntityParam;
import org.jclouds.rest.ExceptionParser;
import org.jclouds.rest.RequestFilters; import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.ResponseParser;
import org.jclouds.rest.SkipEncoding; import org.jclouds.rest.SkipEncoding;
import com.google.common.collect.Multimap;
/** /**
* Provides access to Mezeo PCS v2 via their REST API. * Provides access to Mezeo PCS v2 via their REST API.
* <p/> * <p/>
@ -50,10 +53,9 @@ import org.jclouds.rest.SkipEncoding;
public interface PCSUtil { public interface PCSUtil {
@PUT @PUT
@ExceptionParser(ReturnFalseOn404.class) Future<Void> put(@Endpoint URI resource, @EntityParam String value);
boolean put(@Endpoint URI resource, @EntityParam String value);
@GET @GET
String get(@Endpoint URI resource); @ResponseParser(AddEntryIntoMultiMap.class)
Future<Void> addEntryToMultiMap(Multimap<String, String> map, String key, @Endpoint URI value);
} }

View File

@ -35,6 +35,8 @@ import org.jclouds.blobstore.domain.Blob;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.MultipartForm; import org.jclouds.http.MultipartForm;
import org.jclouds.http.MultipartForm.Part; import org.jclouds.http.MultipartForm.Part;
import org.jclouds.mezeo.pcs2.functions.Key;
import org.jclouds.mezeo.pcs2.util.PCSUtils;
import org.jclouds.rest.binders.EntityBinder; import org.jclouds.rest.binders.EntityBinder;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
@ -50,12 +52,11 @@ public class PCSFileAsMultipartFormBinder implements EntityBinder {
public void addEntityToRequest(Object entity, HttpRequest request) { public void addEntityToRequest(Object entity, HttpRequest request) {
Blob<?> object = (Blob<?>) entity; Blob<?> object = (Blob<?>) entity;
Key key = PCSUtils.parseKey(new Key("junk", object.getKey()));
Multimap<String, String> partHeaders = ImmutableMultimap.of("Content-Disposition", Multimap<String, String> partHeaders = ImmutableMultimap.of("Content-Disposition", String
String.format("form-data; name=\"%s\"; filename=\"%s\"", object.getKey(), object .format("form-data; name=\"%s\"; filename=\"%s\"", key.getKey(), key.getKey()),
.getKey()), HttpHeaders.CONTENT_TYPE, checkNotNull(object.getMetadata() HttpHeaders.CONTENT_TYPE, checkNotNull(object.getMetadata().getContentType(),
.getContentType(), "object.metadata.contentType()")); "object.metadata.contentType()"));
Object data = checkNotNull(object.getData(), "object.getData()"); Object data = checkNotNull(object.getData(), "object.getData()");
Part part; Part part;

View File

@ -88,7 +88,7 @@ public class PCSContextModule extends AbstractModule {
@Provides @Provides
@Singleton @Singleton
public ConcurrentMap<String, String> provideConcurrentMap(FindIdInContainerList finder) { public ConcurrentMap<String, String> provideConcurrentMap(FindIdInContainerList finder) {
return new MapMaker().concurrencyLevel(32).expiration(30, TimeUnit.SECONDS).makeComputingMap( return new MapMaker().expiration(30, TimeUnit.SECONDS).makeComputingMap(
finder); finder);
} }

View File

@ -52,6 +52,7 @@ import org.jclouds.mezeo.pcs2.endpoints.Recyclebin;
import org.jclouds.mezeo.pcs2.endpoints.RootContainer; import org.jclouds.mezeo.pcs2.endpoints.RootContainer;
import org.jclouds.mezeo.pcs2.endpoints.Shares; import org.jclouds.mezeo.pcs2.endpoints.Shares;
import org.jclouds.mezeo.pcs2.endpoints.Tags; import org.jclouds.mezeo.pcs2.endpoints.Tags;
import org.jclouds.mezeo.pcs2.endpoints.WebDAV;
import org.jclouds.mezeo.pcs2.handlers.PCSClientErrorRetryHandler; import org.jclouds.mezeo.pcs2.handlers.PCSClientErrorRetryHandler;
import org.jclouds.mezeo.pcs2.reference.PCSConstants; import org.jclouds.mezeo.pcs2.reference.PCSConstants;
import org.jclouds.rest.RestClientFactory; import org.jclouds.rest.RestClientFactory;
@ -99,7 +100,8 @@ public class RestPCSBlobStoreModule extends AbstractModule {
@Provides @Provides
@Singleton @Singleton
protected BlobStore<ContainerMetadata, FileMetadata, PCSFile> provideBlobStore(RestClientFactory factory) { protected BlobStore<ContainerMetadata, FileMetadata, PCSFile> provideBlobStore(
RestClientFactory factory) {
return factory.create(PCSBlobStore.class); return factory.create(PCSBlobStore.class);
} }
@ -117,6 +119,13 @@ public class RestPCSBlobStoreModule extends AbstractModule {
return URI.create(endpoint); return URI.create(endpoint);
} }
@Provides
@Singleton
@WebDAV
protected URI provideWebDAVURI(@Named(PCSConstants.PROPERTY_PCS2_ENDPOINT) String endpoint) {
return URI.create(endpoint.replaceAll("v2", "dav"));
}
@Provides @Provides
@Singleton @Singleton
@Contacts @Contacts

View File

@ -35,6 +35,7 @@ import org.joda.time.DateTime;
public class ContainerMetadata extends org.jclouds.blobstore.domain.ContainerMetadata implements public class ContainerMetadata extends org.jclouds.blobstore.domain.ContainerMetadata implements
PCSObject { PCSObject {
private URI url; private URI url;
private URI parent;
private DateTime created; private DateTime created;
private DateTime lastModified; private DateTime lastModified;
private DateTime accessed; private DateTime accessed;
@ -46,15 +47,15 @@ public class ContainerMetadata extends org.jclouds.blobstore.domain.ContainerMet
@Override @Override
public String toString() { public String toString() {
return "ContainerMetadata [name=" + name + ", url=" + url + ", accessed=" + accessed return "ContainerMetadata [name=" + name + ", url=" + url + ", parent=" + parent + ", owner="
+ ", bytes=" + bytes + ", created=" + created + ", isInProject=" + isInProject + owner + ", version=" + version + ", bytes=" + bytes + ", isInProject="
+ ", isShared=" + isShared + ", lastModified=" + lastModified + ", owner=" + owner + isInProject + ", isShared=" + isShared + ", created=" + created
+ ", version=" + version + "]"; + ", lastModified=" + lastModified + ", accessed=" + accessed + "]";
} }
@Override @Override
public int hashCode() { public int hashCode() {
int prime = 31; final int prime = 31;
int result = super.hashCode(); int result = super.hashCode();
result = prime * result + ((accessed == null) ? 0 : accessed.hashCode()); result = prime * result + ((accessed == null) ? 0 : accessed.hashCode());
result = prime * result + (int) (bytes ^ (bytes >>> 32)); result = prime * result + (int) (bytes ^ (bytes >>> 32));
@ -63,6 +64,7 @@ public class ContainerMetadata extends org.jclouds.blobstore.domain.ContainerMet
result = prime * result + (isShared ? 1231 : 1237); result = prime * result + (isShared ? 1231 : 1237);
result = prime * result + ((lastModified == null) ? 0 : lastModified.hashCode()); result = prime * result + ((lastModified == null) ? 0 : lastModified.hashCode());
result = prime * result + ((owner == null) ? 0 : owner.hashCode()); result = prime * result + ((owner == null) ? 0 : owner.hashCode());
result = prime * result + ((parent == null) ? 0 : parent.hashCode());
result = prime * result + ((url == null) ? 0 : url.hashCode()); result = prime * result + ((url == null) ? 0 : url.hashCode());
result = prime * result + version; result = prime * result + version;
return result; return result;
@ -103,6 +105,11 @@ public class ContainerMetadata extends org.jclouds.blobstore.domain.ContainerMet
return false; return false;
} else if (!owner.equals(other.owner)) } else if (!owner.equals(other.owner))
return false; return false;
if (parent == null) {
if (other.parent != null)
return false;
} else if (!parent.equals(other.parent))
return false;
if (url == null) { if (url == null) {
if (other.url != null) if (other.url != null)
return false; return false;
@ -112,15 +119,16 @@ public class ContainerMetadata extends org.jclouds.blobstore.domain.ContainerMet
return false; return false;
return true; return true;
} }
public ContainerMetadata() { public ContainerMetadata() {
super(); super();
} }
public ContainerMetadata(String name, URI url, DateTime created, DateTime lastModified, public ContainerMetadata(String name, URI url, URI parent, DateTime created,
DateTime accessed, String owner, boolean isShared, boolean isInProject, int version, DateTime lastModified, DateTime accessed, String owner, boolean isShared,
long bytes) { boolean isInProject, int version, long bytes) {
super(name); super(name);
this.setParent(parent);
this.url = url; this.url = url;
this.created = created; this.created = created;
this.lastModified = lastModified; this.lastModified = lastModified;
@ -168,4 +176,12 @@ public class ContainerMetadata extends org.jclouds.blobstore.domain.ContainerMet
return bytes; return bytes;
} }
public void setParent(URI parent) {
this.parent = parent;
}
public URI getParent() {
return parent;
}
} }

View File

@ -0,0 +1,44 @@
/**
*
* 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.endpoints;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
/**
* Related to a resource of type WebDAV
*
* @author Adrian Cole
*
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Qualifier
public @interface WebDAV {
}

View File

@ -0,0 +1,77 @@
package org.jclouds.mezeo.pcs2.functions;
import static com.google.common.base.Preconditions.checkState;
import java.lang.reflect.Constructor;
import javax.inject.Inject;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ReturnStringIf200;
import org.jclouds.rest.RestContext;
import com.google.common.base.Function;
import com.google.common.collect.Multimap;
/**
*
* @author Adrian Cole
*/
public class AddEntryIntoMultiMap implements Function<HttpResponse, Void>, RestContext {
ReturnStringIf200 returnIf200;
@Inject
private AddEntryIntoMultiMap(ReturnStringIf200 returnIf200) {
this.returnIf200 = returnIf200;
}
private Object[] args;
private HttpRequest request;
static final Void v;
static {
Constructor<Void> cv;
try {
cv = Void.class.getDeclaredConstructor();
cv.setAccessible(true);
v = cv.newInstance();
} catch (Exception e) {
throw new Error("Error setting up class", e);
}
}
@SuppressWarnings("unchecked")
public Void apply(HttpResponse from)
{
checkState(args != null, "args should be initialized at this point");
Multimap<String, String> map = null;
String key = null;
for (Object arg : args) {
if (arg instanceof Multimap)
map = (Multimap<String, String>) arg;
else if (arg instanceof String)
key = arg.toString();
}
checkState(map != null, "No Multimap found in args, improper method declarations");
checkState(key != null, "No String found in args, improper method declarations");
map.put(key, returnIf200.apply(from).trim());
return v;
}
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

@ -27,12 +27,18 @@ import static com.google.common.base.Preconditions.checkState;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.util.Set;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilder;
import org.jclouds.blobstore.internal.BlobRuntimeException;
import org.jclouds.blobstore.reference.BlobStoreConstants;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
@ -44,6 +50,7 @@ import org.jclouds.rest.RestContext;
import org.jclouds.util.Utils; import org.jclouds.util.Utils;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.collect.Sets;
/** /**
* PCS does not return an eTag header. As such, we'll make one out of the object id. * PCS does not return an eTag header. As such, we'll make one out of the object id.
@ -58,6 +65,13 @@ public class AddMetadataAndParseResourceIdIntoBytes implements Function<HttpResp
private Object[] args; private Object[] args;
private HttpRequest request; private HttpRequest request;
/**
* maximum duration of an blob Request
*/
@Inject(optional = true)
@Named(BlobStoreConstants.PROPERTY_BLOBSTORE_TIMEOUT)
protected long requestTimeoutMilliseconds = 30000;
@Inject @Inject
public AddMetadataAndParseResourceIdIntoBytes(PCSUtil util) { public AddMetadataAndParseResourceIdIntoBytes(PCSUtil util) {
this.util = util; this.util = util;
@ -77,11 +91,22 @@ public class AddMetadataAndParseResourceIdIntoBytes implements Function<HttpResp
String toParse = Utils.toStringAndClose(from.getContent()); String toParse = Utils.toStringAndClose(from.getContent());
logger.trace("%s: received the following response: %s", from, toParse); logger.trace("%s: received the following response: %s", from, toParse);
URI uri = URI.create(toParse.trim()); URI uri = URI.create(toParse.trim());
Set<Future<Void>> puts = Sets.newHashSet();
for (Entry<String, String> entry : file.getMetadata().getUserMetadata().entries()) { for (Entry<String, String> entry : file.getMetadata().getUserMetadata().entries()) {
URI key = UriBuilder.fromUri(uri).path(String.format("metadata/%s", entry.getKey())) URI key = UriBuilder.fromUri(uri).path(String.format("metadata/%s", entry.getKey()))
.build(); .build();
util.put(key, entry.getValue()); puts.add(util.put(key, entry.getValue()));
} }
for (Future<Void> put : puts) {
try {
put.get(requestTimeoutMilliseconds, TimeUnit.MILLISECONDS);
} catch (Exception e) {
Utils.<BlobRuntimeException> rethrowIfRuntimeOrSameType(e);
throw new BlobRuntimeException("Error putting metadata for file: " + file, e);
}
}
return PCSUtils.getEtag(uri); return PCSUtils.getEtag(uri);
} catch (IOException e) { } catch (IOException e) {
throw new HttpResponseException("couldn't parse url from response", null, from, e); throw new HttpResponseException("couldn't parse url from response", null, from, e);

View File

@ -59,9 +59,9 @@ public class ContainerAndFileNameToResourceId implements Function<Object, String
Object[] args = (Object[]) from; Object[] args = (Object[]) from;
checkArgument(args[0] instanceof String, "arg[0] must be a container name"); 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)"); checkArgument(args[1] instanceof String, "arg[1] must be a pcsfile name (key)");
String container = args[0].toString(); String container = args[0].toString();
String key = args[1].toString(); String key = args[1].toString();
try { try {
return cachedFinder.get(new Key(container, key)); return cachedFinder.get(new Key(container, key));
} catch (ComputationException e) { } catch (ComputationException e) {

View File

@ -0,0 +1,140 @@
/**
*
* 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.net.URI;
import java.util.SortedSet;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.internal.BlobRuntimeException;
import org.jclouds.blobstore.reference.BlobStoreConstants;
import org.jclouds.mezeo.pcs2.PCSConnection;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.endpoints.RootContainer;
import org.jclouds.mezeo.pcs2.util.PCSUtils;
import org.jclouds.util.Utils;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.collect.ComputationException;
/**
*
* @author Adrian Cole
*/
@Singleton
public class CreateSubFolderIfNotExistsAndGetResourceId implements Function<Object, String> {
/**
* maximum duration of an blob Request
*/
@Inject(optional = true)
@Named(BlobStoreConstants.PROPERTY_BLOBSTORE_TIMEOUT)
protected long requestTimeoutMilliseconds = 30000;
private final ConcurrentMap<String, String> finder;
private final PCSConnection blobStore;
private final URI rootContainer;
@Inject
public CreateSubFolderIfNotExistsAndGetResourceId(PCSConnection blobStore,
ConcurrentMap<String, String> finder, @RootContainer URI rootContainer) {
this.finder = finder;
this.blobStore = blobStore;
this.rootContainer = rootContainer;
}
@SuppressWarnings("unchecked")
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 Blob, "arg[1] must be a pcsfile");
Key key = PCSUtils.parseKey(new Key(args[0].toString(), ((Blob) args[1]).getKey()));
try {
return finder.get(key.getContainer());
} catch (ComputationException e) {
if (e.getCause() instanceof ContainerNotFoundException) {
String[] containerTree = key.getContainer().split("/");
SortedSet<ContainerMetadata> response = blobStore.listContainers();
URI containerUri;
try {
containerUri = urlForNameInListOrCreate(rootContainer, containerTree[0],
response);
} catch (Exception e1) {
Utils.<ContainerNotFoundException> rethrowIfRuntimeOrSameType(e1);
throw new BlobRuntimeException("error creating container at: " + containerTree[0], e1);
}
if (containerTree.length != 1) {
for (int i = 1; i < containerTree.length; i++) {
try {
response = blobStore.listContainers(containerUri).get(
requestTimeoutMilliseconds, TimeUnit.MILLISECONDS);
containerUri = urlForNameInListOrCreate(containerUri, containerTree[i],
response);
} catch (Exception e2) {
Utils.<ContainerNotFoundException> rethrowIfRuntimeOrSameType(e2);
throw new BlobRuntimeException("error listing container at: " + containerUri,
e2);
}
}
}
return PCSUtils.getContainerId(containerUri);
}
Utils.<ContainerNotFoundException> rethrowIfRuntimeOrSameType(e);
throw e;
}
}
@VisibleForTesting
URI urlForNameInListOrCreate(URI parent, String toFind,
SortedSet<ContainerMetadata> containerMetadataList) throws InterruptedException,
ExecutionException, TimeoutException {
for (ContainerMetadata data : containerMetadataList) {
if (toFind.equals(data.getName())) {
return data.getUrl();
}
}
return blobStore.createContainer(parent, toFind).get(requestTimeoutMilliseconds,
TimeUnit.MILLISECONDS);
}
}

View File

@ -23,38 +23,76 @@
*/ */
package org.jclouds.mezeo.pcs2.functions; package org.jclouds.mezeo.pcs2.functions;
import java.net.URI;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
import org.jclouds.blobstore.ContainerNotFoundException; import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.internal.BlobRuntimeException;
import org.jclouds.blobstore.reference.BlobStoreConstants;
import org.jclouds.mezeo.pcs2.PCSConnection; import org.jclouds.mezeo.pcs2.PCSConnection;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata; import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.endpoints.RootContainer;
import org.jclouds.mezeo.pcs2.util.PCSUtils;
import org.jclouds.util.Utils;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function; import com.google.common.base.Function;
public class FindIdInContainerList implements Function<String, String> { public class FindIdInContainerList implements Function<String, String> {
private PCSConnection connection; private final PCSConnection connection;
private final URI rootContainerUri;
/**
* maximum duration of an blob Request
*/
@Inject(optional = true)
@Named(BlobStoreConstants.PROPERTY_BLOBSTORE_TIMEOUT)
protected long requestTimeoutMilliseconds = 30000;
@Inject @Inject
public FindIdInContainerList(PCSConnection connection) { public FindIdInContainerList(PCSConnection connection, @RootContainer URI rootContainerURI) {
this.connection = connection; this.connection = connection;
this.rootContainerUri = rootContainerURI;
} }
public String apply(String key) { public String apply(String key) {
SortedSet<ContainerMetadata> response = connection.listContainers(); String[] containerTree = key.split("/");
return idForNameInListOrException(key, response); URI containerUri = rootContainerUri;
try {
containerUri = urlForNameInListOrException(containerTree[0], rootContainerUri, connection
.listContainers(rootContainerUri).get(requestTimeoutMilliseconds,
TimeUnit.MILLISECONDS));
if (containerTree.length != 1) {
for (int i = 1; i < containerTree.length; i++) {
containerUri = urlForNameInListOrException(containerTree[i], containerUri,
listContainers(containerUri));
}
}
return PCSUtils.getContainerId(containerUri);
} catch (Exception e) {
Utils.<ContainerNotFoundException> rethrowIfRuntimeOrSameType(e);
throw new BlobRuntimeException("error listing container at: " + containerUri, e);
}
}
private SortedSet<ContainerMetadata> listContainers(URI containerUri)
throws InterruptedException, ExecutionException, TimeoutException {
return connection.listContainers(containerUri).get(requestTimeoutMilliseconds,
TimeUnit.MILLISECONDS);
} }
@VisibleForTesting @VisibleForTesting
String idForNameInListOrException(String toFind, URI urlForNameInListOrException(String toFind, URI parent,
SortedSet<ContainerMetadata> containerMetadataList) { SortedSet<ContainerMetadata> containerMetadataList) {
for (ContainerMetadata data : containerMetadataList) { for (ContainerMetadata data : containerMetadataList) {
if (toFind.equals(data.getName())) { if (toFind.equals(data.getName()) && parent.equals(data.getParent())) {
String path = data.getUrl().getPath(); return data.getUrl();
int indexAfterContainersSlash = path.indexOf("containers/") + "containers/".length();
return path.substring(indexAfterContainersSlash);
} }
} }
throw new ContainerNotFoundException(toFind); throw new ContainerNotFoundException(toFind);

View File

@ -36,6 +36,7 @@ import org.jclouds.http.HttpException;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata; import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata; import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile; import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.mezeo.pcs2.util.PCSUtils;
import org.jclouds.util.Utils; import org.jclouds.util.Utils;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
@ -50,6 +51,7 @@ public class FindIdInFileList implements Function<Key, String> {
} }
public String apply(Key key) { public String apply(Key key) {
key = PCSUtils.parseKey(key);
SortedSet<FileMetadata> response; SortedSet<FileMetadata> response;
try { try {
response = connection.listBlobs(key.getContainer()).get(10, TimeUnit.SECONDS); response = connection.listBlobs(key.getContainer()).get(10, TimeUnit.SECONDS);

View File

@ -26,6 +26,7 @@ package org.jclouds.mezeo.pcs2.util;
import java.net.URI; import java.net.URI;
import org.jclouds.http.HttpUtils; import org.jclouds.http.HttpUtils;
import org.jclouds.mezeo.pcs2.functions.Key;
/** /**
* Utilities for PCS connections. * Utilities for PCS connections.
@ -44,4 +45,20 @@ public class PCSUtils {
return eTag; return eTag;
} }
public static Key parseKey(Key key) {
if (key.getKey().indexOf('/') != -1) {
String container = key.getContainer() + '/'
+ key.getKey().substring(0, key.getKey().lastIndexOf('/'));
String newKey = key.getKey().substring(key.getKey().lastIndexOf('/')+1);
key = new Key(container.replaceAll("//", "/"), newKey);
}
return key;
}
public static String getContainerId(URI url) {
String path = url.getPath();
int indexAfterContainersSlash = path.indexOf("containers/") + "containers/".length();
return path.substring(indexAfterContainersSlash);
}
} }

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.xml;
import java.util.SortedSet;
import java.util.concurrent.ConcurrentMap;
import javax.inject.Inject;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.util.PCSUtils;
import org.jclouds.util.DateService;
/**
* @author Adrian Cole
*/
public class CachingFileListToContainerMetadataListHandler extends
FileListToContainerMetadataListHandler {
private final ConcurrentMap<String, String> cache;
@Inject
public CachingFileListToContainerMetadataListHandler(ConcurrentMap<String, String> cache,
DateService dateParser) {
super(dateParser);
this.cache = cache;
}
@Override
public SortedSet<ContainerMetadata> getResult() {
SortedSet<ContainerMetadata> result = super.getResult();
for (ContainerMetadata md : result) {
cache.put(md.getName(), PCSUtils.getContainerId(md.getUrl()));
}
return result;
}
}

View File

@ -26,9 +26,11 @@ package org.jclouds.mezeo.pcs2.xml;
import java.net.URI; import java.net.URI;
import java.util.SortedSet; import java.util.SortedSet;
import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.logging.Logger;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata; import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.util.DateService; import org.jclouds.util.DateService;
import org.joda.time.DateTime; import org.joda.time.DateTime;
@ -43,6 +45,20 @@ import com.google.common.collect.Sets;
public class FileListToContainerMetadataListHandler extends public class FileListToContainerMetadataListHandler extends
ParseSax.HandlerWithResult<SortedSet<ContainerMetadata>> { ParseSax.HandlerWithResult<SortedSet<ContainerMetadata>> {
@Override
public String toString() {
return "FileListToContainerMetadataListHandler [containerMetadata=" + containerMetadata
+ ", currentAccessed=" + currentAccessed + ", currentBytes=" + currentBytes
+ ", currentCreated=" + currentCreated + ", currentInproject=" + currentInproject
+ ", currentModified=" + currentModified + ", currentName=" + currentName
+ ", currentOwner=" + currentOwner + ", currentShared=" + currentShared
+ ", currentText=" + currentText + ", currentUrl=" + currentUrl
+ ", currentVersion=" + currentVersion + ", dateParser=" + dateParser + "]";
}
@Resource
protected Logger logger = Logger.NULL;
private SortedSet<ContainerMetadata> containerMetadata = Sets.newTreeSet(); private SortedSet<ContainerMetadata> containerMetadata = Sets.newTreeSet();
private URI currentUrl; private URI currentUrl;
private String currentName; private String currentName;
@ -59,6 +75,11 @@ public class FileListToContainerMetadataListHandler extends
private final DateService dateParser; private final DateService dateParser;
boolean inContainer = false;
boolean ignore = false;
private URI currentParent;
@Inject @Inject
public FileListToContainerMetadataListHandler(DateService dateParser) { public FileListToContainerMetadataListHandler(DateService dateParser) {
this.dateParser = dateParser; this.dateParser = dateParser;
@ -72,16 +93,54 @@ public class FileListToContainerMetadataListHandler extends
public void startElement(String uri, String localName, String qName, Attributes attributes) public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException { throws SAXException {
if (qName.equals("container")) { if (qName.equals("container")) {
if (inContainer) {
ignore = true;
return;
}
inContainer = true;
int index = attributes.getIndex("xlink:href"); int index = attributes.getIndex("xlink:href");
if (index != -1) { if (index != -1) {
currentUrl = URI.create(attributes.getValue(index)); currentUrl = URI.create(attributes.getValue(index));
} }
} else if (qName.equals("parent") && !ignore) {
int index = attributes.getIndex("xlink:href");
if (index != -1) {
currentParent = URI.create(attributes.getValue(index));
}
} }
} }
@Override @Override
public void endElement(String uri, String name, String qName) { public void endElement(String uri, String name, String qName) {
if (qName.equals("name")) { if (ignore) {
currentText = new StringBuilder();
if (qName.equals("container")) {
ignore = false;
}
return;
}
if (qName.equals("container")) {
inContainer = false;
try {
containerMetadata.add(new ContainerMetadata(currentName, currentUrl, currentParent,
currentCreated, currentModified, currentAccessed, currentOwner, currentShared,
currentInproject, currentVersion, currentBytes));
} catch (RuntimeException e) {
logger.error(e, "error creating object! current state %s", this);
throw e;
}
currentUrl = null;
currentParent = null;
currentName = null;
currentCreated = null;
currentInproject = false;
currentModified = null;
currentOwner = null;
currentVersion = 0;
currentShared = false;
currentAccessed = null;
currentBytes = 0;
} else if (qName.equals("name")) {
currentName = currentText.toString().trim(); currentName = currentText.toString().trim();
} else if (qName.equals("created")) { } else if (qName.equals("created")) {
currentCreated = dateParser.fromSeconds(Long.parseLong(currentText.toString().trim())); currentCreated = dateParser.fromSeconds(Long.parseLong(currentText.toString().trim()));
@ -99,21 +158,6 @@ public class FileListToContainerMetadataListHandler extends
currentAccessed = dateParser.fromSeconds(Long.parseLong(currentText.toString().trim())); currentAccessed = dateParser.fromSeconds(Long.parseLong(currentText.toString().trim()));
} else if (qName.equals("bytes")) { } else if (qName.equals("bytes")) {
currentBytes = Long.parseLong(currentText.toString().trim()); 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(); currentText = new StringBuilder();
} }

View File

@ -24,17 +24,25 @@
package org.jclouds.mezeo.pcs2.xml; package org.jclouds.mezeo.pcs2.xml;
import java.net.URI; import java.net.URI;
import java.util.Set;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
import org.jclouds.blobstore.internal.BlobRuntimeException;
import org.jclouds.blobstore.reference.BlobStoreConstants;
import org.jclouds.mezeo.pcs2.PCSUtil; import org.jclouds.mezeo.pcs2.PCSUtil;
import org.jclouds.mezeo.pcs2.domain.FileMetadata; import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.util.DateService; import org.jclouds.util.DateService;
import org.jclouds.util.Utils;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
/** /**
* @author Adrian Cole * @author Adrian Cole
@ -43,6 +51,13 @@ public class FileMetadataHandler extends BaseFileMetadataHandler<FileMetadata> {
private final PCSUtil util; private final PCSUtil util;
private FileMetadata fileMetadata = null; private FileMetadata fileMetadata = null;
protected Multimap<String, String> userMetadata = HashMultimap.create(); protected Multimap<String, String> userMetadata = HashMultimap.create();
Set<Future<Void>> puts = Sets.newHashSet();
/**
* maximum duration of an blob Request
*/
@Inject(optional = true)
@Named(BlobStoreConstants.PROPERTY_BLOBSTORE_TIMEOUT)
protected long requestTimeoutMilliseconds = 30000;
@Inject @Inject
public FileMetadataHandler(PCSUtil util, DateService dateParser) { public FileMetadataHandler(PCSUtil util, DateService dateParser) {
@ -51,6 +66,14 @@ public class FileMetadataHandler extends BaseFileMetadataHandler<FileMetadata> {
} }
public FileMetadata getResult() { public FileMetadata getResult() {
for (Future<Void> put : puts) {
try {
put.get(requestTimeoutMilliseconds, TimeUnit.MILLISECONDS);
} catch (Exception e) {
Utils.<BlobRuntimeException> rethrowIfRuntimeOrSameType(e);
throw new BlobRuntimeException("Error getting metadata", e);
}
}
return fileMetadata; return fileMetadata;
} }
@ -66,8 +89,8 @@ public class FileMetadataHandler extends BaseFileMetadataHandler<FileMetadata> {
int index = attributes.getIndex("xlink:href"); int index = attributes.getIndex("xlink:href");
if (index != -1) { if (index != -1) {
String key = attributes.getValue(index).replaceAll(".*/metadata/", ""); String key = attributes.getValue(index).replaceAll(".*/metadata/", "");
String value = util.get(URI.create(attributes.getValue(index))).trim(); puts.add(util.addEntryToMultiMap(userMetadata, key.toLowerCase(), URI.create(attributes
userMetadata.put(key.toLowerCase(), value); .getValue(index))));
} }
} }
} }

View File

@ -51,15 +51,16 @@ import org.jclouds.http.HttpRequest;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule; import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.http.filters.BasicAuthentication; import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.http.functions.ParseSax; 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.functions.ReturnTrueIf2xx;
import org.jclouds.http.functions.ReturnVoidIf2xx;
import org.jclouds.http.options.GetOptions; import org.jclouds.http.options.GetOptions;
import org.jclouds.mezeo.pcs2.binders.PCSFileAsMultipartFormBinderTest; import org.jclouds.mezeo.pcs2.binders.PCSFileAsMultipartFormBinderTest;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata; import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata; import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile; import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.mezeo.pcs2.endpoints.RootContainer; import org.jclouds.mezeo.pcs2.endpoints.RootContainer;
import org.jclouds.mezeo.pcs2.endpoints.WebDAV;
import org.jclouds.mezeo.pcs2.functions.AddEntryIntoMultiMap;
import org.jclouds.mezeo.pcs2.functions.AddMetadataAndParseResourceIdIntoBytes; import org.jclouds.mezeo.pcs2.functions.AddMetadataAndParseResourceIdIntoBytes;
import org.jclouds.mezeo.pcs2.functions.AssembleBlobFromContentAndMetadataCache; import org.jclouds.mezeo.pcs2.functions.AssembleBlobFromContentAndMetadataCache;
import org.jclouds.mezeo.pcs2.functions.InvalidateContainerNameCacheAndReturnTrueIf2xx; import org.jclouds.mezeo.pcs2.functions.InvalidateContainerNameCacheAndReturnTrueIf2xx;
@ -72,7 +73,9 @@ import org.jclouds.util.Utils;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Multimap;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
@ -124,6 +127,8 @@ public class PCSBlobStoreTest {
return ImmutableSortedSet return ImmutableSortedSet
.of(new ContainerMetadata( .of(new ContainerMetadata(
"mycontainer", "mycontainer",
URI
.create("https://pcsbeta.mezeo.net/v2/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B"),
URI URI
.create("https://pcsbeta.mezeo.net/v2/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B"), .create("https://pcsbeta.mezeo.net/v2/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B"),
dateService.fromSeconds(1254008225), dateService.fromSeconds(1254008225),
@ -180,6 +185,14 @@ public class PCSBlobStoreTest {
return null; return null;
} }
public Future<? extends SortedSet<ContainerMetadata>> listContainers(URI container) {
throw new UnsupportedOperationException();
}
public Future<URI> createContainer(URI parent, String container) {
throw new UnsupportedOperationException();
}
} }
public void testListContainers() throws SecurityException, NoSuchMethodException { public void testListContainers() throws SecurityException, NoSuchMethodException {
@ -311,8 +324,7 @@ public class PCSBlobStoreTest {
HttpRequest httpMethod = processor.createRequest(method, new Object[] { "mycontainer", HttpRequest httpMethod = processor.createRequest(method, new Object[] { "mycontainer",
"testfile.txt" }); "testfile.txt" });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost"); assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), assertEquals(httpMethod.getEndpoint().getPath(), "/webdav/mycontainer/testfile.txt");
"/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3/content");
assertEquals(httpMethod.getEndpoint().getQuery(), null); assertEquals(httpMethod.getEndpoint().getQuery(), null);
assertEquals(httpMethod.getMethod(), HttpMethod.GET); assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0); assertEquals(httpMethod.getHeaders().size(), 0);
@ -372,24 +384,25 @@ public class PCSBlobStoreTest {
assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_TYPE), Collections assertEquals(httpMethod.getHeaders().get(HttpHeaders.CONTENT_TYPE), Collections
.singletonList("application/unknown")); .singletonList("application/unknown"));
assertEquals("bar", httpMethod.getEntity()); assertEquals("bar", httpMethod.getEntity());
assertEquals(processor.createExceptionParserOrNullIfNotFound(method).getClass(), assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
ReturnFalseOn404.class);
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(), assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
ReturnTrueIf2xx.class); ReturnVoidIf2xx.class);
} }
public void testGetMetadata() throws SecurityException, NoSuchMethodException { public void testAddEntryToMultiMap() throws SecurityException, NoSuchMethodException {
Method method = PCSUtil.class.getMethod("get", URI.class); Method method = PCSUtil.class.getMethod("addEntryToMultiMap", Multimap.class, String.class,
URI.class);
HttpRequest httpMethod = utilProcessor.createRequest(method, new Object[] { HttpRequest httpMethod = utilProcessor
URI.create("http://localhost/pow"), "foo" }); .createRequest(method, new Object[] { ImmutableMultimap.of("key", "value"),
"newkey", URI.create("http://localhost/pow") });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost"); assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/pow"); assertEquals(httpMethod.getEndpoint().getPath(), "/pow");
assertEquals(httpMethod.getMethod(), HttpMethod.GET); assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 0); assertEquals(httpMethod.getHeaders().size(), 0);
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null); assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(), assertEquals(processor.createResponseParser(method, httpMethod, null).getClass(),
ReturnStringIf200.class); AddEntryIntoMultiMap.class);
} }
JaxrsAnnotationProcessor<PCSBlobStore> processor; JaxrsAnnotationProcessor<PCSBlobStore> processor;
@ -406,6 +419,9 @@ public class PCSBlobStoreTest {
URI.create("http://localhost:8080")); URI.create("http://localhost:8080"));
bind(URI.class).annotatedWith(RootContainer.class).toInstance( bind(URI.class).annotatedWith(RootContainer.class).toInstance(
URI.create("http://localhost:8080/root")); URI.create("http://localhost:8080/root"));
bind(URI.class).annotatedWith(WebDAV.class).toInstance(
URI.create("http://localhost:8080/webdav"));
bind(PCSConnection.class).to(StubPCSConnection.class).asEagerSingleton();
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
@ -414,12 +430,13 @@ public class PCSBlobStoreTest {
public PCSUtil getPCSUtil() { public PCSUtil getPCSUtil() {
return new PCSUtil() { return new PCSUtil() {
public String get(URI resource) { public Future<Void> put(URI resource, String value) {
return null; return null;
} }
public boolean put(URI resource, String value) { public Future<Void> addEntryToMultiMap(Multimap<String, String> map,
return true; String key, URI value) {
return null;
} }
}; };

View File

@ -102,14 +102,14 @@ public class PCSConnectionLiveTest {
public void testObjectOperations() throws Exception { public void testObjectOperations() throws Exception {
String containerName = containerPrefix + ".testObjectOperations"; String containerName = containerPrefix + ".testObjectOperations";
String data = "Here is my data"; String data = "Here is my data";
URI container = connection.createContainer(containerName).get(10, TimeUnit.SECONDS); URI container = connection.createContainer(containerName).get(10, TimeUnit.SECONDS);
// Test PUT with string data, ETag hash, and a piece of metadata // Test PUT with string data, ETag hash, and a piece of metadata
PCSFile object = new PCSFile("object"); PCSFile object = new PCSFile("object");
object.setData(data); object.setData(data);
object.setContentLength(data.length()); object.setContentLength(data.length());
URI objectURI = connection.uploadFile(container, object).get(10, TimeUnit.SECONDS); URI objectURI = connection.uploadFile(container, object).get(30, TimeUnit.SECONDS);
try { try {
connection.downloadFile(UriBuilder.fromUri(objectURI).path("sad").build()).get(10, connection.downloadFile(UriBuilder.fromUri(objectURI).path("sad").build()).get(10,

View File

@ -33,6 +33,7 @@ import java.net.URI;
import java.util.Collections; import java.util.Collections;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Future;
import javax.inject.Singleton; import javax.inject.Singleton;
import javax.ws.rs.HttpMethod; import javax.ws.rs.HttpMethod;
@ -58,6 +59,7 @@ import org.jclouds.util.Utils;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.Multimap;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
@ -141,6 +143,23 @@ public class PCSConnectionTest {
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null); assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
} }
public void testListContainersURI() throws SecurityException, NoSuchMethodException {
Method method = PCSConnection.class.getMethod("listContainers", URI.class);
HttpRequest httpMethod = processor.createRequest(method, new Object[] { URI
.create("http://localhost/mycontainer") });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/mycontainer/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 testUploadFile() throws SecurityException, NoSuchMethodException, IOException { public void testUploadFile() throws SecurityException, NoSuchMethodException, IOException {
Method method = PCSConnection.class.getMethod("uploadFile", URI.class, PCSFile.class); Method method = PCSConnection.class.getMethod("uploadFile", URI.class, PCSFile.class);
@ -214,12 +233,13 @@ public class PCSConnectionTest {
public PCSUtil getPCSUtil() { public PCSUtil getPCSUtil() {
return new PCSUtil() { return new PCSUtil() {
public String get(URI resource) { public Future<Void> put(URI resource, String value) {
return null; return null;
} }
public boolean put(URI resource, String value) { public Future<Void> addEntryToMultiMap(Multimap<String, String> map,
return true; String key, URI value) {
return null;
} }
}; };

View File

@ -35,6 +35,7 @@ import org.jclouds.mezeo.pcs2.PCSConnection;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata; import org.jclouds.mezeo.pcs2.domain.ContainerMetadata;
import org.jclouds.mezeo.pcs2.domain.FileMetadata; import org.jclouds.mezeo.pcs2.domain.FileMetadata;
import org.jclouds.mezeo.pcs2.domain.PCSFile; import org.jclouds.mezeo.pcs2.domain.PCSFile;
import org.jclouds.mezeo.pcs2.endpoints.RootContainer;
import org.jclouds.mezeo.pcs2.internal.StubPCSConnection; import org.jclouds.mezeo.pcs2.internal.StubPCSConnection;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
@ -58,6 +59,7 @@ public class StubPCSBlobStoreModule extends AbstractModule {
}).asEagerSingleton(); }).asEagerSingleton();
bind(PCSConnection.class).to(StubPCSConnection.class).asEagerSingleton(); bind(PCSConnection.class).to(StubPCSConnection.class).asEagerSingleton();
bind(URI.class).annotatedWith(PCS.class).toInstance(URI.create("https://localhost/pcsblob")); bind(URI.class).annotatedWith(PCS.class).toInstance(URI.create("https://localhost/pcsblob"));
bind(URI.class).annotatedWith(RootContainer.class).toInstance(
URI.create("http://localhost/root"));
} }
} }

View File

@ -31,6 +31,7 @@ import static org.easymock.classextension.EasyMock.verify;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.net.URI; import java.net.URI;
import java.util.concurrent.Future;
import javax.ws.rs.ext.RuntimeDelegate; import javax.ws.rs.ext.RuntimeDelegate;
@ -55,20 +56,22 @@ public class AddMetadataAndParseResourceIdIntoBytesTest {
} }
HttpResponse response = new HttpResponse(); HttpResponse response = new HttpResponse();
@SuppressWarnings("unchecked")
PCSUtil createPCSUtil() { PCSUtil createPCSUtil() {
PCSUtil connection = createMock(PCSUtil.class); PCSUtil connection = createMock(PCSUtil.class);
final Future<Void> voidF = createMock(Future.class);
expect( expect(
connection connection
.put( .put(
eq(URI eq(URI
.create("http://localhost/contents/7F143552-AAF5-11DE-BBB0-0BC388ED913B/metadata/foo")), .create("http://localhost/contents/7F143552-AAF5-11DE-BBB0-0BC388ED913B/metadata/foo")),
eq("bar"))).andReturn(true); eq("bar"))).andReturn(voidF);
expect( expect(
connection connection
.put( .put(
eq(URI eq(URI
.create("http://localhost/contents/7F143552-AAF5-11DE-BBB0-0BC388ED913B/metadata/biz")), .create("http://localhost/contents/7F143552-AAF5-11DE-BBB0-0BC388ED913B/metadata/biz")),
eq("baz"))).andReturn(true); eq("baz"))).andReturn(voidF);
replay(connection); replay(connection);
return connection; return connection;
} }

View File

@ -23,14 +23,21 @@
*/ */
package org.jclouds.mezeo.pcs2.functions; package org.jclouds.mezeo.pcs2.functions;
import static org.easymock.classextension.EasyMock.createNiceMock;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.util.SortedSet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.jclouds.blobstore.ContainerNotFoundException; import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.mezeo.pcs2.PCSConnection; import org.jclouds.mezeo.pcs2.PCSConnection;
import org.jclouds.mezeo.pcs2.domain.ContainerMetadata; 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; import org.jclouds.util.DateService;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -44,25 +51,104 @@ import com.google.common.collect.ImmutableSortedSet;
@Test(groups = "unit", testName = "pcs2.FindIdInContainerList") @Test(groups = "unit", testName = "pcs2.FindIdInContainerList")
public class FindIdInContainerListTest { public class FindIdInContainerListTest {
private DateService dateService = new DateService(); private DateService dateService = new DateService();
private final PCSConnection connection = new PCSConnection() {
private final ImmutableSortedSet<ContainerMetadata> OF = ImmutableSortedSet public Future<URI> createContainer(String container) {
.of(new ContainerMetadata( return null;
"test1", }
URI
.create("https://pcsbeta.mezeo.net/v2/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B"), public Future<URI> createContainer(URI parent, String container) {
dateService.fromSeconds(1254008225), dateService.fromSeconds(1254008226), return null;
dateService.fromSeconds(1254008227), "adrian@jclouds.org", true, false, 1, }
1024));
public Future<Void> deleteContainer(URI container) {
return null;
}
public Future<Void> deleteFile(URI file) {
return null;
}
public Future<InputStream> downloadFile(URI file) {
return null;
}
public SortedSet<ContainerMetadata> listContainers() {
return null;
}
public Future<? extends SortedSet<ContainerMetadata>> listContainers(URI container) {
if (container.equals(URI.create("https://localhost/root"))) {
return createFuture(ImmutableSortedSet.of(new ContainerMetadata("apple", URI
.create("https://localhost/containers/rootapple"), URI
.create("https://localhost/root"), dateService.fromSeconds(1254008225),
dateService.fromSeconds(1254008226), dateService.fromSeconds(1254008227),
"adrian@jclouds.org", true, false, 1, 1024)));
} else if (container.equals(URI.create("https://localhost/containers/rootapple"))) {
return createFuture(ImmutableSortedSet.of(new ContainerMetadata("apple", URI
.create("https://localhost/containers/appleapple"), URI
.create("https://localhost/containers/rootapple"), dateService
.fromSeconds(1254008225), dateService.fromSeconds(1254008226), dateService
.fromSeconds(1254008227), "adrian@jclouds.org", true, false, 1, 1024)));
} else {
return createFuture(ImmutableSortedSet.<ContainerMetadata> of());
}
}
<T> Future<T> createFuture(final T data) {
return new Future<T>() {
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
public T get() throws InterruptedException, ExecutionException {
return data;
}
public T get(long timeout, TimeUnit unit) throws InterruptedException,
ExecutionException, TimeoutException {
return data;
}
public boolean isCancelled() {
return false;
}
public boolean isDone() {
return false;
}
};
}
public Future<? extends SortedSet<FileMetadata>> listFiles(URI container) {
return null;
}
public Future<URI> uploadFile(URI container, PCSFile object) {
return null;
}
};
FindIdInContainerList binder = new FindIdInContainerList(connection, URI
.create("https://localhost/root"));
@Test(expectedExceptions = ContainerNotFoundException.class) @Test(expectedExceptions = ContainerNotFoundException.class)
public void testBad() { public void testBad() {
FindIdInContainerList binder = new FindIdInContainerList(createNiceMock(PCSConnection.class)); binder.apply("hello");
binder.idForNameInListOrException("hello", OF); }
@Test(expectedExceptions = ContainerNotFoundException.class)
public void testBad2() {
binder.apply("apple/hello");
} }
public void testGood() { public void testGood() {
FindIdInContainerList binder = new FindIdInContainerList(createNiceMock(PCSConnection.class)); assertEquals(binder.apply("apple"), "rootapple");
assertEquals(binder.idForNameInListOrException("test1", OF), }
"7F143552-AAF5-11DE-BBB0-0BC388ED913B");
public void testSub() {
assertEquals(binder.apply("apple/apple"), "appleapple");
} }
} }

View File

@ -50,7 +50,7 @@ public class PCSBlobStoreIntegrationTest extends
assertEquals(metadata.getSize(), TEST_STRING.length()); assertEquals(metadata.getSize(), TEST_STRING.length());
assertEquals(metadata.getUserMetadata().get("adrian"), Collections assertEquals(metadata.getUserMetadata().get("adrian"), Collections
.singletonList("powderpuff")); .singletonList("powderpuff"));
// Content-MD5 not supported http://code.google.com/p/jclouds/issues/detail?id=105 // Issue 105
// assertEquals(metadata.getContentMD5(), HttpUtils.md5(TEST_STRING.getBytes())); // assertEquals(metadata.getContentMD5(), HttpUtils.md5(TEST_STRING.getBytes()));
} }
@ -58,62 +58,64 @@ public class PCSBlobStoreIntegrationTest extends
@Test(enabled = false) @Test(enabled = false)
public void testGetIfMatch() throws InterruptedException, ExecutionException, TimeoutException, public void testGetIfMatch() throws InterruptedException, ExecutionException, TimeoutException,
IOException { IOException {
// etag not supported http://code.google.com/p/jclouds/issues/detail?id=105 // Issue 105
} }
@Override @Override
@Test(enabled = false) @Test(enabled = false)
public void testGetIfModifiedSince() throws InterruptedException, ExecutionException, public void testGetIfModifiedSince() throws InterruptedException, ExecutionException,
TimeoutException, IOException { TimeoutException, IOException {
// unsupported // Issue 105
} }
@Override @Override
@Test(enabled = false) @Test(enabled = false)
public void testGetIfNoneMatch() throws InterruptedException, ExecutionException, public void testGetIfNoneMatch() throws InterruptedException, ExecutionException,
TimeoutException, IOException { TimeoutException, IOException {
// etag not supported http://code.google.com/p/jclouds/issues/detail?id=105 // Issue 105
} }
@Override @Override
@Test(enabled = false) @Test(enabled = false)
public void testGetIfUnmodifiedSince() throws InterruptedException, ExecutionException, public void testGetIfUnmodifiedSince() throws InterruptedException, ExecutionException,
TimeoutException, IOException { TimeoutException, IOException {
// unsupported // Issue 105
} }
@Override @Override
@Test(enabled = false) @Test(enabled = false)
public void testGetRange() throws InterruptedException, ExecutionException, TimeoutException, public void testGetRange() throws InterruptedException, ExecutionException, TimeoutException,
IOException { IOException {
// unsupported http://code.google.com/p/jclouds/issues/detail?id=106 // Issue 106, Mezeo defect 2644
} }
@Override @Override
@Test(enabled = false) @Test(enabled = false)
public void testGetStartAt() throws InterruptedException, ExecutionException, TimeoutException, public void testGetStartAt() throws InterruptedException, ExecutionException, TimeoutException,
IOException { IOException {
// unsupported http://code.google.com/p/jclouds/issues/detail?id=106 // Issue 106, Mezeo defect 2644
} }
@Override @Override
@Test(enabled = false) @Test(enabled = false)
public void testGetTail() throws InterruptedException, ExecutionException, TimeoutException, public void testGetTail() throws InterruptedException, ExecutionException, TimeoutException,
IOException { IOException {
// unsupported http://code.google.com/p/jclouds/issues/detail?id=106 // Issue 106, Mezeo defect 2644
} }
@Override @Override
@Test(enabled = false) @Test(enabled = false)
public void testGetTwoRanges() throws InterruptedException, ExecutionException, public void testGetTwoRanges() throws InterruptedException, ExecutionException,
TimeoutException, IOException { TimeoutException, IOException {
// unsupported http://code.google.com/p/jclouds/issues/detail?id=106 // Issue 106, Mezeo defect 2644
} }
@DataProvider(name = "delete") @DataProvider(name = "delete")
@Override @Override
public Object[][] createData() { // normal constraints: The characters \ / : * ? " < > and | cannot be used in names.
return new Object[][] { { "normal" } }; public Object[][] createData() {// unicode Issue 110, Mezeo defect: 2675
// slashes are supported, as they are a part of filepaths which we use nested container to
// create.
return new Object[][] { { "normal" }, { "sp ace" }, { "path/foo" } };
} }
} }

View File

@ -48,7 +48,7 @@ public class PCSTestInitializer extends
@Override @Override
protected PCSContext createLiveContext(Module configurationModule, String url, String app, protected PCSContext createLiveContext(Module configurationModule, String url, String app,
String account, String key) { String account, String key) {
return new PCSContextBuilder(URI.create(url), account, key).relaxSSLHostname().withModules( return new PCSContextBuilder(URI.create(url), account, key).relaxSSLHostname().withSaxDebug().withModules(
configurationModule, new Log4JLoggingModule()).buildContext(); configurationModule, new Log4JLoggingModule()).buildContext();
} }

View File

@ -41,31 +41,48 @@ import org.jclouds.mezeo.pcs2.domain.PCSFile;
*/ */
public class StubPCSConnection implements PCSConnection { public class StubPCSConnection implements PCSConnection {
public Future<URI> createContainer(String container) {
throw new UnsupportedOperationException();
}
public Future<URI> createContainer(URI parent, String container) {
throw new UnsupportedOperationException();
}
public Future<Void> deleteContainer(URI container) { public Future<Void> deleteContainer(URI container) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public Future<Void> deleteFile(URI file) { public Future<Void> deleteFile(URI file) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public Future<InputStream> downloadFile(URI file) { public Future<InputStream> downloadFile(URI file) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
}
public Future<? extends SortedSet<FileMetadata>> listFiles(URI container) {
throw new UnsupportedOperationException();
}
public Future<URI> uploadFile(URI container, PCSFile object) {
throw new UnsupportedOperationException();
}
public Future<URI> createContainer(String container) {
throw new UnsupportedOperationException();
} }
public SortedSet<ContainerMetadata> listContainers() { public SortedSet<ContainerMetadata> listContainers() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
}
public Future<? extends SortedSet<ContainerMetadata>> listContainers(URI container) {
throw new UnsupportedOperationException();
}
public Future<? extends SortedSet<FileMetadata>> listFiles(URI container) {
throw new UnsupportedOperationException();
}
public Future<URI> uploadFile(URI container, PCSFile object) {
throw new UnsupportedOperationException();
} }
} }

View File

@ -28,6 +28,7 @@ import static org.testng.Assert.assertEquals;
import java.net.URI; import java.net.URI;
import org.jclouds.http.HttpUtils; import org.jclouds.http.HttpUtils;
import org.jclouds.mezeo.pcs2.functions.Key;
import org.testng.annotations.Test; import org.testng.annotations.Test;
/** /**
@ -44,4 +45,17 @@ public class PCSUtilsTest {
.create("http://localhost/contents/7F143552-AAF5-11DE-BBB0-0BC388ED913B")); .create("http://localhost/contents/7F143552-AAF5-11DE-BBB0-0BC388ED913B"));
assertEquals(eTag, expected); assertEquals(eTag, expected);
} }
public void testParseKey() {
Key key = PCSUtils.parseKey(new Key("container", "key"));
assertEquals(key.getContainer(), "container");
assertEquals(key.getKey(), "key");
key = PCSUtils.parseKey(new Key("container", "container/key"));
assertEquals(key.getContainer(), "container/container");
assertEquals(key.getKey(), "key");
key = PCSUtils.parseKey(new Key("container", "/container/key"));
assertEquals(key.getContainer(), "container/container");
assertEquals(key.getKey(), "key");
}
} }

View File

@ -63,6 +63,8 @@ public class FileListToContainerMetadataListHandlerTest extends BaseHandlerTest
"test1", "test1",
URI URI
.create("https://pcsbeta.mezeo.net/v2/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B"), .create("https://pcsbeta.mezeo.net/v2/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B"),
URI
.create("https://pcsbeta.mezeo.net/v2/containers/0B5C8F50-8E72-11DE-A1D4-D73479DA6257"),
dateService.fromSeconds(1254008225), dateService.fromSeconds(1254008226), dateService.fromSeconds(1254008225), dateService.fromSeconds(1254008226),
dateService.fromSeconds(1254008227), "adrian@jclouds.org", true, false, 1, dateService.fromSeconds(1254008227), "adrian@jclouds.org", true, false, 1,
1024)); 1024));

View File

@ -23,14 +23,12 @@
*/ */
package org.jclouds.mezeo.pcs2.xml; 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.easymock.classextension.EasyMock.createMock;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.InputStream; import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.util.concurrent.Future;
import javax.inject.Singleton; import javax.inject.Singleton;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
@ -42,6 +40,7 @@ import org.jclouds.util.DateService;
import org.testng.annotations.BeforeTest; import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.Multimap;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Provides; import com.google.inject.Provides;
@ -54,7 +53,6 @@ import com.google.inject.Provides;
public class FileMetadataHandlerTest extends BaseHandlerTest { public class FileMetadataHandlerTest extends BaseHandlerTest {
private DateService dateService; private DateService dateService;
private PCSUtil util;
@BeforeTest @BeforeTest
@Override @Override
@ -66,19 +64,23 @@ public class FileMetadataHandlerTest extends BaseHandlerTest {
protected void configure() { protected void configure() {
} }
@SuppressWarnings("unused") @SuppressWarnings( { "unused", "unchecked" })
@Singleton @Singleton
@Provides @Provides
PCSUtil provideUtil() { PCSUtil provideUtil() {
util = createMock(PCSUtil.class); final Future<Void> voidF = createMock(Future.class);
// Note that we should convert uppercase to lowercase! return new PCSUtil() {
expect( public Future<Void> addEntryToMultiMap(Multimap<String, String> map, String key,
util URI value) {
.get(URI map.put(key.toLowerCase(), "bar");
.create("https://pcsbeta.mezeo.net/v2/files/9E4C5AFA-A98B-11DE-8B4C-C3884B4A2DA3/metadata/Foo"))) return voidF;
.andReturn("bar"); }
replay(util);
return util; public Future<Void> put(URI resource, String value) {
return null;
}
};
} }
}); });
@ -96,10 +98,8 @@ public class FileMetadataHandlerTest extends BaseHandlerTest {
MediaType.TEXT_PLAIN, false); MediaType.TEXT_PLAIN, false);
// Note that we should convert uppercase to lowercase, since most clouds do anyway // Note that we should convert uppercase to lowercase, since most clouds do anyway
expects.getUserMetadata().put("foo", "bar"); expects.getUserMetadata().put("foo", "bar");
FileMetadata result = (FileMetadata) factory.create( FileMetadata result = (FileMetadata) factory.create(
injector.getInstance(FileMetadataHandler.class)).parse(is); injector.getInstance(FileMetadataHandler.class)).parse(is);
verify(util);
assertEquals(result, expects); assertEquals(result, expects);
} }

View File

@ -15,7 +15,11 @@
<bytes>1024</bytes> <bytes>1024</bytes>
<contents <contents
xlink:href="https://pcsbeta.mezeo.net/v2/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B/contents" xlink:href="https://pcsbeta.mezeo.net/v2/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B/contents"
xlink:type="simple" count="0" start="0" total="0" /> xlink:type="simple" count="0" start="0" total="0">
<container
xlink:href="https://eval.mezeo.net/v2/containers/D3256E66-B29F-11DE-9597-BF70124CE977"
xlink:type="simple" />
</contents>
<tags <tags
xlink:href="https://pcsbeta.mezeo.net/v2/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B/tags" xlink:href="https://pcsbeta.mezeo.net/v2/containers/7F143552-AAF5-11DE-BBB0-0BC388ED913B/tags"
xlink:type="simple" /> xlink:type="simple" />