Skip to content

Commit 1a878a1

Browse files
committed
Add Remote Config conditions to template
1 parent f2c5e81 commit 1a878a1

File tree

6 files changed

+290
-4
lines changed

6 files changed

+290
-4
lines changed
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
* Copyright 2020 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.firebase.remoteconfig;
18+
19+
import static com.google.common.base.Preconditions.checkArgument;
20+
import static com.google.common.base.Preconditions.checkNotNull;
21+
22+
import com.google.common.base.Strings;
23+
import com.google.firebase.internal.NonNull;
24+
import com.google.firebase.internal.Nullable;
25+
import com.google.firebase.remoteconfig.internal.TemplateResponse.ConditionResponse;
26+
27+
/**
28+
* Represents a Remote Config condition that can be included in a {@link Template}.
29+
* A condition targets a specific group of users. A list of these conditions make up
30+
* part of a Remote Config template.
31+
*/
32+
public final class Condition {
33+
34+
private String name;
35+
private String expression;
36+
private TagColor tagColor;
37+
38+
/**
39+
* Creates a new {@link Condition}.
40+
*
41+
* @param name A non-null, non-empty, and unique name of this condition.
42+
* @param expression A non-null and non-empty expression of this condition.
43+
*/
44+
public Condition(@NonNull String name, @NonNull String expression) {
45+
checkArgument(!Strings.isNullOrEmpty(name), "condition name must not be null or empty");
46+
checkArgument(!Strings.isNullOrEmpty(expression),
47+
"condition expression must not be null or empty");
48+
this.name = name;
49+
this.expression = expression;
50+
this.tagColor = TagColor.UNSPECIFIED;
51+
}
52+
53+
Condition(@NonNull ConditionResponse conditionResponse) {
54+
checkNotNull(conditionResponse);
55+
this.name = conditionResponse.getName();
56+
this.expression = conditionResponse.getExpression();
57+
if (conditionResponse.getTagColor() == null) {
58+
this.tagColor = TagColor.UNSPECIFIED;
59+
} else {
60+
this.tagColor = TagColor.valueOf(conditionResponse.getTagColor());
61+
}
62+
}
63+
64+
/**
65+
* Gets the name of the condition.
66+
*
67+
* @return The {@link String} name of the condition.
68+
*/
69+
@NonNull
70+
public String getName() {
71+
return name;
72+
}
73+
74+
/**
75+
* Gets the expression of the condition.
76+
*
77+
* @return The {@link String} expression of the condition.
78+
*/
79+
@NonNull
80+
public String getExpression() {
81+
return expression;
82+
}
83+
84+
/**
85+
* Gets the tag color of the condition.
86+
*
87+
* @return The {@link String} tag color of the condition.
88+
*/
89+
@NonNull
90+
public TagColor getTagColor() {
91+
return tagColor;
92+
}
93+
94+
/**
95+
* Sets the name of the condition.
96+
*
97+
* @param name A non-empty and unique name of this condition.
98+
* @return This {@link Condition}.
99+
*/
100+
public Condition setName(@NonNull String name) {
101+
checkArgument(!Strings.isNullOrEmpty(name), "condition name must not be null or empty");
102+
this.name = name;
103+
return this;
104+
}
105+
106+
/**
107+
* Sets the expression of the condition.
108+
*
109+
* <p>See <a href="https://firebase.google.com/docs/remote-config/condition-reference">
110+
* condition expressions</a> for the expected syntax of this field.
111+
*
112+
* @param expression The logic of this condition.
113+
* @return This {@link Condition}.
114+
*/
115+
public Condition setExpression(@NonNull String expression) {
116+
checkArgument(!Strings.isNullOrEmpty(expression),
117+
"condition expression must not be null or empty");
118+
this.expression = expression;
119+
return this;
120+
}
121+
122+
/**
123+
* Sets the tag color of the condition.
124+
*
125+
* <p>The color associated with this condition for display purposes in the Firebase Console.
126+
* Not specifying this value results in the console picking an arbitrary color to associate
127+
* with the condition.
128+
*
129+
* @param tagColor The tag color of this condition.
130+
* Passing null sets to {@code TagColor.UNSPECIFIED}
131+
* @return This {@link Condition}.
132+
*/
133+
public Condition setTagColor(@Nullable TagColor tagColor) {
134+
this.tagColor = tagColor == null ? TagColor.UNSPECIFIED : tagColor;
135+
return this;
136+
}
137+
138+
ConditionResponse toConditionResponse() {
139+
return new ConditionResponse()
140+
.setName(this.name)
141+
.setExpression(this.expression)
142+
.setTagColor(this.tagColor.getColor());
143+
}
144+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.google.firebase.remoteconfig;
2+
3+
public enum TagColor {
4+
BLUE("BLUE"),
5+
BROWN("BROWN"),
6+
CYAN("CYAN"),
7+
DEEP_ORANGE("DEEP_ORANGE"),
8+
GREEN("GREEN"),
9+
INDIGO("INDIGO"),
10+
LIME("LIME"),
11+
ORANGE("ORANGE"),
12+
PINK("PINK"),
13+
PURPLE("PURPLE"),
14+
TEAL("TEAL"),
15+
UNSPECIFIED("CONDITION_DISPLAY_COLOR_UNSPECIFIED");
16+
17+
private final String color;
18+
19+
TagColor(String color) {
20+
this.color = color;
21+
}
22+
23+
public String getColor() {
24+
return color;
25+
}
26+
}

src/main/java/com/google/firebase/remoteconfig/Template.java

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
import com.google.firebase.internal.NonNull;
2222
import com.google.firebase.remoteconfig.internal.TemplateResponse;
2323

24+
import java.util.ArrayList;
2425
import java.util.HashMap;
26+
import java.util.List;
2527
import java.util.Map;
2628

2729
/**
@@ -31,23 +33,32 @@ public final class Template {
3133

3234
private String etag;
3335
private Map<String, Parameter> parameters;
36+
private List<Condition> conditions;
3437

3538
/**
3639
* Creates a new {@link Template}.
3740
*/
3841
public Template() {
3942
parameters = new HashMap<>();
43+
conditions = new ArrayList<>();
4044
}
4145

4246
Template(@NonNull TemplateResponse templateResponse) {
4347
checkNotNull(templateResponse);
4448
this.parameters = new HashMap<>();
49+
this.conditions = new ArrayList<>();
4550
if (templateResponse.getParameters() != null) {
4651
for (Map.Entry<String, TemplateResponse.ParameterResponse> entry
4752
: templateResponse.getParameters().entrySet()) {
4853
this.parameters.put(entry.getKey(), new Parameter(entry.getValue()));
4954
}
5055
}
56+
if (templateResponse.getConditions() != null) {
57+
for (TemplateResponse.ConditionResponse conditionResponse
58+
: templateResponse.getConditions()) {
59+
this.conditions.add(new Condition(conditionResponse));
60+
}
61+
}
5162
}
5263

5364
/**
@@ -70,6 +81,16 @@ public Map<String, Parameter> getParameters() {
7081
return this.parameters;
7182
}
7283

84+
/**
85+
* Gets the list of conditions of the template.
86+
*
87+
* @return A non-null list of conditions
88+
*/
89+
@NonNull
90+
public List<Condition> getConditions() {
91+
return conditions;
92+
}
93+
7394
/**
7495
* Sets the map of parameters of the template.
7596
*
@@ -84,16 +105,35 @@ public Template setParameters(
84105
return this;
85106
}
86107

108+
/**
109+
* Sets the list of conditions of the template.
110+
*
111+
* @param conditions A non-null list of conditions in descending order by priority.
112+
* @return This {@link Template} instance.
113+
*/
114+
public Template setConditions(
115+
@NonNull List<Condition> conditions) {
116+
checkNotNull(conditions, "conditions must not be null.");
117+
this.conditions = conditions;
118+
return this;
119+
}
120+
87121
Template setETag(String etag) {
88122
this.etag = etag;
89123
return this;
90124
}
91125

92126
TemplateResponse toTemplateResponse() {
93127
Map<String, TemplateResponse.ParameterResponse> parameterResponses = new HashMap<>();
94-
for (Map.Entry<String, Parameter> entry : parameters.entrySet()) {
128+
for (Map.Entry<String, Parameter> entry : this.parameters.entrySet()) {
95129
parameterResponses.put(entry.getKey(), entry.getValue().toParameterResponse());
96130
}
97-
return new TemplateResponse().setParameters(parameterResponses);
131+
List<TemplateResponse.ConditionResponse> conditionResponses = new ArrayList<>();
132+
for (Condition condition : this.conditions) {
133+
conditionResponses.add(condition.toConditionResponse());
134+
}
135+
return new TemplateResponse()
136+
.setParameters(parameterResponses)
137+
.setConditions(conditionResponses);
98138
}
99139
}

src/main/java/com/google/firebase/remoteconfig/internal/TemplateResponse.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import com.google.api.client.util.Key;
2020

21+
import java.util.List;
2122
import java.util.Map;
2223

2324
/**
@@ -29,16 +30,29 @@ public final class TemplateResponse {
2930
@Key("parameters")
3031
private Map<String, ParameterResponse> parameters;
3132

33+
@Key("conditions")
34+
private List<ConditionResponse> conditions;
35+
3236
public Map<String, ParameterResponse> getParameters() {
3337
return parameters;
3438
}
3539

40+
public List<ConditionResponse> getConditions() {
41+
return conditions;
42+
}
43+
3644
public TemplateResponse setParameters(
3745
Map<String, ParameterResponse> parameters) {
3846
this.parameters = parameters;
3947
return this;
4048
}
4149

50+
public TemplateResponse setConditions(
51+
List<ConditionResponse> conditions) {
52+
this.conditions = conditions;
53+
return this;
54+
}
55+
4256
/**
4357
* The Data Transfer Object for parsing Remote Config parameter responses from the
4458
* Remote Config service.
@@ -114,4 +128,47 @@ public ParameterValueResponse setUseInAppDefault(boolean useInAppDefault) {
114128
return this;
115129
}
116130
}
131+
132+
/**
133+
* The Data Transfer Object for parsing Remote Config condition responses from the
134+
* Remote Config service.
135+
**/
136+
public static final class ConditionResponse {
137+
138+
@Key("name")
139+
private String name;
140+
141+
@Key("expression")
142+
private String expression;
143+
144+
@Key("tagColor")
145+
private String tagColor;
146+
147+
public String getName() {
148+
return name;
149+
}
150+
151+
public String getExpression() {
152+
return expression;
153+
}
154+
155+
public String getTagColor() {
156+
return tagColor;
157+
}
158+
159+
public ConditionResponse setName(String name) {
160+
this.name = name;
161+
return this;
162+
}
163+
164+
public ConditionResponse setExpression(String expression) {
165+
this.expression = expression;
166+
return this;
167+
}
168+
169+
public ConditionResponse setTagColor(String tagColor) {
170+
this.tagColor = tagColor;
171+
return this;
172+
}
173+
}
117174
}

