You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ga...@apache.org on 2015/04/03 00:40:47 UTC

[1/4] jclouds git commit: JCLOUDS-651: Add copyBlob to portable abstraction

Repository: jclouds
Updated Branches:
  refs/heads/master 914ad04ae -> 67d731f05


JCLOUDS-651: Add copyBlob to portable abstraction

Some providers optimize this operation with a server-side copy.  Add a
fallback implementation which does a client-side copy.


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/3cf8abc2
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/3cf8abc2
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/3cf8abc2

Branch: refs/heads/master
Commit: 3cf8abc22e896f51ed388349252da8b1445c0bfd
Parents: 914ad04
Author: Andrew Gaul <ga...@apache.org>
Authored: Fri Sep 5 17:32:08 2014 -0700
Committer: Andrew Gaul <ga...@apache.org>
Committed: Thu Apr 2 15:36:52 2015 -0700

----------------------------------------------------------------------
 .../java/org/jclouds/blobstore/BlobStore.java   | 13 ++++
 .../blobstore/config/LocalBlobStore.java        | 41 +++++++++++
 .../blobstore/internal/BaseBlobStore.java       | 44 +++++++++++
 .../jclouds/blobstore/options/CopyOptions.java  | 57 +++++++++++++++
 .../blobstore/util/ForwardingBlobStore.java     |  7 ++
 .../blobstore/util/ReadOnlyBlobStore.java       |  7 ++
 .../internal/BaseBlobIntegrationTest.java       | 77 ++++++++++++++++++++
 7 files changed, 246 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/3cf8abc2/blobstore/src/main/java/org/jclouds/blobstore/BlobStore.java
----------------------------------------------------------------------
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/BlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/BlobStore.java
index bebdb48..f4b26d2 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/BlobStore.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/BlobStore.java
@@ -27,6 +27,7 @@ import org.jclouds.blobstore.domain.BlobMetadata;
 import org.jclouds.blobstore.domain.ContainerAccess;
 import org.jclouds.blobstore.domain.PageSet;
 import org.jclouds.blobstore.domain.StorageMetadata;
+import org.jclouds.blobstore.options.CopyOptions;
 import org.jclouds.blobstore.options.CreateContainerOptions;
 import org.jclouds.blobstore.options.GetOptions;
 import org.jclouds.blobstore.options.ListContainerOptions;
