diff --git a/blobstore/src/main/clojure/org/jclouds/blobstore2.clj b/blobstore/src/main/clojure/org/jclouds/blobstore2.clj index 7621f98334..f3190da05a 100644 --- a/blobstore/src/main/clojure/org/jclouds/blobstore2.clj +++ b/blobstore/src/main/clojure/org/jclouds/blobstore2.clj @@ -50,7 +50,7 @@ See http://code.google.com/p/jclouds for details." domain.Blob domain.internal.BlobBuilderImpl options.PutOptions options.PutOptions$Builder options.CreateContainerOptions options.ListContainerOptions] - org.jclouds.io.Payloads + [org.jclouds.io Payload Payloads payloads.StreamingPayload] java.util.Arrays [java.security DigestOutputStream MessageDigest] com.google.common.collect.ImmutableSet @@ -73,6 +73,39 @@ See http://code.google.com/p/jclouds for details." (catch Exception e (JCECrypto.)))) +;; +;; Payload support for creating Blobs. +;; + +(def ^{:doc "Type object for a Java primitive byte array, for use in the + PayloadSource protocol." + :private true} + byte-array-type (class (make-array Byte/TYPE 0))) + +(defprotocol PayloadSource + "Various types can have PayloadSource extended onto them so that they are + easily coerced into a Payload." + (^Payload payload [arg] "Coerce arg into a Payload.")) + +(extend-protocol PayloadSource + Payload + (payload [p] p) + java.io.InputStream + (payload [is] (Payloads/newInputStreamPayload is)) + byte-array-type + (payload [ba] (Payloads/newByteArrayPayload ba)) + String + (payload [s] (Payloads/newStringPayload s)) + java.io.File + (payload [f] (Payloads/newFilePayload f)) + clojure.lang.IFn + ;; This will let you pass a closure to payload that takes an OutputStream + ;; as argument and writes to it when called from a StreamingPayload. + (payload [func] + (StreamingPayload. (reify org.jclouds.io.WriteTo + (writeTo [this output-stream] + (func output-stream)))))) + (defn blobstore "Create a logged in context. Options for communication style @@ -278,7 +311,10 @@ Options can also be specified for extension modules (.countBlobs blobstore container-name)) (defn blob - "Create a new blob with the specified payload and options." + "Create a new blob with the specified payload and options. + + The payload argument can be anything accepted by org.jclouds.io.Payloads, or + you can make one manually (recommended) with the payload protocol function." ([^String name & {:keys [payload content-type content-length content-md5 calculate-md5 content-disposition content-encoding content-language metadata]}] @@ -286,7 +322,8 @@ Options can also be specified for extension modules (not (and (nil? payload) calculate-md5))]} (let [blob-builder (.name (BlobBuilderImpl. crypto-impl) name) blob-builder (if payload - (.payload blob-builder payload) + (.payload blob-builder + (org.jclouds.blobstore2/payload payload)) (.forSigning blob-builder)) blob-builder (if content-length ;; Special case, arg is prim. (.contentLength blob-builder content-length) diff --git a/blobstore/src/test/clojure/org/jclouds/blobstore2_test.clj b/blobstore/src/test/clojure/org/jclouds/blobstore2_test.clj index 02673198e7..1afa747e39 100644 --- a/blobstore/src/test/clojure/org/jclouds/blobstore2_test.clj +++ b/blobstore/src/test/clojure/org/jclouds/blobstore2_test.clj @@ -22,7 +22,8 @@ (:use [clojure.test]) (:import [org.jclouds.blobstore BlobStoreContextFactory] [org.jclouds.crypto CryptoStreams] - [java.io ByteArrayOutputStream] + [java.io ByteArrayInputStream ByteArrayOutputStream + StringBufferInputStream] [org.jclouds.util Strings2])) (defn clean-stub-fixture @@ -157,4 +158,37 @@ (is (= (seq (.. a-blob (getPayload) (getContentMetadata) (getContentMD5))) (seq (CryptoStreams/md5 (.getBytes "test-payload"))))))) +(deftest payload-protocol-test + (is (instance? org.jclouds.io.Payload (payload "test"))) + (is (blob "blob1" :payload (payload "blob1"))) + (is (create-container *blobstore* "container")) + (is (= "blob1" + (do + (put-blob *blobstore* "container" + (blob "blob1" + :payload "blob1")) + (Strings2/toStringAndClose (get-blob-stream *blobstore* + "container" "blob1"))))) + (is (= "blob1" + (do + (put-blob *blobstore* "container" + (blob "blob1" + :payload (StringBufferInputStream. "blob1"))) + (Strings2/toStringAndClose (get-blob-stream *blobstore* + "container" "blob1"))))) + (is (= "blob1" + (do + (put-blob *blobstore* "container" + (blob "blob1" + :payload (.getBytes "blob1"))) + (Strings2/toStringAndClose (get-blob-stream *blobstore* + "container" "blob1"))))) + (is (= "blob1" + (do + (put-blob *blobstore* "container" + (blob "blob1" + :payload #(.write % (.getBytes "blob1")))) + (Strings2/toStringAndClose (get-blob-stream *blobstore* + "container" "blob1")))))) + ;; TODO: more tests involving blob-specific functions