Skip to content

Commit 1431f0d

Browse files
committed
Refactor IAM-related classes to be ready to support more services
- Remove resourcemanager's Policy class - Rename core's IamPolicy to Policy - Add Role class to hold string values for roles - Add Policy.Marshaller and Policy.DefaultMarshaller classes to convert Policy to/from gRPC protos - Add PolicyMarshaller to resourcemanager to convert Policy to/from resourcemanager's protos - Update READMEs, javadoc and examples
1 parent 7cd60df commit 1431f0d

File tree

20 files changed

+519
-448
lines changed

20 files changed

+519
-448
lines changed

google-cloud-core/pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,12 @@
111111
<dependency>
112112
<groupId>com.google.api.grpc</groupId>
113113
<artifactId>grpc-google-common-protos</artifactId>
114-
<version>0.0.7</version>
114+
<version>0.0.9</version>
115+
</dependency>
116+
<dependency>
117+
<groupId>com.google.api.grpc</groupId>
118+
<artifactId>grpc-google-iam-v1</artifactId>
119+
<version>0.0.9</version>
115120
</dependency>
116121
</dependencies>
117122
</project>

google-cloud-core/src/main/java/com/google/cloud/Identity.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@
2424
import java.util.Objects;
2525

2626
/**
27-
* An identity in an {@link IamPolicy}. The following types of identities are permitted in IAM
28-
* policies:
27+
* An identity in a {@link Policy}. The following types of identities are permitted in IAM policies:
2928
* <ul>
3029
* <li>Google account
3130
* <li>Service account
@@ -161,6 +160,11 @@ public static Identity domain(String domain) {
161160
return new Identity(Type.DOMAIN, checkNotNull(domain));
162161
}
163162

163+
@Override
164+
public String toString() {
165+
return strValue();
166+
}
167+
164168
@Override
165169
public int hashCode() {
166170
return Objects.hash(value, type);

google-cloud-core/src/main/java/com/google/cloud/IamPolicy.java renamed to google-cloud-core/src/main/java/com/google/cloud/Policy.java

Lines changed: 129 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,21 @@
1919
import static com.google.common.base.Preconditions.checkArgument;
2020
import static com.google.common.base.Preconditions.checkNotNull;
2121

22+
import com.google.common.base.Function;
23+
import com.google.common.base.MoreObjects;
2224
import com.google.common.collect.ImmutableMap;
2325
import com.google.common.collect.ImmutableSet;
26+
import com.google.common.collect.Lists;
27+
import com.google.protobuf.ByteString;
2428

2529
import java.io.Serializable;
30+
import java.util.ArrayList;
2631
import java.util.Arrays;
2732
import java.util.HashMap;
2833
import java.util.HashSet;
2934
import java.util.LinkedHashSet;
35+
import java.util.LinkedList;
36+
import java.util.List;
3037
import java.util.Map;
3138
import java.util.Objects;
3239
import java.util.Set;
@@ -37,69 +44,127 @@
3744
* a set of identities to a role, where the identities can be user accounts, Google groups, Google
3845
* domains, and service accounts. A role is a named list of permissions defined by IAM.
3946
*
40-
* @param <R> the data type of roles (should be serializable)
4147
* @see <a href="https://cloud.google.com/iam/reference/rest/v1/Policy">Policy</a>
4248
*/
43-
public abstract class IamPolicy<R> implements Serializable {
49+
public final class Policy implements Serializable {
4450

45-
private static final long serialVersionUID = 1114489978726897720L;
51+
private static final long serialVersionUID = -3348914530232544290L;
4652

47-
private final Map<R, Set<Identity>> bindings;
53+
private final Map<Role, Set<Identity>> bindings;
4854
private final String etag;
49-
private final Integer version;
55+
private final int version;
56+
57+
public abstract static class Marshaller<T> {
58+
59+
protected static final Function<String, Identity> IDENTITY_VALUE_OF_FUNCTION =
60+
new Function<String, Identity>() {
61+
@Override
62+
public Identity apply(String identityPb) {
63+
return Identity.valueOf(identityPb);
64+
}
65+
};
66+
protected static final Function<Identity, String> IDENTITY_STR_VALUE_FUNCTION =
67+
new Function<Identity, String>() {
68+
@Override
69+
public String apply(Identity identity) {
70+
return identity.strValue();
71+
}
72+
};
73+
74+
protected abstract Policy fromPb(T policyPb);
75+
76+
protected abstract T toPb(Policy policy);
77+
}
78+
79+
public static class DefaultMarshaller extends Marshaller<com.google.iam.v1.Policy> {
80+
81+
@Override
82+
protected Policy fromPb(com.google.iam.v1.Policy policyPb) {
83+
Map<Role, Set<Identity>> bindings = new HashMap<>();
84+
for (com.google.iam.v1.Binding bindingPb : policyPb.getBindingsList()) {
85+
bindings.put(Role.of(bindingPb.getRole()),
86+
ImmutableSet.copyOf(
87+
Lists.transform(bindingPb.getMembersList(), IDENTITY_VALUE_OF_FUNCTION)));
88+
}
89+
return builder()
90+
.bindings(bindings)
91+
.etag(policyPb.getEtag().size() == 0 ? null : policyPb.getEtag().toStringUtf8())
92+
.version(policyPb.getVersion())
93+
.build();
94+
}
95+
96+
@Override
97+
protected com.google.iam.v1.Policy toPb(Policy policy) {
98+
com.google.iam.v1.Policy.Builder policyBuilder = com.google.iam.v1.Policy.newBuilder();
99+
List<com.google.iam.v1.Binding> bindingPbList = new LinkedList<>();
100+
for (Map.Entry<Role, Set<Identity>> binding : policy.bindings().entrySet()) {
101+
com.google.iam.v1.Binding.Builder bindingBuilder = com.google.iam.v1.Binding.newBuilder();
102+
bindingBuilder.setRole(binding.getKey().value());
103+
bindingBuilder.addAllMembers(
104+
Lists.transform(new ArrayList<>(binding.getValue()), IDENTITY_STR_VALUE_FUNCTION));
105+
bindingPbList.add(bindingBuilder.build());
106+
}
107+
policyBuilder.addAllBindings(bindingPbList);
108+
if (policy.etag != null) {
109+
policyBuilder.setEtag(ByteString.copyFromUtf8(policy.etag));
110+
}
111+
policyBuilder.setVersion(policy.version);
112+
return policyBuilder.build();
113+
}
114+
}
50115

51116
/**
52-
* Builder for an IAM Policy.
53-
*
54-
* @param <R> the data type of roles
55-
* @param <B> the subclass extending this abstract builder
117+
* A builder for {@code Policy} objects.
56118
*/
57-
public abstract static class Builder<R, B extends Builder<R, B>> {
119+
public static class Builder {
58120

59-
private final Map<R, Set<Identity>> bindings = new HashMap<>();
121+
private final Map<Role, Set<Identity>> bindings = new HashMap<>();
60122
private String etag;
61-
private Integer version;
123+
private int version;
62124

63-
/**
64-
* Constructor for IAM Policy builder.
65-
*/
66125
protected Builder() {}
67126

127+
protected Builder(Policy policy) {
128+
bindings(policy.bindings);
129+
etag(policy.etag);
130+
version(policy.version);
131+
}
132+
68133
/**
69134
* Replaces the builder's map of bindings with the given map of bindings.
70135
*
71136
* @throws NullPointerException if the given map is null or contains any null keys or values
72137
* @throws IllegalArgumentException if any identities in the given map are null
73138
*/
74-
public final B bindings(Map<R, Set<Identity>> bindings) {
139+
public final Builder bindings(Map<Role, Set<Identity>> bindings) {
75140
checkNotNull(bindings, "The provided map of bindings cannot be null.");
76-
for (Map.Entry<R, Set<Identity>> binding : bindings.entrySet()) {
141+
for (Map.Entry<Role, Set<Identity>> binding : bindings.entrySet()) {
77142
checkNotNull(binding.getKey(), "The role cannot be null.");
78143
Set<Identity> identities = binding.getValue();
79144
checkNotNull(identities, "A role cannot be assigned to a null set of identities.");
80145
checkArgument(!identities.contains(null), "Null identities are not permitted.");
81146
}
82147
this.bindings.clear();
83-
for (Map.Entry<R, Set<Identity>> binding : bindings.entrySet()) {
84-
this.bindings.put(binding.getKey(), new HashSet<Identity>(binding.getValue()));
148+
for (Map.Entry<Role, Set<Identity>> binding : bindings.entrySet()) {
149+
this.bindings.put(binding.getKey(), new HashSet<>(binding.getValue()));
85150
}
86-
return self();
151+
return this;
87152
}
88153

89154
/**
90155
* Removes the role (and all identities associated with that role) from the policy.
91156
*/
92-
public final B removeRole(R role) {
157+
public final Builder removeRole(Role role) {
93158
bindings.remove(role);
94-
return self();
159+
return this;
95160
}
96161

97162
/**
98163
* Adds one or more identities to the policy under the role specified.
99164
*
100165
* @throws NullPointerException if the role or any of the identities is null.
101166
*/
102-
public final B addIdentity(R role, Identity first, Identity... others) {
167+
public final Builder addIdentity(Role role, Identity first, Identity... others) {
103168
String nullIdentityMessage = "Null identities are not permitted.";
104169
checkNotNull(first, nullIdentityMessage);
105170
checkNotNull(others, nullIdentityMessage);
@@ -111,18 +176,18 @@ public final B addIdentity(R role, Identity first, Identity... others) {
111176
toAdd.addAll(Arrays.asList(others));
112177
Set<Identity> identities = bindings.get(checkNotNull(role, "The role cannot be null."));
113178
if (identities == null) {
114-
identities = new HashSet<Identity>();
179+
identities = new HashSet<>();
115180
bindings.put(role, identities);
116181
}
117182
identities.addAll(toAdd);
118-
return self();
183+
return this;
119184
}
120185

121186
/**
122187
* Removes one or more identities from an existing binding. Does nothing if the binding
123188
* associated with the provided role doesn't exist.
124189
*/
125-
public final B removeIdentity(R role, Identity first, Identity... others) {
190+
public final Builder removeIdentity(Role role, Identity first, Identity... others) {
126191
Set<Identity> identities = bindings.get(role);
127192
if (identities != null) {
128193
identities.remove(first);
@@ -131,7 +196,7 @@ public final B removeIdentity(R role, Identity first, Identity... others) {
131196
if (identities != null && identities.isEmpty()) {
132197
bindings.remove(role);
133198
}
134-
return self();
199+
return this;
135200
}
136201

137202
/**
@@ -145,31 +210,31 @@ public final B removeIdentity(R role, Identity first, Identity... others) {
145210
* applied to the same version of the policy. If no etag is provided in the call to
146211
* setIamPolicy, then the existing policy is overwritten blindly.
147212
*/
148-
protected final B etag(String etag) {
213+
protected final Builder etag(String etag) {
149214
this.etag = etag;
150-
return self();
215+
return this;
151216
}
152217

153218
/**
154219
* Sets the version of the policy. The default version is 0, meaning only the "owner", "editor",
155220
* and "viewer" roles are permitted. If the version is 1, you may also use other roles.
156221
*/
157-
protected final B version(Integer version) {
222+
protected final Builder version(int version) {
158223
this.version = version;
159-
return self();
224+
return this;
160225
}
161226

162-
@SuppressWarnings("unchecked")
163-
private B self() {
164-
return (B) this;
227+
/**
228+
* Creates a {@code Policy} object.
229+
*/
230+
public final Policy build() {
231+
return new Policy(this);
165232
}
166-
167-
public abstract IamPolicy<R> build();
168233
}
169234

170-
protected IamPolicy(Builder<R, ? extends Builder<R, ?>> builder) {
171-
ImmutableMap.Builder<R, Set<Identity>> bindingsBuilder = ImmutableMap.builder();
172-
for (Map.Entry<R, Set<Identity>> binding : builder.bindings.entrySet()) {
235+
private Policy(Builder builder) {
236+
ImmutableMap.Builder<Role, Set<Identity>> bindingsBuilder = ImmutableMap.builder();
237+
for (Map.Entry<Role, Set<Identity>> binding : builder.bindings.entrySet()) {
173238
bindingsBuilder.put(binding.getKey(), ImmutableSet.copyOf(binding.getValue()));
174239
}
175240
this.bindings = bindingsBuilder.build();
@@ -180,12 +245,14 @@ protected IamPolicy(Builder<R, ? extends Builder<R, ?>> builder) {
180245
/**
181246
* Returns a builder containing the properties of this IAM Policy.
182247
*/
183-
public abstract Builder<R, ? extends Builder<R, ?>> toBuilder();
248+
public Builder toBuilder() {
249+
return new Builder(this);
250+
}
184251

185252
/**
186253
* The map of bindings that comprises the policy.
187254
*/
188-
public Map<R, Set<Identity>> bindings() {
255+
public Map<Role, Set<Identity>> bindings() {
189256
return bindings;
190257
}
191258

@@ -208,27 +275,42 @@ public String etag() {
208275
* Sets the version of the policy. The default version is 0, meaning only the "owner", "editor",
209276
* and "viewer" roles are permitted. If the version is 1, you may also use other roles.
210277
*/
211-
public Integer version() {
278+
public int version() {
212279
return version;
213280
}
214281

215282
@Override
216-
public final int hashCode() {
283+
public String toString() {
284+
return MoreObjects.toStringHelper(this)
285+
.add("bindings", bindings)
286+
.add("etag", etag)
287+
.add("version", version)
288+
.toString();
289+
}
290+
291+
@Override
292+
public int hashCode() {
217293
return Objects.hash(getClass(), bindings, etag, version);
218294
}
219295

220296
@Override
221-
public final boolean equals(Object obj) {
297+
public boolean equals(Object obj) {
222298
if (obj == this) {
223299
return true;
224300
}
225-
if (obj == null || !obj.getClass().equals(getClass())) {
301+
if (!(obj instanceof Policy)) {
226302
return false;
227303
}
228-
@SuppressWarnings("rawtypes")
229-
IamPolicy other = (IamPolicy) obj;
304+
Policy other = (Policy) obj;
230305
return Objects.equals(bindings, other.bindings())
231306
&& Objects.equals(etag, other.etag())
232307
&& Objects.equals(version, other.version());
233308
}
309+
310+
/**
311+
* Returns a builder for {@code Policy} objects.
312+
*/
313+
public static Builder builder() {
314+
return new Builder();
315+
}
234316
}

0 commit comments

Comments
 (0)