() {
+ @Override
+ public Acl apply(ObjectAccessControl objectAccessControl) {
+ return Acl.fromPb(objectAccessControl);
+ }
+ }));
+ }
+ return builder.build();
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ this.storage = options.service();
+ }
+
+ /**
+ * Create a new blob with no content.
+ *
+ * @return a complete blob
+ * @throws StorageException upon failure
+ */
+ public Blob create(BlobTargetOption... options) {
+ return storage.create(this, options);
+ }
+
+ /**
+ * Create a new blob. Direct upload is used to upload {@code content}. For large content,
+ * {@link #writer} is recommended as it uses resumable upload. MD5 and CRC32C hashes of
+ * {@code content} are computed and used for validating transferred data.
+ *
+ * @return a complete blob
+ * @throws StorageException upon failure
+ * @see Hashes and ETags
+ */
+ public Blob create(byte[] content, BlobTargetOption... options) {
+ return storage.create(this, content, options);
+ }
+
+ /**
+ * Create a new blob. Direct upload is used to upload {@code content}. For large content,
+ * {@link #writer} is recommended as it uses resumable upload. By default any md5 and crc32c
+ * values in the given {@code blob} are ignored unless requested via the
+ * {@code BlobWriteOption.md5Match} and {@code BlobWriteOption.crc32cMatch} options.
+ *
+ * @return a complete blob
+ * @throws StorageException upon failure
+ */
+ public Blob create(InputStream content, BlobWriteOption... options) {
+ return storage.create(this, content, options);
}
/**
@@ -184,22 +910,7 @@ public static Blob get(Storage storage, String bucket, String blob,
* @throws StorageException upon failure
*/
public static Blob get(Storage storage, BlobId blobId, Storage.BlobGetOption... options) {
- BlobInfo info = storage.get(blobId, options);
- return info != null ? new Blob(storage, info) : null;
- }
-
- /**
- * Returns the blob's information.
- */
- public BlobInfo info() {
- return info;
- }
-
- /**
- * Returns the blob's id.
- */
- public BlobId id() {
- return info.blobId();
+ return storage.get(blobId, options);
}
/**
@@ -211,9 +922,9 @@ public BlobId id() {
*/
public boolean exists(BlobSourceOption... options) {
int length = options.length;
- Storage.BlobGetOption[] getOptions = Arrays.copyOf(toGetOptions(info, options), length + 1);
+ Storage.BlobGetOption[] getOptions = Arrays.copyOf(toGetOptions(this, options), length + 1);
getOptions[length] = Storage.BlobGetOption.fields();
- return storage.get(info.blobId(), getOptions) != null;
+ return storage.get(blobId, getOptions) != null;
}
/**
@@ -223,7 +934,7 @@ public boolean exists(BlobSourceOption... options) {
* @throws StorageException upon failure
*/
public byte[] content(Storage.BlobSourceOption... options) {
- return storage.readAllBytes(info.blobId(), options);
+ return storage.readAllBytes(blobId, options);
}
/**
@@ -234,7 +945,7 @@ public byte[] content(Storage.BlobSourceOption... options) {
* @throws StorageException upon failure
*/
public Blob reload(BlobSourceOption... options) {
- return Blob.get(storage, info.blobId(), toGetOptions(info, options));
+ return Blob.get(storage, blobId, toGetOptions(this, options));
}
/**
@@ -243,27 +954,27 @@ public Blob reload(BlobSourceOption... options) {
* {@link #delete} operations. A new {@code Blob} object is returned. By default no checks are
* made on the metadata generation of the current blob. If you want to update the information only
* if the current blob metadata are at their latest version use the {@code metagenerationMatch}
- * option: {@code blob.update(newInfo, BlobTargetOption.metagenerationMatch())}.
+ * option: {@code blob.update(newBlob, BlobTargetOption.metagenerationMatch())}.
*
- * Original metadata are merged with metadata in the provided {@code blobInfo}. To replace
+ *
Original metadata are merged with metadata in the provided {@code blob}. To replace
* metadata instead you first have to unset them. Unsetting metadata can be done by setting the
- * provided {@code blobInfo}'s metadata to {@code null}.
+ * provided {@code blob}'s metadata to {@code null}.
*
*
* Example usage of replacing blob's metadata:
- *
{@code blob.update(blob.info().toBuilder().metadata(null).build());}
- * {@code blob.update(blob.info().toBuilder().metadata(newMetadata).build());}
+ * {@code blob.update(blob.toBuilder().metadata(null).build());}
+ * {@code blob.update(blob.toBuilder().metadata(newMetadata).build());}
*
*
- * @param blobInfo new blob's information. Bucket and blob names must match the current ones
+ * @param blob the new blob. Bucket and blob names must match the current ones
* @param options update options
* @return a {@code Blob} object with updated information
* @throws StorageException upon failure
*/
- public Blob update(BlobInfo blobInfo, BlobTargetOption... options) {
- checkArgument(Objects.equals(blobInfo.bucket(), info.bucket()), "Bucket name must match");
- checkArgument(Objects.equals(blobInfo.name(), info.name()), "Blob name must match");
- return new Blob(storage, storage.update(blobInfo, options));
+ public Blob update(Blob blob, BlobTargetOption... options) {
+ checkArgument(Objects.equals(blob.bucket(), bucket()), "Bucket name must match");
+ checkArgument(Objects.equals(blob.name(), name()), "Blob name must match");
+ return storage.update(blob, options);
}
/**
@@ -274,7 +985,7 @@ public Blob update(BlobInfo blobInfo, BlobTargetOption... options) {
* @throws StorageException upon failure
*/
public boolean delete(BlobSourceOption... options) {
- return storage.delete(info.blobId(), toSourceOptions(info, options));
+ return storage.delete(blobId, toSourceOptions(this, options));
}
/**
@@ -288,8 +999,12 @@ public boolean delete(BlobSourceOption... options) {
* @throws StorageException upon failure
*/
public CopyWriter copyTo(BlobId targetBlob, BlobSourceOption... options) {
- CopyRequest copyRequest = CopyRequest.builder().source(info.bucket(), info.name())
- .sourceOptions(toSourceOptions(info, options)).target(targetBlob).build();
+ CopyRequest copyRequest =
+ CopyRequest.builder()
+ .source(this.bucket(), this.name())
+ .sourceOptions(toSourceOptions(this, options))
+ .target(storage, targetBlob)
+ .build();
return storage.copy(copyRequest);
}
@@ -304,7 +1019,7 @@ public CopyWriter copyTo(BlobId targetBlob, BlobSourceOption... options) {
* @throws StorageException upon failure
*/
public CopyWriter copyTo(String targetBucket, BlobSourceOption... options) {
- return copyTo(targetBucket, info.name(), options);
+ return copyTo(targetBucket, name(), options);
}
/**
@@ -329,7 +1044,7 @@ public CopyWriter copyTo(String targetBucket, String targetBlob, BlobSourceOptio
* @throws StorageException upon failure
*/
public ReadChannel reader(BlobSourceOption... options) {
- return storage.reader(info.blobId(), toSourceOptions(info, options));
+ return storage.reader(blobId, toSourceOptions(this, options));
}
/**
@@ -341,7 +1056,7 @@ public ReadChannel reader(BlobSourceOption... options) {
* @throws StorageException upon failure
*/
public WriteChannel writer(BlobWriteOption... options) {
- return storage.writer(info, options);
+ return storage.writer(this, options);
}
/**
@@ -358,14 +1073,7 @@ public WriteChannel writer(BlobWriteOption... options) {
* @see Signed-URLs
*/
public URL signUrl(long duration, TimeUnit unit, SignUrlOption... options) {
- return storage.signUrl(info, duration, unit, options);
- }
-
- /**
- * Returns the blob's {@code Storage} object used to issue requests.
- */
- public Storage storage() {
- return storage;
+ return storage.signUrl(this, duration, unit, options);
}
/**
@@ -405,42 +1113,30 @@ public static List get(final Storage storage, List blobs) {
checkNotNull(storage);
checkNotNull(blobs);
BlobId[] blobArray = blobs.toArray(new BlobId[blobs.size()]);
- return Collections.unmodifiableList(Lists.transform(storage.get(blobArray),
- new Function() {
- @Override
- public Blob apply(BlobInfo blobInfo) {
- return blobInfo != null ? new Blob(storage, blobInfo) : null;
- }
- }));
+ return Collections.unmodifiableList(storage.get(blobArray));
}
/**
* Updates the requested blobs. A batch request is used to update blobs. Original metadata are
- * merged with metadata in the provided {@code BlobInfo} objects. To replace metadata instead
+ * merged with metadata in the provided {@code Blob} objects. To replace metadata instead
* you first have to unset them. Unsetting metadata can be done by setting the provided
- * {@code BlobInfo} objects metadata to {@code null}. See
- * {@link #update(com.google.gcloud.storage.BlobInfo,
+ * {@code Blob} objects metadata to {@code null}. See
+ * {@link #update(com.google.gcloud.storage.Blob,
* com.google.gcloud.storage.Storage.BlobTargetOption...) } for a code example.
*
* @param storage the storage service used to issue the request
- * @param infos the blobs to update
+ * @param blobs the blobs to update
* @return an immutable list of {@code Blob} objects. If a blob does not exist or access to it has
* been denied the corresponding item in the list is {@code null}
* @throws StorageException upon failure
*/
- public static List update(final Storage storage, BlobInfo... infos) {
+ public static List update(final Storage storage, Blob... blobs) {
checkNotNull(storage);
- checkNotNull(infos);
- if (infos.length == 0) {
+ checkNotNull(blobs);
+ if (blobs.length == 0) {
return Collections.emptyList();
}
- return Collections.unmodifiableList(Lists.transform(storage.update(infos),
- new Function() {
- @Override
- public Blob apply(BlobInfo blobInfo) {
- return blobInfo != null ? new Blob(storage, blobInfo) : null;
- }
- }));
+ return Collections.unmodifiableList(storage.update(blobs));
}
/**
diff --git a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/BlobInfo.java b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/BlobInfo.java
deleted file mode 100644
index b27d00d68a16..000000000000
--- a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/BlobInfo.java
+++ /dev/null
@@ -1,699 +0,0 @@
-/*
- * Copyright 2015 Google Inc. All Rights Reserved.
- *
- * Licensed 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 com.google.gcloud.storage;
-
-import static com.google.common.base.MoreObjects.firstNonNull;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.api.client.util.Data;
-import com.google.api.client.util.DateTime;
-import com.google.api.services.storage.model.ObjectAccessControl;
-import com.google.api.services.storage.model.StorageObject;
-import com.google.api.services.storage.model.StorageObject.Owner;
-import com.google.common.base.Function;
-import com.google.common.base.MoreObjects;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
-import java.io.Serializable;
-import java.math.BigInteger;
-import java.util.AbstractMap;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * Google Storage object metadata.
- *
- * @see Concepts and
- * Terminology
- */
-public final class BlobInfo implements Serializable {
-
- static final Function FROM_PB_FUNCTION =
- new Function() {
- @Override
- public BlobInfo apply(StorageObject pb) {
- return BlobInfo.fromPb(pb);
- }
- };
- static final Function TO_PB_FUNCTION =
- new Function() {
- @Override
- public StorageObject apply(BlobInfo blobInfo) {
- return blobInfo.toPb();
- }
- };
- private static final long serialVersionUID = 2228487739943277159L;
- private final BlobId blobId;
- private final String id;
- private final String selfLink;
- private final String cacheControl;
- private final List acl;
- private final Acl.Entity owner;
- private final Long size;
- private final String etag;
- private final String md5;
- private final String crc32c;
- private final String mediaLink;
- private final Map metadata;
- private final Long metageneration;
- private final Long deleteTime;
- private final Long updateTime;
- private final String contentType;
- private final String contentEncoding;
- private final String contentDisposition;
- private final String contentLanguage;
- private final Integer componentCount;
-
- /**
- * This class is meant for internal use only. Users are discouraged from using this class.
- */
- public static final class ImmutableEmptyMap extends AbstractMap {
-
- @Override
- public Set> entrySet() {
- return ImmutableSet.of();
- }
- }
-
- public static final class Builder {
-
- private BlobId blobId;
- private String id;
- private String contentType;
- private String contentEncoding;
- private String contentDisposition;
- private String contentLanguage;
- private Integer componentCount;
- private String cacheControl;
- private List acl;
- private Acl.Entity owner;
- private Long size;
- private String etag;
- private String selfLink;
- private String md5;
- private String crc32c;
- private String mediaLink;
- private Map metadata;
- private Long metageneration;
- private Long deleteTime;
- private Long updateTime;
-
- private Builder() {}
-
- private Builder(BlobInfo blobInfo) {
- blobId = blobInfo.blobId;
- id = blobInfo.id;
- cacheControl = blobInfo.cacheControl;
- contentEncoding = blobInfo.contentEncoding;
- contentType = blobInfo.contentType;
- contentDisposition = blobInfo.contentDisposition;
- contentLanguage = blobInfo.contentLanguage;
- componentCount = blobInfo.componentCount;
- acl = blobInfo.acl;
- owner = blobInfo.owner;
- size = blobInfo.size;
- etag = blobInfo.etag;
- selfLink = blobInfo.selfLink;
- md5 = blobInfo.md5;
- crc32c = blobInfo.crc32c;
- mediaLink = blobInfo.mediaLink;
- metadata = blobInfo.metadata;
- metageneration = blobInfo.metageneration;
- deleteTime = blobInfo.deleteTime;
- updateTime = blobInfo.updateTime;
- }
-
- /**
- * Sets the blob identity.
- */
- public Builder blobId(BlobId blobId) {
- this.blobId = checkNotNull(blobId);
- return this;
- }
-
- Builder id(String id) {
- this.id = id;
- return this;
- }
-
- /**
- * Sets the blob's data content type.
- *
- * @see Content-Type
- */
- public Builder contentType(String contentType) {
- this.contentType = firstNonNull(contentType, Data.nullOf(String.class));
- return this;
- }
-
- /**
- * Sets the blob's data content disposition.
- *
- * @see Content-Disposition
- */
- public Builder contentDisposition(String contentDisposition) {
- this.contentDisposition = firstNonNull(contentDisposition, Data.nullOf(String.class));
- return this;
- }
-
- /**
- * Sets the blob's data content language.
- *
- * @see Content-Language
- */
- public Builder contentLanguage(String contentLanguage) {
- this.contentLanguage = firstNonNull(contentLanguage, Data.nullOf(String.class));
- return this;
- }
-
- /**
- * Sets the blob's data content encoding.
- *
- * @see Content-Encoding
- */
- public Builder contentEncoding(String contentEncoding) {
- this.contentEncoding = firstNonNull(contentEncoding, Data.nullOf(String.class));
- return this;
- }
-
- Builder componentCount(Integer componentCount) {
- this.componentCount = componentCount;
- return this;
- }
-
- /**
- * Sets the blob's data cache control.
- *
- * @see Cache-Control
- */
- public Builder cacheControl(String cacheControl) {
- this.cacheControl = firstNonNull(cacheControl, Data.nullOf(String.class));
- return this;
- }
-
- /**
- * Sets the blob's access control configuration.
- *
- * @see
- * About Access Control Lists
- */
- public Builder acl(List acl) {
- this.acl = acl != null ? ImmutableList.copyOf(acl) : null;
- return this;
- }
-
- Builder owner(Acl.Entity owner) {
- this.owner = owner;
- return this;
- }
-
- Builder size(Long size) {
- this.size = size;
- return this;
- }
-
- Builder etag(String etag) {
- this.etag = etag;
- return this;
- }
-
- Builder selfLink(String selfLink) {
- this.selfLink = selfLink;
- return this;
- }
-
- /**
- * Sets the MD5 hash of blob's data. MD5 value must be encoded in base64.
- *
- * @see
- * Hashes and ETags: Best Practices
- */
- public Builder md5(String md5) {
- this.md5 = firstNonNull(md5, Data.nullOf(String.class));
- return this;
- }
-
- /**
- * Sets the CRC32C checksum of blob's data as described in
- * RFC 4960, Appendix B; encoded in
- * base64 in big-endian order.
- *
- * @see
- * Hashes and ETags: Best Practices
- */
- public Builder crc32c(String crc32c) {
- this.crc32c = firstNonNull(crc32c, Data.nullOf(String.class));
- return this;
- }
-
- Builder mediaLink(String mediaLink) {
- this.mediaLink = mediaLink;
- return this;
- }
-
- /**
- * Sets the blob's user provided metadata.
- */
- public Builder metadata(Map metadata) {
- this.metadata = metadata != null
- ? new HashMap<>(metadata) : Data.