src/test/java/com/google/firebase/remoteconfig/FirebaseRemoteConfigClientImplTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import com.google.firebase.testing.TestUtils;
4646

4747
import java.io.IOException;
48+
import java.util.ArrayList;
4849
import java.util.List;
4950
import java.util.Map;
5051

@@ -86,6 +87,7 @@ public void testGetTemplate() throws Exception {
8687

8788
Template template = client.getTemplate();
8889

90+
// Check Parameters
8991
assertEquals(TEST_ETAG, template.getETag());
9092
Map<String, Parameter> parameters = template.getParameters();
9193
assertEquals(2, parameters.size());
@@ -107,6 +109,24 @@ public void testGetTemplate() throws Exception {
107109
assertTrue(
108110
headerParameter.getDefaultValue() instanceof ParameterValue.InAppDefault);
109111
checkGetRequestHeader(interceptor.getLastRequest());
112+
113+
// Check Conditions
114+
List<Condition> actualConditions = template.getConditions();
115+
List<Condition> expectedConditions = new ArrayList<>();
116+
expectedConditions
117+
.add(new Condition("ios_en", "device.os == 'ios' && device.country in ['us', 'uk']")
118+
.setTagColor(TagColor.INDIGO));
119+
expectedConditions
120+
.add(new Condition("android_en",
121+
"device.os == 'android' && device.country in ['us', 'uk']")
122+
.setTagColor(TagColor.UNSPECIFIED));
123+
assertEquals(expectedConditions.size(), actualConditions.size());
124+
for (int i = 0; i < expectedConditions.size(); i++) {
125+
assertEquals(expectedConditions.get(i).getName(), actualConditions.get(i).getName());
126+
assertEquals(expectedConditions.get(i).getExpression(),
127+
actualConditions.get(i).getExpression());
128+
assertEquals(expectedConditions.get(i).getTagColor(), actualConditions.get(i).getTagColor());
129+
}
110130
}
111131

112132
@Test

0 commit comments

Comments
 (0)