• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
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.android.adservices.service.measurement;
18 
19 import android.annotation.Nullable;
20 
21 import com.android.adservices.LoggerFactory;
22 import com.android.adservices.service.Flags;
23 import com.android.adservices.service.measurement.registration.FetcherUtil;
24 
25 import org.json.JSONArray;
26 import org.json.JSONException;
27 import org.json.JSONObject;
28 
29 import java.math.BigInteger;
30 import java.util.ArrayList;
31 import java.util.HashMap;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Objects;
36 
37 /** POJO for FilterMap. */
38 public class FilterMap {
39 
40     private Map<String, List<String>> mAttributionFilterMap;
41     private Map<String, FilterValue> mAttributionFilterMapWithLongValue;
42 
43     public static final String RESERVED_PREFIX = "_";
44     public static final String LOOKBACK_WINDOW = "_lookback_window";
45 
FilterMap()46     FilterMap() {
47         mAttributionFilterMap = new HashMap<>();
48         mAttributionFilterMapWithLongValue = new HashMap<>();
49     }
50 
51     @Override
equals(Object obj)52     public boolean equals(Object obj) {
53         if (!(obj instanceof FilterMap)) {
54             return false;
55         }
56         FilterMap attributionFilterMap = (FilterMap) obj;
57         return Objects.equals(mAttributionFilterMap, attributionFilterMap.mAttributionFilterMap)
58                 && Objects.equals(
59                         mAttributionFilterMapWithLongValue,
60                         attributionFilterMap.mAttributionFilterMapWithLongValue);
61     }
62 
63     @Override
hashCode()64     public int hashCode() {
65         return Objects.hash(mAttributionFilterMap, mAttributionFilterMapWithLongValue);
66     }
67 
68     /**
69      * Returns the attribution filter map.
70      *
71      * @deprecated use {@link #getAttributionFilterMapWithLongValue()} instead.
72      */
73     @Deprecated
getAttributionFilterMap()74     public Map<String, List<String>> getAttributionFilterMap() {
75         return mAttributionFilterMap;
76     }
77 
78     /** Returns the attribution filter map with lookback window included. */
getAttributionFilterMapWithLongValue()79     public Map<String, FilterValue> getAttributionFilterMapWithLongValue() {
80         return mAttributionFilterMapWithLongValue;
81     }
82 
83     /**
84      * Returns the long value given the key. {@code key} must be present and the value kind must be
85      * {@link FilterValue.Kind#LONG_VALUE}.
86      */
getLongValue(String key)87     public long getLongValue(String key) {
88         return mAttributionFilterMapWithLongValue.get(key).longValue();
89     }
90 
91     /** Returns whether the attribution filter map is empty. */
isEmpty(Flags flags)92     public boolean isEmpty(Flags flags) {
93         return flags.getMeasurementEnableLookbackWindowFilter()
94                 ? mAttributionFilterMapWithLongValue.isEmpty()
95                 : mAttributionFilterMap.isEmpty();
96     }
97 
98     /**
99      * Returns the string list value given the key. {@code key} must be present and the value kind
100      * must be {@link FilterValue.Kind#STRING_LIST_VALUE}.
101      */
getStringListValue(String key)102     public List<String> getStringListValue(String key) {
103         return mAttributionFilterMapWithLongValue.get(key).stringListValue();
104     }
105 
106     /**
107      * Serializes the object into a {@link JSONObject}.
108      *
109      * @return serialized {@link JSONObject}.
110      */
111     @Nullable
serializeAsJson(Flags flags)112     public JSONObject serializeAsJson(Flags flags) {
113         return flags.getMeasurementEnableLookbackWindowFilter()
114                 ? serializeAsJsonV2()
115                 : serializeAsJson();
116     }
117 
118     @Nullable
serializeAsJson()119     private JSONObject serializeAsJson() {
120         if (mAttributionFilterMap == null) {
121             return null;
122         }
123 
124         try {
125             JSONObject result = new JSONObject();
126             for (String key : mAttributionFilterMap.keySet()) {
127                 result.put(key, new JSONArray(mAttributionFilterMap.get(key)));
128             }
129 
130             return result;
131         } catch (JSONException e) {
132             LoggerFactory.getMeasurementLogger().d(e, "Failed to serialize filtermap.");
133             return null;
134         }
135     }
136 
137     @Nullable
serializeAsJsonV2()138     private JSONObject serializeAsJsonV2() {
139         if (mAttributionFilterMapWithLongValue == null) {
140             return null;
141         }
142 
143         try {
144             JSONObject result = new JSONObject();
145             for (String key : mAttributionFilterMapWithLongValue.keySet()) {
146                 FilterValue value = mAttributionFilterMapWithLongValue.get(key);
147                 switch (value.kind()) {
148                     case LONG_VALUE:
149                         result.put(key, value.longValue());
150                         break;
151                     case STRING_LIST_VALUE:
152                         result.put(key, new JSONArray(value.stringListValue()));
153                         break;
154                 }
155             }
156             return result;
157         } catch (JSONException e) {
158             LoggerFactory.getMeasurementLogger().d(e, "Failed to serialize filtermap.");
159             return null;
160         }
161     }
162 
163     /** Builder for {@link FilterMap}. */
164     public static final class Builder {
165         private final FilterMap mBuilding;
166 
Builder()167         public Builder() {
168             mBuilding = new FilterMap();
169         }
170 
171         /** See {@link FilterMap#getAttributionFilterMapWithLongValue()}. */
setAttributionFilterMapWithLongValue( Map<String, FilterValue> attributionFilterMap)172         public Builder setAttributionFilterMapWithLongValue(
173                 Map<String, FilterValue> attributionFilterMap) {
174             mBuilding.mAttributionFilterMapWithLongValue = attributionFilterMap;
175             return this;
176         }
177 
178         /** Adds filter with long value. */
addLongValue(String key, long value)179         public Builder addLongValue(String key, long value) {
180             mBuilding.mAttributionFilterMapWithLongValue.put(key, FilterValue.ofLong(value));
181             return this;
182         }
183 
184         /** Adds filter with string list value. */
addStringListValue(String key, List<String> value)185         public Builder addStringListValue(String key, List<String> value) {
186             mBuilding.mAttributionFilterMapWithLongValue.put(key, FilterValue.ofStringList(value));
187             return this;
188         }
189 
190         /**
191          * See {@link FilterMap#getAttributionFilterMap()}.
192          *
193          * @deprecated use {@link #setAttributionFilterMapWithLongValue} instead.
194          */
195         @Deprecated
setAttributionFilterMap(Map<String, List<String>> attributionFilterMap)196         public Builder setAttributionFilterMap(Map<String, List<String>> attributionFilterMap) {
197             mBuilding.mAttributionFilterMap = attributionFilterMap;
198             return this;
199         }
200 
201         /** Builds FilterMap from JSONObject. */
buildFilterData(JSONObject jsonObject, Flags flags)202         public Builder buildFilterData(JSONObject jsonObject, Flags flags) throws JSONException {
203             return flags.getMeasurementEnableLookbackWindowFilter()
204                     ? buildFilterDataV2(jsonObject)
205                     : buildFilterData(jsonObject);
206         }
207 
208         /**
209          * Builds FilterMap from JSONObject.
210          *
211          * @deprecated use {@link #buildFilterDataV2} instead.
212          */
213         @Deprecated
buildFilterData(JSONObject jsonObject)214         public Builder buildFilterData(JSONObject jsonObject) throws JSONException {
215             Map<String, List<String>> filterMap = new HashMap<>();
216             Iterator<String> keys = jsonObject.keys();
217             while (keys.hasNext()) {
218                 String key = keys.next();
219                 JSONArray jsonArray = jsonObject.getJSONArray(key);
220                 List<String> filterMapList = new ArrayList<>();
221                 for (int i = 0; i < jsonArray.length(); i++) {
222                     filterMapList.add(jsonArray.getString(i));
223                 }
224                 filterMap.put(key, filterMapList);
225             }
226             mBuilding.mAttributionFilterMap = filterMap;
227             return this;
228         }
229 
230         /** Builds FilterMap from JSONObject with long filter values. */
buildFilterDataV2(JSONObject jsonObject)231         public Builder buildFilterDataV2(JSONObject jsonObject) throws JSONException {
232             Map<String, FilterValue> filterMap = new HashMap<>();
233             Iterator<String> keys = jsonObject.keys();
234             while (keys.hasNext()) {
235                 String key = keys.next();
236                 if (LOOKBACK_WINDOW.equals(key)) {
237                     String value = jsonObject.getString(key);
238                     try {
239                         BigInteger lookbackWindowValue = new BigInteger(value);
240                         filterMap.put(
241                                 key,
242                                 FilterValue.ofLong(
243                                         lookbackWindowValue.compareTo(
244                                                                 FetcherUtil
245                                                                         .BIG_INTEGER_LONG_MAX_VALUE)
246                                                         > 0
247                                                 ? Long.MAX_VALUE
248                                                 : Long.parseLong(value)));
249                     } catch (NumberFormatException e) {
250                         throw new JSONException(
251                                 String.format(
252                                         "Failed to parse long value: %s for key: %s", value, key));
253                     }
254                 } else {
255                     JSONArray jsonArray = jsonObject.getJSONArray(key);
256                     List<String> filterMapList = new ArrayList<>();
257                     for (int i = 0; i < jsonArray.length(); i++) {
258                         filterMapList.add(jsonArray.getString(i));
259                     }
260                     filterMap.put(key, FilterValue.ofStringList(filterMapList));
261                 }
262             }
263             mBuilding.mAttributionFilterMapWithLongValue = filterMap;
264             return this;
265         }
266 
267         /** Build the {@link FilterMap}. */
build()268         public FilterMap build() {
269             return mBuilding;
270         }
271     }
272 }
273