@@ -230,6 +231,18 @@ public interface BlobStore {
    String putBlob(String container, Blob blob, PutOptions options);
 
    /**
+    * Copy blob from one container to another.  Some providers implement this
+    * more efficiently than corresponding getBlob and putBlob operations.
+    *
+    * Note: options are currently ignored
+    *
+    * @return ETag of new blob
+    * @throws ContainerNotFoundException if either container does not exist
+    */
+   String copyBlob(String fromContainer, String fromName, String toContainer, String toName,
+         CopyOptions options);
+
+   /**
     * Retrieves the metadata of a {@code Blob} at location {@code container/name}
     * 
     * @param container

http://git-wip-us.apache.org/repos/asf/jclouds/blob/3cf8abc2/blobstore/src/main/java/org/jclouds/blobstore/config/LocalBlobStore.java
----------------------------------------------------------------------
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/config/LocalBlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/config/LocalBlobStore.java
index 36e883d..2e1b636 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/config/LocalBlobStore.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/config/LocalBlobStore.java
@@ -30,7 +30,9 @@ import static org.jclouds.blobstore.options.ListContainerOptions.Builder.recursi
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.Date;
+import java.util.Map;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.regex.Pattern;
@@ -57,6 +59,7 @@ import org.jclouds.blobstore.domain.StorageType;
 import org.jclouds.blobstore.domain.internal.MutableStorageMetadataImpl;
 import org.jclouds.blobstore.domain.internal.PageSetImpl;
 import org.jclouds.blobstore.domain.internal.StorageMetadataImpl;
+import org.jclouds.blobstore.options.CopyOptions;
 import org.jclouds.blobstore.options.CreateContainerOptions;
 import org.jclouds.blobstore.options.GetOptions;
 import org.jclouds.blobstore.options.ListContainerOptions;
@@ -75,11 +78,13 @@ import org.jclouds.io.ContentMetadata;
 import org.jclouds.io.ContentMetadataCodec;
 import org.jclouds.io.Payload;
 import org.jclouds.logging.Logger;
+import org.jclouds.util.Closeables2;
 
 import com.google.common.base.Function;
 import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
+import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 
@@ -493,6 +498,42 @@ public final class LocalBlobStore implements BlobStore {
       }
    }
 
+   @Override
+   public String copyBlob(String fromContainer, String fromName, String toContainer, String toName,
+         CopyOptions options) {
+      Blob blob = getBlob(fromContainer, fromName);
+      if (blob == null) {
+         throw new KeyNotFoundException(fromContainer, fromName, "while copying");
+      }
+
+      InputStream is = null;
+      try {
+         is = blob.getPayload().openStream();
+         ContentMetadata metadata = blob.getMetadata().getContentMetadata();
+         BlobBuilder.PayloadBlobBuilder builder = blobBuilder(toName)
+               .payload(is)
+               .contentDisposition(metadata.getContentDisposition())
+               .contentEncoding(metadata.getContentEncoding())
+               .contentLanguage(metadata.getContentLanguage())
+               .contentType(metadata.getContentType());
+         Long contentLength = metadata.getContentLength();
+         if (contentLength != null) {
+            builder.contentLength(contentLength);
+         }
+         Optional<Map<String, String>> userMetadata = options.getUserMetadata();
+         if (userMetadata.isPresent()) {
+            builder.userMetadata(userMetadata.get());
+         } else {
+            builder.userMetadata(blob.getMetadata().getUserMetadata());
+         }
+         return putBlob(toContainer, builder.build());
+      } catch (IOException ioe) {
+         throw Throwables.propagate(ioe);
+      } finally {
+         Closeables2.closeQuietly(is);
+      }
+   }
+
    private void copyPayloadHeadersToBlob(Payload payload, Blob blob) {
       blob.getAllHeaders().putAll(contentMetadataCodec.toHeaders(payload.getContentMetadata()));
    }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/3cf8abc2/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseBlobStore.java
----------------------------------------------------------------------
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseBlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseBlobStore.java
index 73a01b3..1204e0d 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseBlobStore.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseBlobStore.java
@@ -21,6 +21,9 @@ import static com.google.common.base.Preconditions.checkState;
 import static org.jclouds.blobstore.options.ListContainerOptions.Builder.recursive;
 import static org.jclouds.util.Predicates2.retry;
 
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.Map;
 import java.util.Set;
 
 import javax.inject.Inject;
@@ -28,17 +31,23 @@ import javax.inject.Inject;
 import org.jclouds.blobstore.BlobStore;
 import org.jclouds.blobstore.BlobStoreContext;
 import org.jclouds.blobstore.ContainerNotFoundException;
+import org.jclouds.blobstore.KeyNotFoundException;
 import org.jclouds.blobstore.domain.Blob;
 import org.jclouds.blobstore.domain.BlobBuilder;
 import org.jclouds.blobstore.domain.PageSet;
 import org.jclouds.blobstore.domain.StorageMetadata;
+import org.jclouds.blobstore.options.CopyOptions;
 import org.jclouds.blobstore.options.ListContainerOptions;
 import org.jclouds.blobstore.util.BlobUtils;
 import org.jclouds.collect.Memoized;
 import org.jclouds.domain.Location;
+import org.jclouds.io.ContentMetadata;
+import org.jclouds.util.Closeables2;
 
+import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
+import com.google.common.base.Throwables;
 
 public abstract class BaseBlobStore implements BlobStore {
 
@@ -231,4 +240,39 @@ public abstract class BaseBlobStore implements BlobStore {
     */
    protected abstract boolean deleteAndVerifyContainerGone(String container);
 
+   @Override
+   public String copyBlob(String fromContainer, String fromName, String toContainer, String toName,
+         CopyOptions options) {
+      Blob blob = getBlob(fromContainer, fromName);
+      if (blob == null) {
+         throw new KeyNotFoundException(fromContainer, fromName, "while copying");
+      }
+
+      InputStream is = null;
+      try {
+         is = blob.getPayload().openStream();
+         ContentMetadata metadata = blob.getMetadata().getContentMetadata();
+         BlobBuilder.PayloadBlobBuilder builder = blobBuilder(toName)
+               .payload(is)
+               .contentDisposition(metadata.getContentDisposition())
+               .contentEncoding(metadata.getContentEncoding())
+               .contentLanguage(metadata.getContentLanguage())
+               .contentType(metadata.getContentType());
+         Long contentLength = metadata.getContentLength();
+         if (contentLength != null) {
+            builder.contentLength(contentLength);
+         }
+         Optional<Map<String, String>> userMetadata = options.getUserMetadata();
+         if (userMetadata.isPresent()) {
+            builder.userMetadata(userMetadata.get());
+         } else {
+            builder.userMetadata(blob.getMetadata().getUserMetadata());
+         }
+         return putBlob(toContainer, builder.build());
+      } catch (IOException ioe) {
+         throw Throwables.propagate(ioe);
+      } finally {
+         Closeables2.closeQuietly(is);
+      }
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/3cf8abc2/blobstore/src/main/java/org/jclouds/blobstore/options/CopyOptions.java
----------------------------------------------------------------------
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/options/CopyOptions.java b/blobstore/src/main/java/org/jclouds/blobstore/options/CopyOptions.java
new file mode 100644
index 0000000..3b89e98
--- /dev/null
+++ b/blobstore/src/main/java/org/jclouds/blobstore/options/CopyOptions.java
@@ -0,0 +1,57 @@
+/*
+ * 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.blobstore.options;
+
+import java.util.Map;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+
+public final class CopyOptions {
+   public static final CopyOptions NONE = builder().build();
+
+   private final Optional<Map<String, String>> userMetadata;
+
+   private CopyOptions(Builder builder) {
+      this.userMetadata = Optional.fromNullable(builder.userMetadata);
+   }
+
+   public Optional<Map<String, String>> getUserMetadata() {
+      return userMetadata;
+   }
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public static class Builder {
+      Map<String, String> userMetadata;
+
+      Builder() {
+      }
+
+      public Builder userMetadata(Map<String, String> userMetadata) {
+         this.userMetadata = ImmutableMap.copyOf(userMetadata);
+         return this;
+      }
+
+      public CopyOptions build() {
+          return new CopyOptions(this);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/3cf8abc2/blobstore/src/main/java/org/jclouds/blobstore/util/ForwardingBlobStore.java
----------------------------------------------------------------------
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/util/ForwardingBlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/util/ForwardingBlobStore.java
index 55860ec..60c2d7a 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/util/ForwardingBlobStore.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/util/ForwardingBlobStore.java
@@ -32,6 +32,7 @@ import org.jclouds.blobstore.domain.BlobMetadata;
 import org.jclouds.blobstore.domain.ContainerAccess;
 import org.jclouds.blobstore.domain.PageSet;
 import org.jclouds.blobstore.domain.StorageMetadata;
+import org.jclouds.blobstore.options.CopyOptions;
 import org.jclouds.blobstore.options.CreateContainerOptions;
 import org.jclouds.blobstore.options.GetOptions;
 import org.jclouds.blobstore.options.ListContainerOptions;
@@ -162,6 +163,12 @@ public abstract class ForwardingBlobStore extends ForwardingObject
    }
 
    @Override
+   public String copyBlob(String fromContainer, String fromName, String toContainer, String toName,
+         CopyOptions options) {
+      return delegate().copyBlob(fromContainer, fromName, toContainer, toName, options);
+   }
+
+   @Override
    public BlobMetadata blobMetadata(String container, String name) {
       return delegate().blobMetadata(container, name);
    }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/3cf8abc2/blobstore/src/main/java/org/jclouds/blobstore/util/ReadOnlyBlobStore.java
----------------------------------------------------------------------
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/util/ReadOnlyBlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/util/ReadOnlyBlobStore.java
index dfb4a02..16e481e 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/util/ReadOnlyBlobStore.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/util/ReadOnlyBlobStore.java
@@ -23,6 +23,7 @@ import org.jclouds.blobstore.domain.Blob;
 import org.jclouds.blobstore.domain.BlobAccess;
 import org.jclouds.blobstore.domain.BlobBuilder;
 import org.jclouds.blobstore.domain.ContainerAccess;
+import org.jclouds.blobstore.options.CopyOptions;
 import org.jclouds.blobstore.options.CreateContainerOptions;
 import org.jclouds.blobstore.options.ListContainerOptions;
 import org.jclouds.blobstore.options.PutOptions;
@@ -107,6 +108,12 @@ public final class ReadOnlyBlobStore extends ForwardingBlobStore {
    }
 
    @Override
+   public String copyBlob(String fromContainer, String fromName, String toContainer, String toName,
+         CopyOptions options) {
+      throw new UnsupportedOperationException("Read-only BlobStore");
+   }
+
+   @Override
    public void removeBlob(String container, String name) {
       throw new UnsupportedOperationException("Read-only BlobStore");
    }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/3cf8abc2/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobIntegrationTest.java
----------------------------------------------------------------------
diff --git a/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobIntegrationTest.java b/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobIntegrationTest.java
index 81b3af2..b205e84 100644
--- a/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobIntegrationTest.java
+++ b/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobIntegrationTest.java
@@ -57,6 +57,7 @@ import org.jclouds.blobstore.domain.BlobMetadata;
 import org.jclouds.blobstore.domain.PageSet;
 import org.jclouds.blobstore.domain.StorageMetadata;
 import org.jclouds.blobstore.domain.StorageType;
+import org.jclouds.blobstore.options.CopyOptions;
 import org.jclouds.blobstore.options.PutOptions;
 import org.jclouds.crypto.Crypto;
 import org.jclouds.encryption.internal.JCECrypto;
@@ -82,6 +83,7 @@ import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
 import com.google.common.hash.HashCode;
+import com.google.common.io.ByteStreams;
 import com.google.common.io.ByteSource;
 import com.google.common.io.Files;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -729,6 +731,81 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
       }
    }
 
+   @Test(groups = { "integration", "live" })
+   public void testCopyBlobCopyMetadata() throws Exception {
+      BlobStore blobStore = view.getBlobStore();
+      String fromName = "source";
+      String toName = "to";
+      ByteSource payload = TestUtils.randomByteSource().slice(0, 1024);
+      Map<String, String> userMetadata = ImmutableMap.of("key1", "value1", "key2", "value2");
+      PayloadBlobBuilder blobBuilder = blobStore
+            .blobBuilder(fromName)
+            .payload(payload)
+            .contentLength(payload.size());
+      addContentMetadata(blobBuilder);
+      blobBuilder.userMetadata(userMetadata);
+      Blob blob = blobBuilder.build();
+
+      String fromContainer = getContainerName();
+      String toContainer = getContainerName();
+      try {
+         blobStore.putBlob(fromContainer, blob);
+         blobStore.copyBlob(fromContainer, fromName, toContainer, toName, CopyOptions.NONE);
+         Blob toBlob = blobStore.getBlob(toContainer, toName);
+         InputStream is = null;
+         try {
+            is = toBlob.getPayload().openStream();
+            assertEquals(ByteStreams.toByteArray(is), payload.read());
+         } finally {
+            Closeables2.closeQuietly(is);
+         }
+         // TODO: Swift does not preserve system metadata
+         //checkContentMetadata(toBlob);
+         assertThat(toBlob.getMetadata().getUserMetadata()).isEqualTo(userMetadata);
+      } finally {
+         returnContainer(toContainer);
+         returnContainer(fromContainer);
+      }
+   }
+
+   @Test(groups = { "integration", "live" })
+   public void testCopyBlobReplaceMetadata() throws Exception {
+      BlobStore blobStore = view.getBlobStore();
+      String fromName = "source";
+      String toName = "to";
+      ByteSource payload = TestUtils.randomByteSource().slice(0, 1024);
+      PayloadBlobBuilder blobBuilder = blobStore
+            .blobBuilder(fromName)
+            .payload(payload)
+            .contentLength(payload.size());
+      addContentMetadata(blobBuilder);
+      Blob blob = blobBuilder.build();
+
+      String fromContainer = getContainerName();
+      String toContainer = getContainerName();
+      try {
+         blobStore.putBlob(fromContainer, blob);
+         Map<String, String> userMetadata = ImmutableMap.of("key1", "value1", "key2", "value2");
+         blobStore.copyBlob(fromContainer, fromName, toContainer, toName,
+               CopyOptions.builder().userMetadata(userMetadata).build());
+         Blob toBlob = blobStore.getBlob(toContainer, toName);
+         InputStream is = null;
+         try {
+            is = toBlob.getPayload().openStream();
+            assertEquals(ByteStreams.toByteArray(is), payload.read());
+         } finally {
+            Closeables2.closeQuietly(is);
+         }
+         // TODO: S3 overrideMetadataWith also overrides system metadata
+         // TODO: Swift does not preserve system metadata
+         //checkContentMetadata(toBlob);
+         assertThat(toBlob.getMetadata().getUserMetadata()).isEqualTo(userMetadata);
+      } finally {
+         returnContainer(toContainer);
+         returnContainer(fromContainer);
+      }
+   }
+
    protected void validateMetadata(BlobMetadata metadata) throws IOException {
       assert metadata.getContentMetadata().getContentType().startsWith("text/plain") : metadata.getContentMetadata()
                .getContentType();


[3/4] jclouds git commit: JCLOUDS-651: Add S3 server-side copyBlob

Posted by ga...@apache.org.
JCLOUDS-651: Add S3 server-side copyBlob


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/b85068ca
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/b85068ca
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/b85068ca

Branch: refs/heads/master
Commit: b85068ca7fa608ffd785cbc6ef3c003ef85deb4d
Parents: 31369ae
Author: Andrew Gaul <ga...@apache.org>
Authored: Fri Sep 5 19:06:16 2014 -0700
Committer: Andrew Gaul <ga...@apache.org>
Committed: Thu Apr 2 15:36:53 2015 -0700

----------------------------------------------------------------------
 .../org/jclouds/s3/blobstore/S3BlobStore.java   | 22 ++++++++++++++++++++
 1 file changed, 22 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/b85068ca/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobStore.java
----------------------------------------------------------------------
diff --git a/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobStore.java b/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobStore.java
index 2d6b84a..cd38e52 100644
--- a/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobStore.java
+++ b/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobStore.java
@@ -21,6 +21,7 @@ import static com.google.common.base.Preconditions.checkState;
 import static org.jclouds.util.Predicates2.retry;
 
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import javax.inject.Inject;
@@ -37,6 +38,7 @@ import org.jclouds.blobstore.domain.PageSet;
 import org.jclouds.blobstore.domain.StorageMetadata;
 import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
 import org.jclouds.blobstore.internal.BaseBlobStore;
+import org.jclouds.blobstore.options.CopyOptions;
 import org.jclouds.blobstore.options.CreateContainerOptions;
 import org.jclouds.blobstore.options.ListContainerOptions;
 import org.jclouds.blobstore.options.PutOptions;
@@ -57,12 +59,14 @@ import org.jclouds.s3.domain.AccessControlList.GroupGranteeURI;
 import org.jclouds.s3.domain.AccessControlList.Permission;
 import org.jclouds.s3.domain.BucketMetadata;
 import org.jclouds.s3.domain.CannedAccessPolicy;
+import org.jclouds.s3.options.CopyObjectOptions;
 import org.jclouds.s3.options.ListBucketOptions;
 import org.jclouds.s3.options.PutBucketOptions;
 import org.jclouds.s3.options.PutObjectOptions;
 import org.jclouds.s3.util.S3Utils;
 
 import com.google.common.base.Function;
+import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
 import com.google.common.cache.CacheLoader;
@@ -273,6 +277,24 @@ public class S3BlobStore extends BaseBlobStore {
       return sync.putObject(container, blob2Object.apply(blob), options);
    }
 
+   @Override
+   public String copyBlob(String fromContainer, String fromName, String toContainer, String toName,
+         CopyOptions options) {
+      CopyObjectOptions s3Options = new CopyObjectOptions();
+
+      // TODO: content disposition
+      // TODO: content encoding
+      // TODO: content language
+      // TODO: content type
+
+      Optional<Map<String, String>> userMetadata = options.getUserMetadata();
+      if (userMetadata.isPresent()) {
+         s3Options.overrideMetadataWith(userMetadata.get());
+      }
+
+      return sync.copyObject(fromContainer, fromName, toContainer, toName, s3Options).getETag();
+   }
+
    /**
     * This implementation invokes {@link S3Client#deleteObject}
     * 


[2/4] jclouds git commit: JCLOUDS-651: Add Azure server-side copyBlob

Posted by ga...@apache.org.
JCLOUDS-651: Add Azure server-side copyBlob


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/31369ae5
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/31369ae5
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/31369ae5

Branch: refs/heads/master
Commit: 31369ae59058da5ba0331f79f3576c112e22414f
Parents: 3cf8abc
Author: Andrew Gaul <ga...@apache.org>
Authored: Tue Mar 31 11:36:26 2015 -0700
Committer: Andrew Gaul <ga...@apache.org>
Committed: Thu Apr 2 15:36:53 2015 -0700

----------------------------------------------------------------------
 .../azureblob/blobstore/AzureBlobStore.java     | 29 ++++++++++++++++++++
 1 file changed, 29 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/31369ae5/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobStore.java
----------------------------------------------------------------------
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobStore.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobStore.java
index 9144700..ccd31b5 100644
--- a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobStore.java
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobStore.java
@@ -19,7 +19,9 @@ package org.jclouds.azureblob.blobstore;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.jclouds.azure.storage.options.ListOptions.Builder.includeMetadata;
 
+import java.net.URI;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import javax.inject.Inject;
@@ -38,6 +40,7 @@ import org.jclouds.azureblob.blobstore.strategy.MultipartUploadStrategy;
 import org.jclouds.azureblob.domain.ContainerProperties;
 import org.jclouds.azureblob.domain.ListBlobBlocksResponse;
 import org.jclouds.azureblob.domain.PublicAccess;
+import org.jclouds.azureblob.options.CopyBlobOptions;
 import org.jclouds.azureblob.options.ListBlobsOptions;
 import org.jclouds.blobstore.BlobStoreContext;
 import org.jclouds.blobstore.domain.Blob;
@@ -49,6 +52,7 @@ import org.jclouds.blobstore.domain.StorageMetadata;
 import org.jclouds.blobstore.domain.internal.PageSetImpl;
 import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
 import org.jclouds.blobstore.internal.BaseBlobStore;
+import org.jclouds.blobstore.options.CopyOptions;
 import org.jclouds.blobstore.options.CreateContainerOptions;
 import org.jclouds.blobstore.options.ListContainerOptions;
 import org.jclouds.blobstore.options.PutOptions;
@@ -58,6 +62,7 @@ import org.jclouds.domain.Location;
 import org.jclouds.http.options.GetOptions;
 
 import com.google.common.base.Function;
+import com.google.common.base.Optional;
 import com.google.common.base.Supplier;
 import com.google.common.collect.Iterables;
 import org.jclouds.io.Payload;
@@ -215,6 +220,30 @@ public class AzureBlobStore extends BaseBlobStore {
       return putBlob(container, blob);
    }
 
+   @Override
+   public String copyBlob(String fromContainer, String fromName, String toContainer, String toName,
+         CopyOptions options) {
+      CopyBlobOptions.Builder azureOptions = CopyBlobOptions.builder();
+
+      Optional<Map<String, String>> userMetadata = options.getUserMetadata();
+      if (userMetadata.isPresent()) {
+         azureOptions.overrideUserMetadata(userMetadata.get());
+      }
+
+      URI source = context.getSigner().signGetBlob(fromContainer, fromName).getEndpoint();
+      sync.copyBlob(source, toContainer, toName, azureOptions.build());
+
+      String eTag = sync.getBlobProperties(toContainer, toName).getETag();
+
+      // TODO: Azure does not allow updating system metadata during copy - call SetBlobProperties (not yet implemented)
+      // TODO: content disposition
+      // TODO: content encoding
+      // TODO: content language
+      // TODO: content type
+
+      return eTag;
+   }
+
    /**
     * This implementation invokes {@link AzureBlobClient#deleteObject}
     * 


[4/4] jclouds git commit: JCLOUDS-651: Add Swift server-side copyBlob

Posted by ga...@apache.org.
JCLOUDS-651: Add Swift server-side copyBlob

This has some limitations as discussed in JCLOUDS-872.


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/67d731f0
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/67d731f0
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/67d731f0

Branch: refs/heads/master
Commit: 67d731f0543a3f95d164ffb1bc3e37ef6c9361ec
Parents: b85068c
Author: Andrew Gaul <ga...@apache.org>
Authored: Sun Mar 29 21:51:03 2015 -0700
Committer: Andrew Gaul <ga...@apache.org>
Committed: Thu Apr 2 15:36:54 2015 -0700

----------------------------------------------------------------------
 .../blobstore/RegionScopedSwiftBlobStore.java   | 28 ++++++++++++++++++++
 1 file changed, 28 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/67d731f0/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/blobstore/RegionScopedSwiftBlobStore.java
----------------------------------------------------------------------
diff --git a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/blobstore/RegionScopedSwiftBlobStore.java b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/blobstore/RegionScopedSwiftBlobStore.java
index d535569..4516264 100644
--- a/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/blobstore/RegionScopedSwiftBlobStore.java
+++ b/apis/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/blobstore/RegionScopedSwiftBlobStore.java
@@ -25,6 +25,7 @@ import static org.jclouds.location.predicates.LocationPredicates.idEquals;
 import static org.jclouds.openstack.swift.v1.options.PutOptions.Builder.metadata;
 
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import javax.inject.Inject;
@@ -44,6 +45,7 @@ import org.jclouds.blobstore.domain.internal.BlobBuilderImpl;
 import org.jclouds.blobstore.domain.internal.BlobImpl;
 import org.jclouds.blobstore.domain.internal.PageSetImpl;
 import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
+import org.jclouds.blobstore.options.CopyOptions;
 import org.jclouds.blobstore.options.CreateContainerOptions;
 import org.jclouds.blobstore.options.GetOptions;
 import org.jclouds.blobstore.options.ListContainerOptions;
@@ -229,6 +231,32 @@ public class RegionScopedSwiftBlobStore implements BlobStore {
    }
 
    @Override
+   public String copyBlob(String fromContainer, String fromName, String toContainer, String toName,
+         CopyOptions options) {
+      ObjectApi objectApi = api.getObjectApi(regionId, toContainer);
+
+      boolean copied = objectApi.copy(toName, fromContainer, fromName);
+      if (!copied) {
+         throw new RuntimeException("could not copy blob");
+      }
+
+      // TODO: content disposition
+      // TODO: content encoding
+      // TODO: content language
+      // TODO: content type
+
+      Optional<Map<String, String>> userMetadata = options.getUserMetadata();
+      if (userMetadata.isPresent()) {
+         boolean updated = objectApi.updateMetadata(toName, userMetadata.get());
+         if (!updated) {
+            throw new RuntimeException("could not copy blob");
+         }
+      }
+
+      return objectApi.getWithoutBody(toName).getETag();
+   }
+
+   @Override
    public BlobMetadata blobMetadata(String container, String name) {
       SwiftObject object = api.getObjectApi(regionId, container).get(name);
       if (object == null) {