Skip to content
Merged
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 @@ -36,6 +36,7 @@
import com.google.firebase.internal.HttpRequestInfo;
import com.google.firebase.internal.SdkUtils;
import com.google.firebase.remoteconfig.internal.RemoteConfigServiceErrorResponse;
import com.google.firebase.remoteconfig.internal.TemplateResponse;

import java.io.IOException;
import java.util.List;
Expand Down Expand Up @@ -94,8 +95,9 @@ public RemoteConfigTemplate getTemplate() throws FirebaseRemoteConfigException {
HttpRequestInfo request = HttpRequestInfo.buildGetRequest(remoteConfigUrl)
.addAllHeaders(COMMON_HEADERS);
IncomingHttpResponse response = httpClient.send(request);
RemoteConfigTemplate parsed = httpClient.parse(response, RemoteConfigTemplate.class);
return parsed.setETag(getETag(response));
TemplateResponse templateResponse = httpClient.parse(response, TemplateResponse.class);
RemoteConfigTemplate template = templateResponse.toRemoteConfigTemplate();
return template.setETag(getETag(response));
}

private String getETag(IncomingHttpResponse response) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* Copyright 2020 Google LLC
*
* 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.firebase.remoteconfig;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.firebase.internal.NonNull;
import com.google.firebase.internal.Nullable;
import com.google.firebase.remoteconfig.internal.TemplateResponse.ParameterResponse;
import com.google.firebase.remoteconfig.internal.TemplateResponse.ParameterValueResponse;

import java.util.HashMap;
import java.util.Map;

