1 /*
2  * Copyright (C) 2023 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 com.android.adservices.LoggerFactory;
20 import com.android.adservices.service.measurement.util.UnsignedLong;
21 
22 import org.json.JSONException;
23 import org.json.JSONObject;
24 
25 import java.util.Objects;
26 
27 /** POJO for attributed trigger.  */
28 public class AttributedTrigger {
29     private final String mTriggerId;
30     private final long mPriority;
31     private final UnsignedLong mTriggerData;
32     private final long mValue;
33     private final long mTriggerTime;
34     private final UnsignedLong mDedupKey;
35     private final UnsignedLong mDebugKey;
36     private final Boolean mHasSourceDebugKey;
37     private long mContribution;
38 
39     @Override
equals(Object obj)40     public boolean equals(Object obj) {
41         if (!(obj instanceof AttributedTrigger)) {
42             return false;
43         }
44         AttributedTrigger t = (AttributedTrigger) obj;
45 
46         return mTriggerId.equals(t.mTriggerId)
47                 && mPriority == t.mPriority
48                 && Objects.equals(mTriggerData, t.mTriggerData)
49                 && mValue == t.mValue
50                 && mTriggerTime == t.mTriggerTime
51                 && Objects.equals(mDedupKey, t.mDedupKey)
52                 && Objects.equals(mDebugKey, t.mDebugKey)
53                 && Objects.equals(mHasSourceDebugKey, t.mHasSourceDebugKey);
54     }
55 
56     @Override
hashCode()57     public int hashCode() {
58         return Objects.hash(
59                 mTriggerId,
60                 mPriority,
61                 mTriggerData,
62                 mValue,
63                 mTriggerTime,
64                 mDedupKey,
65                 mDebugKey,
66                 mHasSourceDebugKey);
67     }
68 
AttributedTrigger(JSONObject json)69     public AttributedTrigger(JSONObject json) throws JSONException {
70         mTriggerId = json.getString(JsonKeys.TRIGGER_ID);
71         if (!json.isNull(TriggerSpecs.FlexEventReportJsonKeys.PRIORITY)) {
72             mPriority = json.getLong(TriggerSpecs.FlexEventReportJsonKeys.PRIORITY);
73         } else {
74             mPriority = 0L;
75         }
76         if (!json.isNull(TriggerSpecs.FlexEventReportJsonKeys.TRIGGER_DATA)) {
77             mTriggerData = new UnsignedLong(
78                     json.getString(TriggerSpecs.FlexEventReportJsonKeys.TRIGGER_DATA));
79         } else {
80             mTriggerData = null;
81         }
82         if (!json.isNull(TriggerSpecs.FlexEventReportJsonKeys.VALUE)) {
83             mValue = json.getLong(TriggerSpecs.FlexEventReportJsonKeys.VALUE);
84         } else {
85             mValue = 0L;
86         }
87         if (!json.isNull(TriggerSpecs.FlexEventReportJsonKeys.TRIGGER_TIME)) {
88             mTriggerTime = json.getLong(TriggerSpecs.FlexEventReportJsonKeys.TRIGGER_TIME);
89         } else {
90             mTriggerTime = 0L;
91         }
92         if (!json.isNull(JsonKeys.DEDUP_KEY)) {
93             mDedupKey = new UnsignedLong(
94                     json.getString(JsonKeys.DEDUP_KEY));
95         } else {
96             mDedupKey = null;
97         }
98         if (!json.isNull(JsonKeys.DEBUG_KEY)) {
99             mDebugKey = new UnsignedLong(
100                     json.getString(JsonKeys.DEBUG_KEY));
101         } else {
102             mDebugKey = null;
103         }
104         if (!json.isNull(JsonKeys.HAS_SOURCE_DEBUG_KEY)) {
105             mHasSourceDebugKey = json.getBoolean(JsonKeys.HAS_SOURCE_DEBUG_KEY);
106         } else {
107             mHasSourceDebugKey = null;
108         }
109     }
110 
AttributedTrigger( String triggerId, UnsignedLong triggerData, UnsignedLong dedupKey)111     public AttributedTrigger(
112             String triggerId,
113             UnsignedLong triggerData,
114             UnsignedLong dedupKey) {
115         mTriggerId = triggerId;
116         mDedupKey = dedupKey;
117         mDebugKey = null;
118         mHasSourceDebugKey = null;
119         mPriority = 0L;
120         mTriggerData = triggerData;
121         mValue = 0L;
122         mTriggerTime = 0L;
123     }
124 
AttributedTrigger( String triggerId, long priority, UnsignedLong triggerData, long value, long triggerTime, UnsignedLong dedupKey, UnsignedLong debugKey, boolean hasSourceDebugKey)125     public AttributedTrigger(
126             String triggerId,
127             long priority,
128             UnsignedLong triggerData,
129             long value,
130             long triggerTime,
131             UnsignedLong dedupKey,
132             UnsignedLong debugKey,
133             boolean hasSourceDebugKey) {
134         mTriggerId = triggerId;
135         mPriority = priority;
136         mTriggerData = triggerData;
137         mValue = value;
138         mTriggerTime = triggerTime;
139         mDedupKey = dedupKey;
140         mDebugKey = debugKey;
141         mHasSourceDebugKey = hasSourceDebugKey;
142     }
143 
getTriggerId()144     public String getTriggerId() {
145         return mTriggerId;
146     }
147 
getPriority()148     public long getPriority() {
149         return mPriority;
150     }
151 
getTriggerData()152     public UnsignedLong getTriggerData() {
153         return mTriggerData;
154     }
155 
getValue()156     public long getValue() {
157         return mValue;
158     }
159 
getTriggerTime()160     public long getTriggerTime() {
161         return mTriggerTime;
162     }
163 
getDedupKey()164     public UnsignedLong getDedupKey() {
165         return mDedupKey;
166     }
167 
getDebugKey()168     public UnsignedLong getDebugKey() {
169         return mDebugKey;
170     }
171 
172     /**
173      * Returns whether the source debug key was permitted and populated when this trigger was
174      * attributed.
175      */
hasSourceDebugKey()176     public boolean hasSourceDebugKey() {
177         return mHasSourceDebugKey;
178     }
179 
getContribution()180     public long getContribution() {
181         return mContribution;
182     }
183 
184     /** Adds to the attributed trigger's contribution. */
addContribution(long contribution)185     public void addContribution(long contribution) {
186         mContribution += contribution;
187     }
188 
189     /** Returns the remaining value this attributed trigger can contribute to summary buckets. */
remainingValue()190     public long remainingValue() {
191         return getValue() - getContribution();
192     }
193 
194     /** Encodes the attributed trigger to a JSONObject */
encodeToJson()195     public JSONObject encodeToJson() {
196         JSONObject json = new JSONObject();
197         try {
198             json.put(JsonKeys.TRIGGER_ID, mTriggerId);
199             json.put(
200                     TriggerSpecs.FlexEventReportJsonKeys.TRIGGER_DATA,
201                     mTriggerData.toString());
202             json.put(JsonKeys.DEDUP_KEY, mDedupKey.toString());
203         } catch (JSONException e) {
204             LoggerFactory.getMeasurementLogger()
205                     .e(e, "AttributedTrigger::encodeToJson cannot encode to JSON");
206             return null;
207         }
208         return json;
209     }
210 
211     /** Encodes the attributed trigger to a JSONObject */
encodeToJsonFlexApi()212     public JSONObject encodeToJsonFlexApi() {
213         JSONObject json = new JSONObject();
214         try {
215             json.put(JsonKeys.TRIGGER_ID, mTriggerId);
216             json.put(
217                     TriggerSpecs.FlexEventReportJsonKeys.TRIGGER_DATA,
218                     mTriggerData.toString());
219             json.put(TriggerSpecs.FlexEventReportJsonKeys.TRIGGER_TIME, mTriggerTime);
220             json.put(TriggerSpecs.FlexEventReportJsonKeys.VALUE, mValue);
221             if (mDedupKey != null) {
222                 json.put(JsonKeys.DEDUP_KEY, mDedupKey.toString());
223             }
224             if (mDebugKey != null) {
225                 json.put(JsonKeys.DEBUG_KEY, mDebugKey.toString());
226             }
227             json.put(JsonKeys.HAS_SOURCE_DEBUG_KEY, mHasSourceDebugKey);
228             json.put(TriggerSpecs.FlexEventReportJsonKeys.PRIORITY, mPriority);
229         } catch (JSONException e) {
230             LoggerFactory.getMeasurementLogger()
231                     .e(
232                             e,
233                             "AttributedTrigger::encodeToJsonFlexApi cannot encode to JSON");
234             return null;
235         }
236         return json;
237     }
238 
239     private interface JsonKeys {
240         String TRIGGER_ID = "trigger_id";
241         String DEDUP_KEY = "dedup_key";
242         String DEBUG_KEY = "debug_key";
243         String HAS_SOURCE_DEBUG_KEY = "has_source_debug_key";
244     }
245 }
246