Updates to improve blobstore.clj.

* New function blob2 exposes many more options for creating blobs.
* Updated functions that use blob to use blob2.
* New functions sign-get, sign-put, and sign-delete replace the
  functionality of sign-blob-request.
* Added tests.
* Deprecation metadata added to blob and sign-blob-request.
This commit is contained in:
David Santiago 2011-04-01 23:32:07 -05:00
parent 4f7a58b498
commit 2c74c70b1f
2 changed files with 96 additions and 9 deletions

View File

@ -44,9 +44,9 @@ See http://code.google.com/p/jclouds for details."
(:import [java.io File FileOutputStream OutputStream] (:import [java.io File FileOutputStream OutputStream]
java.util.Properties java.util.Properties
[org.jclouds.blobstore [org.jclouds.blobstore
AsyncBlobStore BlobStore BlobStoreContext BlobStoreContextFactory AsyncBlobStore domain.BlobBuilder BlobStore BlobStoreContext
domain.BlobMetadata domain.StorageMetadata domain.Blob BlobStoreContextFactory domain.BlobMetadata domain.StorageMetadata
options.ListContainerOptions] domain.Blob options.ListContainerOptions]
org.jclouds.io.Payloads org.jclouds.io.Payloads
org.jclouds.io.payloads.PhantomPayload org.jclouds.io.payloads.PhantomPayload
java.util.Arrays java.util.Arrays
@ -267,6 +267,7 @@ Note: (apply concat coll) or (lazy-cat coll) are not lazy wrt coll itself."
:put. For :put requests, :content-length must be specified. Optionally, :put. For :put requests, :content-length must be specified. Optionally,
:content-type, :content-disposition, :content-language, :content-encoding :content-type, :content-disposition, :content-language, :content-encoding
and :content-md5 may be given." and :content-md5 may be given."
{:deprecated "1.0-beta-10"}
([container-name path] ([container-name path]
(sign-blob-request container-name path {:method :get} *blobstore*)) (sign-blob-request container-name path {:method :get} *blobstore*))
([container-name path ([container-name path
@ -299,6 +300,33 @@ Note: (apply concat coll) or (lazy-cat coll) are not lazy wrt coll itself."
(.setContentLanguage content-language)) (.setContentLanguage content-language))
payload))))))) payload)))))))
(defn sign-get
"Get a signed http GET request for manipulating a blob in another
application, Ex. curl."
([container-name name]
(sign-get container-name name *blobstore*))
([container-name name ^BlobStore blobstore]
(.signGetBlob (.. blobstore getContext getSigner) container-name name)))
(defn sign-put
"Get a signed http PUT request for manipulating a blob in another
application, Ex. curl. A Blob with at least the name and content-length
must be given."
([container-name blob]
(sign-put container-name blob *blobstore*))
([container-name ^Blob blob ^BlobStore blobstore]
(.signPutBlob (.. blobstore getContext getSigner)
container-name
blob)))
(defn sign-delete
"Get a signed http DELETE request for manipulating a blob in another
applicaiton, Ex. curl."
([container-name name]
(sign-delete container-name name *blobstore*))
([container-name name ^BlobStore blobstore]
(.signRemoveBlob (.. blobstore getContext getSigner) container-name name)))
(defn get-blob-stream (defn get-blob-stream
"Get an inputstream from the blob at a given path" "Get an inputstream from the blob at a given path"
([container-name path] ([container-name path]
@ -340,21 +368,46 @@ example:
(.inDirectory (new ListContainerOptions) dir)))) (.inDirectory (new ListContainerOptions) dir))))
(defn blob (defn blob
"create a new blob with the specified payload" "create a new blob with the specified payload"
{:deprecated "1.0-beta-10"}
([#^String name payload] ([#^String name payload]
(blob name payload *blobstore*)) (blob name payload *blobstore*))
([#^String name payload #^BlobStore blobstore] ([#^String name payload #^BlobStore blobstore]
(doto (.newBlob blobstore name) (doto (.newBlob blobstore name)
(.setPayload payload)))) (.setPayload payload))))
(defn blob2
"Create a new blob with the specified payload and options."
([^String name option-map]
(blob2 name option-map *blobstore*))
([^String name
{:keys [payload content-type content-length content-md5
content-disposition content-encoding content-language metadata]
:or {for-signing false}}
^BlobStore blobstore]
(let [blob-builder (if payload
(.payload (.blobBuilder blobstore name) payload)
(.forSigning (.blobBuilder blobstore name)))
blob-builder (if content-length ;; Special case, arg is prim.
(.contentLength blob-builder content-length)
blob-builder)]
(doto blob-builder
(.contentType content-type)
(.contentMD5 content-md5)
(.contentDisposition content-disposition)
(.contentEncoding content-encoding)
(.contentLanguage content-language)
(.userMetadata metadata))
(.build blob-builder))))
(defn md5-blob (defn md5-blob
"add a content md5 to a blob, or make a new blob that has an md5. "add a content md5 to a blob, or make a new blob that has an md5.
note that this implies rebuffering, if the blob's payload isn't repeatable" note that this implies rebuffering, if the blob's payload isn't repeatable"
([#^Blob blob] ([#^Blob blob]
(Payloads/calculateMD5 blob)) (Payloads/calculateMD5 blob))
([#^String name payload] ([#^String name payload]
(blob name payload *blobstore*)) (blob2 name {:payload payload} *blobstore*))
([#^String name payload #^BlobStore blobstore] ([#^String name payload #^BlobStore blobstore]
(md5-blob (blob name payload blobstore)))) (md5-blob (blob2 name {:payload payload} blobstore))))
(defn upload-blob (defn upload-blob
"Create anrepresenting text data: "Create anrepresenting text data:

View File

@ -146,6 +146,40 @@
(is (= "f" (first (.get (.getHeaders request) "Content-Disposition")))) (is (= "f" (first (.get (.getHeaders request) "Content-Disposition"))))
(is (= "g" (first (.get (.getHeaders request) "Content-Encoding"))))))) (is (= "g" (first (.get (.getHeaders request) "Content-Encoding")))))))
(deftest sign-get-test
(let [request (sign-get "container" "path")]
(is (= "http://localhost/container/path" (str (.getEndpoint request))))
(is (= "GET" (.getMethod request)))))
(deftest sign-put-test
(let [request (sign-put "container"
(blob2 "path" {:content-length 10}))]
(is (= "http://localhost/container/path" (str (.getEndpoint request))))
(is (= "PUT" (.getMethod request)))
(is (= "10" (first (.get (.getHeaders request) "Content-Length"))))
(is (nil?
(first (.get (.getHeaders request) "Content-Type"))))))
(deftest sign-put-with-headers-test
(let [request (sign-put
"container"
(blob2 "path" {:content-length 10
:content-type "x"
:content-language "en"
:content-disposition "f"
:content-encoding "g"}))]
(is (= "PUT" (.getMethod request)))
(is (= "10" (first (.get (.getHeaders request) "Content-Length"))))
(is (= "x" (first (.get (.getHeaders request) "Content-Type"))))
(is (= "en" (first (.get (.getHeaders request) "Content-Language"))))
(is (= "f" (first (.get (.getHeaders request) "Content-Disposition"))))
(is (= "g" (first (.get (.getHeaders request) "Content-Encoding"))))))
(deftest sign-delete-test
(let [request (sign-delete "container" "path")]
(is (= "http://localhost/container/path" (str (.getEndpoint request))))
(is (= "DELETE" (.getMethod request)))))
;; TODO: more tests involving blob-specific functions ;; TODO: more tests involving blob-specific functions
(deftest corruption-hunt (deftest corruption-hunt