/**
* Represents a Remote Config parameter that can be included in a {@link RemoteConfigTemplate}.
* At minimum, a default value or a conditional value must be present for the
* parameter to have any effect.
*/
public final class RemoteConfigParameter {

private RemoteConfigParameterValue defaultValue;
private String description;
private Map<String, RemoteConfigParameterValue> conditionalValues;

/**
* Creates a new {@link RemoteConfigParameter}.
*/
public RemoteConfigParameter() {
conditionalValues = new HashMap<>();
}

/**
* Gets the default value of the parameter.
*
* @return A {@link RemoteConfigParameterValue} instance or null.
*/
@Nullable
public RemoteConfigParameterValue getDefaultValue() {
return defaultValue;
}

/**
* Gets the description of the parameter.
*
* @return The {@link String} description of the parameter or null.
*/
@Nullable
public String getDescription() {
return description;
}

/**
* Gets the conditional values of the parameter.
* The condition name of the highest priority (the one listed first in the
Copy link
Contributor

Choose a reason for hiding this comment

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

This is interesting . . . you mean this gets all the possible values, including the one actually assigned -- for a particular client instance? -- in the top position in the map?

Copy link
Member Author

Choose a reason for hiding this comment

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

This gets all the conditional values assigned for that specific parameter. You can set a default value in a parameter to be used when all the conditional values are evaluated to false. Otherwise, the parameter will use the conditional value with the highest priority. The priority is determined by the order of the conditions are stored in the top-level conditions array of the RemoteConfigTemplate. The top-level conditions array is not part of this PR and will be added in a future PR.
https://firebase.google.com/docs/reference/remote-config/rest/v1/RemoteConfigParameter

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, thanks for the explanation. Parameter evaluation is pretty complex . . . when everything is done, I might try to start a review of our "parameters and conditions" concepts page, just to make sure it's all still accurate.

* {@link RemoteConfigTemplate}'s conditions list) determines the value of this parameter.
*
* @return A non-null map of conditional values.
*/
@NonNull
public Map<String, RemoteConfigParameterValue> getConditionalValues() {
return conditionalValues;
}

/**
* Sets the default value of the parameter.
* This is the value to set the parameter to, when none of the named conditions
Copy link
Contributor

Choose a reason for hiding this comment

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

Does the developer actually set the value? Or does our backend logic?

Copy link
Member Author

Choose a reason for hiding this comment

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

When getting an existing template the backend will set the values for existing Parameters. If the developer wants to create and add new parameters then they can set a default value to set the parameter to, when none of the named conditions evaluate to true.

* evaluate to true.
*
* @param value An {@link RemoteConfigParameterValue} instance.
* @return This {@link RemoteConfigParameter}.
*/
public RemoteConfigParameter setDefaultValue(@Nullable RemoteConfigParameterValue value) {
defaultValue = value;
return this;
}

/**
* Sets the description of the parameter.
* Should not be over 100 characters and may contain any Unicode characters.
*
* @param description The description of the parameter.
* @return This {@link RemoteConfigParameter}.
*/
public RemoteConfigParameter setDescription(@Nullable String description) {
this.description = description;
return this;
}

/**
* Sets the conditional values of the parameter.
Copy link
Contributor

Choose a reason for hiding this comment

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

Again this is maybe just my own confusion, but -- I can see how a developer might want to automate the setting of a list of conditional values. But isn't the actual value sort of set at runtime, after evaluating the conditions?

Copy link
Member Author

Choose a reason for hiding this comment

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

When creating new parameters the developer needs to add conditional values manually. The condition names in conditionalValues map must match the names in the top-level conditions array in RemoteConfigTemplate. Otherwise, the API will throw a condition does not exist error.

* The condition name of the highest priority (the one listed first in the
* {@link RemoteConfigTemplate}'s conditions list) determines the value of this parameter.
*
* @param conditionalValues A non-null map of conditional values.
* @return This {@link RemoteConfigParameter}.
*/
public RemoteConfigParameter setConditionalValues(
@NonNull Map<String, RemoteConfigParameterValue> conditionalValues) {
checkNotNull(conditionalValues, "conditional values must not be null.");
this.conditionalValues = conditionalValues;
return this;
}

ParameterResponse toParameterResponse() {
Map<String, ParameterValueResponse> conditionalResponseValues = new HashMap<>();
for (Map.Entry<String, RemoteConfigParameterValue> entry : conditionalValues.entrySet()) {
conditionalResponseValues.put(entry.getKey(), entry.getValue().toParameterValueResponse());
}
ParameterValueResponse parameterValueResponse = (defaultValue == null) ? null : defaultValue
.toParameterValueResponse();
return new ParameterResponse(parameterValueResponse, description,
conditionalResponseValues);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright 2020 Google LLC
*
* 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.firebase.remoteconfig;

import com.google.firebase.remoteconfig.internal.TemplateResponse.ParameterValueResponse;

/**
* Represents a Remote Config parameter value that can be used in a {@link RemoteConfigTemplate}.
*/
public abstract class RemoteConfigParameterValue {

/**
* Creates a new {@link RemoteConfigParameterValue.Explicit} instance with the given value.
*
* @param value The value of the {@link RemoteConfigParameterValue.Explicit}.
* @return A {@link RemoteConfigParameterValue.Explicit} instance.
*/
public static Explicit of(String value) {
return new Explicit(value);
}

/**
* Creates a new {@link RemoteConfigParameterValue.InAppDefault} instance.
*
* @return A {@link RemoteConfigParameterValue.InAppDefault} instance.
*/
public static InAppDefault inAppDefault() {
return new InAppDefault();
}

abstract ParameterValueResponse toParameterValueResponse();

/**
* Represents an explicit Remote Config parameter value with a {@link String} value that the
* parameter is set to.
*/
public static final class Explicit extends RemoteConfigParameterValue {

private final String value;

private Explicit(String value) {
this.value = value;
}

/**
* Gets the value of {@link RemoteConfigParameterValue.Explicit}.
*
* @return The {@link String} value.
*/
public String getValue() {
return this.value;
}

@Override
ParameterValueResponse toParameterValueResponse() {
return ParameterValueResponse.ofValue(this.value);
}
}

/**
* Represents an in app default parameter value.
*/
public static final class InAppDefault extends RemoteConfigParameterValue {

@Override
ParameterValueResponse toParameterValueResponse() {
return ParameterValueResponse.ofInAppDefaultValue();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,73 @@

package com.google.firebase.remoteconfig;

import com.google.api.client.util.Key;
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.firebase.internal.NonNull;
import com.google.firebase.remoteconfig.internal.TemplateResponse;

import java.util.HashMap;
import java.util.Map;

/**
* Represents a Remote Config template.
*/
public final class RemoteConfigTemplate {

@Key("etag")
private String etag;
private Map<String, RemoteConfigParameter> parameters;

/**
* Creates a new {@link RemoteConfigTemplate}.
*/
public RemoteConfigTemplate() {
parameters = new HashMap<>();
}

/**
* Gets the ETag of the template.
*
* @return The ETag of the template.
*/
public String getETag() {
return this.etag;
}

/**
* Gets the map of parameters of the template.
*
* @return A non-null map of parameter keys to their optional default values and optional
* conditional values.
*/
@NonNull
public Map<String, RemoteConfigParameter> getParameters() {
return this.parameters;
}

/**
* Sets the map of parameters of the template.
*
* @param parameters A non-null map of parameter keys to their optional default values and
* optional conditional values.
* @return This {@link RemoteConfigTemplate} instance.
*/
public RemoteConfigTemplate setParameters(
@NonNull Map<String, RemoteConfigParameter> parameters) {
checkNotNull(parameters, "parameters must not be null.");
this.parameters = parameters;
return this;
}

RemoteConfigTemplate setETag(String etag) {
this.etag = etag;
return this;
}

TemplateResponse toTemplateResponse() {
Map<String, TemplateResponse.ParameterResponse> parameterResponses = new HashMap<>();
for (Map.Entry<String, RemoteConfigParameter> entry : parameters.entrySet()) {
parameterResponses.put(entry.getKey(), entry.getValue().toParameterResponse());
}
return new TemplateResponse(parameterResponses);
}
}
Loading