Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,10 @@ interface ProjectAsSource<O extends Opt> {
O asSource();
}

interface HasherSelector extends BucketObjectHmacKeyAllOpt {
Hasher getHasher();
}

/**
* This class extends off {@link ObjectSourceOpt} and {@link ObjectTargetOpt} in order to satisfy
* some the shimming constraints of the subclasses of {@link OptionShim}.
Expand Down Expand Up @@ -589,7 +593,11 @@ static Headers extraHeaders(ImmutableMap<String, String> extraHeaders) {
return new Headers(extraHeaders);
}

static final class Crc32cMatch implements ObjectTargetOpt {
static DefaultHasherSelector defaultHasherSelector() {
return DefaultHasherSelector.INSTANCE;
}

static final class Crc32cMatch implements ObjectTargetOpt, HasherSelector {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool! Thanks for walking through the UnifiedOpts interfaces

private static final long serialVersionUID = 8172282701777561769L;
private final int val;

Expand Down Expand Up @@ -630,6 +638,11 @@ public Mapper<BidiWriteObjectRequest.Builder> bidiWriteObject() {
};
}

@Override
public Hasher getHasher() {
return Hasher.noop();
}

@Override
public int hashCode() {
return Objects.hash(val);
Expand Down Expand Up @@ -1315,7 +1328,7 @@ public Mapper<ListObjectsRequest.Builder> listObjects() {
}

@Deprecated
static final class Md5Match implements ObjectTargetOpt {
static final class Md5Match implements ObjectTargetOpt, HasherSelector {
private static final long serialVersionUID = 5237207911268363887L;
private final String val;

Expand Down Expand Up @@ -1358,6 +1371,11 @@ public Mapper<BidiWriteObjectRequest.Builder> bidiWriteObject() {
};
}

@Override
public Hasher getHasher() {
return Hasher.noop();
}

@Override
public int hashCode() {
return Objects.hash(val);
Expand Down Expand Up @@ -1983,8 +2001,8 @@ public Mapper<ListObjectsRequest.Builder> listObjects() {
}
}

static final class UserProject extends RpcOptVal<String>
implements BucketSourceOpt,
interface BucketObjectHmacKeyAllOpt
extends BucketSourceOpt,
BucketTargetOpt,
BucketListOpt,
ObjectSourceOpt,
Expand All @@ -1993,6 +2011,18 @@ static final class UserProject extends RpcOptVal<String>
HmacKeySourceOpt,
HmacKeyTargetOpt,
HmacKeyListOpt {
@Override
default Mapper<RewriteObjectRequest.Builder> rewriteObject() {
return Mapper.identity();
}

@Override
default Mapper<MoveObjectRequest.Builder> moveObject() {
return Mapper.identity();
}
}

static final class UserProject extends RpcOptVal<String> implements BucketObjectHmacKeyAllOpt {
private static final long serialVersionUID = 3962499996741180460L;

private UserProject(String val) {
Expand All @@ -2004,28 +2034,10 @@ public Mapper<GrpcCallContext> getGrpcMetadataMapper() {
return ctx ->
ctx.withExtraHeaders(ImmutableMap.of("X-Goog-User-Project", ImmutableList.of(val)));
}

@Override
public Mapper<RewriteObjectRequest.Builder> rewriteObject() {
return Mapper.identity();
}

@Override
public Mapper<MoveObjectRequest.Builder> moveObject() {
return Mapper.identity();
}
}

static final class Headers extends RpcOptVal<ImmutableMap<String, String>>
implements BucketSourceOpt,
BucketTargetOpt,
BucketListOpt,
ObjectSourceOpt,
ObjectTargetOpt,
ObjectListOpt,
HmacKeySourceOpt,
HmacKeyTargetOpt,
HmacKeyListOpt {
implements BucketObjectHmacKeyAllOpt {

/**
* The set of header names which are blocked from being able to be provided for an instance of
Expand Down Expand Up @@ -2181,16 +2193,6 @@ private void copyEntries(
}
}
}

@Override
public Mapper<RewriteObjectRequest.Builder> rewriteObject() {
return Mapper.identity();
}

@Override
public Mapper<MoveObjectRequest.Builder> moveObject() {
return Mapper.identity();
}
}

static final class VersionsFilter extends RpcOptVal<@NonNull Boolean> implements ObjectListOpt {
Expand Down Expand Up @@ -2606,6 +2608,17 @@ public String toString() {
}
}

static final class DefaultHasherSelector implements HasherSelector, Opt {
private static final DefaultHasherSelector INSTANCE = new DefaultHasherSelector();

private DefaultHasherSelector() {}

@Override
public Hasher getHasher() {
return Hasher.defaultHasher();
}
}

/**
* Internal "collection" class to represent a set of {@link Opt}s, and to provide useful
* transformations to individual mappers or to resolve any extractors providing a new instance
Expand Down Expand Up @@ -2702,6 +2715,22 @@ Opts<T> projectAsSource() {
return Utils.mapBuild(builder);
}

@VisibleForTesting
HasherSelector getHasherSelector() {
HasherSelector search = defaultHasherSelector();
Predicate<Opt> p = isInstanceOf(HasherSelector.class);
for (T opt : opts) {
if (p.test(opt)) {
search = (HasherSelector) opt;
}
}
return search;
}

Hasher getHasher() {
return getHasherSelector().getHasher();
}

Mapper<GrpcCallContext> grpcMetadataMapper() {
return fuseMappers(GrpcMetadataMapper.class, GrpcMetadataMapper::getGrpcMetadataMapper);
}
Expand Down Expand Up @@ -2754,7 +2783,7 @@ Mapper<ReadObjectRequest.Builder> readObjectRequest() {
return fuseMappers(ObjectSourceOpt.class, ObjectSourceOpt::readObject);
}

public Mapper<BidiReadObjectRequest.Builder> bidiReadObjectRequest() {
Mapper<BidiReadObjectRequest.Builder> bidiReadObjectRequest() {
return fuseMappers(ObjectSourceOpt.class, ObjectSourceOpt::bidiReadObject);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertThrows;

import com.google.cloud.storage.UnifiedOpts.Crc32cMatch;
import com.google.cloud.storage.UnifiedOpts.DefaultHasherSelector;
import com.google.cloud.storage.UnifiedOpts.HasherSelector;
import com.google.cloud.storage.UnifiedOpts.Md5Match;
import com.google.cloud.storage.UnifiedOpts.ObjectSourceOpt;
import com.google.cloud.storage.UnifiedOpts.ObjectTargetOpt;
import com.google.cloud.storage.UnifiedOpts.Opt;
Expand Down Expand Up @@ -146,6 +150,27 @@ public void validateFactoryMethodEnforceNonNull_storage_updateHmacKeyOption() th
validateFactoryMethodEnforceNonNull(Storage.UpdateHmacKeyOption.class);
}

@Test
public void getHasher_selectsLastValue() {
DefaultHasherSelector first = UnifiedOpts.defaultHasherSelector();
Md5Match second = UnifiedOpts.md5Match("asdf");
Crc32cMatch third = UnifiedOpts.crc32cMatch(3);
Opts<HasherSelector> hasherOpts = Opts.from(first, second, third);

HasherSelector actual = hasherOpts.getHasherSelector();
assertThat(actual).isSameInstanceAs(third);
}

@Test
public void hasher_md5Match_noop() {
assertThat(UnifiedOpts.md5Match("xyz").getHasher()).isEqualTo(Hasher.noop());
}

@Test
public void hasher_crc32cMatch_noop() {
assertThat(UnifiedOpts.crc32cMatch(77).getHasher()).isEqualTo(Hasher.noop());
}

@Test
public void transformTo() {
SecretKey key =
Expand All @@ -172,8 +197,8 @@ public byte[] getEncoded() {
UnifiedOpts.encryptionKey(key),
// userProject implements both target and source
UnifiedOpts.userProject("user-project"),
// crc32c is not a source opt or a ProjectToSource opt, it should be excluded
UnifiedOpts.crc32cMatch(1));
// contentType is not a source opt or a ProjectToSource opt, it should be excluded
UnifiedOpts.setContentType("application/octet-stream"));
Opts<ObjectSourceOpt> sourceOpts = targetOpts.transformTo(ObjectSourceOpt.class);

Opts<ObjectSourceOpt> expected =
Expand Down