Skip to content

Commit 197781c

Browse files
committed
Better encapsulation
1 parent 699b811 commit 197781c

File tree

2 files changed

+112
-81
lines changed

2 files changed

+112
-81
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Copyright 2021 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.crashlytics.internal.common;
16+
17+
import androidx.annotation.NonNull;
18+
import com.google.firebase.crashlytics.internal.Logger;
19+
import java.util.ArrayList;
20+
import java.util.Collections;
21+
import java.util.HashMap;
22+
import java.util.List;
23+
import java.util.Map;
24+
25+
/** Handles any key/values for metadata. */
26+
public class KeysMap {
27+
private final Map<String, String> keys = new HashMap<>();
28+
private int maxEntries;
29+
private int maxEntryLength;
30+
31+
public KeysMap(int maxEntries, int maxEntryLength) {
32+
this.maxEntries = maxEntries;
33+
this.maxEntryLength = maxEntryLength;
34+
}
35+
36+
@NonNull
37+
public Map<String, String> getKeys() {
38+
return Collections.unmodifiableMap(keys);
39+
}
40+
41+
public void setKey(String key, String value) {
42+
setSyncKeys(
43+
new HashMap<String, String>() {
44+
{
45+
put(sanitizeKey(key), sanitizeAttribute(value));
46+
}
47+
});
48+
}
49+
50+
public void setKeys(Map<String, String> keysAndValues) {
51+
setSyncKeys(keysAndValues);
52+
}
53+
54+
/** Gatekeeper function for access to attributes or internalKeys */
55+
private synchronized void setSyncKeys(Map<String, String> keysAndValues) {
56+
// We want all access to the keys hashmap to be locked so that there is no way to create
57+
// a race condition and add more than maxEntries keys.
58+
59+
// Update any existing keys first, then add any additional keys
60+
Map<String, String> currentKeys = new HashMap<String, String>();
61+
Map<String, String> newKeys = new HashMap<String, String>();
62+
63+
// Split into current and new keys
64+
for (Map.Entry<String, String> entry : keysAndValues.entrySet()) {
65+
String key = sanitizeKey(entry.getKey());
66+
String value = (entry.getValue() == null) ? "" : sanitizeAttribute(entry.getValue());
67+
if (keys.containsKey(key)) {
68+
currentKeys.put(key, value);
69+
} else {
70+
newKeys.put(key, value);
71+
}
72+
}
73+
74+
keys.putAll(currentKeys);
75+
76+
// Add new keys if there is space
77+
if (keys.size() + newKeys.size() > maxEntries) {
78+
int keySlotsLeft = maxEntries - keys.size();
79+
Logger.getLogger().v("Exceeded maximum number of custom attributes (" + maxEntries + ").");
80+
List<String> newKeyList = new ArrayList<>(newKeys.keySet());
81+
newKeys.keySet().retainAll(newKeyList.subList(0, keySlotsLeft));
82+
}
83+
keys.putAll(newKeys);
84+
}
85+
86+
/** Checks that the key is not null then sanitizes it. */
87+
private String sanitizeKey(String key) {
88+
if (key == null) {
89+
throw new IllegalArgumentException("Custom attribute key must not be null.");
90+
}
91+
return sanitizeAttribute(key);
92+
}
93+
94+
/** Trims the string and truncates it to maxEntryLength. */
95+
public String sanitizeAttribute(String input) {
96+
if (input != null) {
97+
input = input.trim();
98+
if (input.length() > maxEntryLength) {
99+
input = input.substring(0, maxEntryLength);
100+
}
101+
}
102+
return input;
103+
}
104+
}

firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/UserMetadata.java

Lines changed: 8 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@
1616

1717
import androidx.annotation.NonNull;
1818
import androidx.annotation.Nullable;
19-
import com.google.firebase.crashlytics.internal.Logger;
20-
import java.util.ArrayList;
21-
import java.util.Collections;
22-
import java.util.HashMap;
23-
import java.util.List;
2419
import java.util.Map;
2520

2621
/** Handles attributes set by the user. */
@@ -30,8 +25,8 @@ public class UserMetadata {
3025
static final int MAX_INTERNAL_KEY_SIZE = 8192;
3126

3227
private String userId = null;
33-
private final Map<String, String> attributes = new HashMap<>();
34-
private final Map<String, String> internalKeys = new HashMap<>();
28+
private final KeysMap customKeys = new KeysMap(MAX_ATTRIBUTES, MAX_ATTRIBUTE_SIZE);
29+
private final KeysMap internalKeys = new KeysMap(MAX_ATTRIBUTES, MAX_INTERNAL_KEY_SIZE);
3530

3631
public UserMetadata() {}
3732

@@ -41,95 +36,27 @@ public String getUserId() {
4136
}
4237

4338
public void setUserId(String identifier) {
44-
userId = sanitizeAttribute(identifier, MAX_ATTRIBUTE_SIZE);
39+
userId = customKeys.sanitizeAttribute(identifier);
4540
}
4641

4742
@NonNull
4843
public Map<String, String> getCustomKeys() {
49-
return Collections.unmodifiableMap(attributes);
44+
return customKeys.getKeys();
5045
}
5146

5247
public void setCustomKey(String key, String value) {
53-
setSyncCustomKeys(
54-
new HashMap<String, String>() {
55-
{
56-
put(key, value);
57-
}
58-
},
59-
attributes,
60-
MAX_ATTRIBUTE_SIZE);
48+
customKeys.setKey(key, value);
6149
}
6250

6351
public void setCustomKeys(Map<String, String> keysAndValues) {
64-
setSyncCustomKeys(keysAndValues, attributes, MAX_ATTRIBUTE_SIZE);
52+
customKeys.setKeys(keysAndValues);
6553
}
6654

6755
public Map<String, String> getInternalKeys() {
68-
return Collections.unmodifiableMap(internalKeys);
56+
return internalKeys.getKeys();
6957
}
7058

7159
public void setInternalKey(String key, String value) {
72-
setSyncCustomKeys(
73-
new HashMap<String, String>() {
74-
{
75-
put(key, value);
76-
}
77-
},
78-
internalKeys,
79-
MAX_INTERNAL_KEY_SIZE);
80-
}
81-
82-
/** Gatekeeper function for access to attributes or internalKeys */
83-
private synchronized void setSyncCustomKeys(
84-
Map<String, String> keysAndValues, Map<String, String> keys_map, int maxAttributeSize) {
85-
// We want all access to the keys_map hashmap to be locked so that there is no way to create
86-
// a race condition and add more than MAX_ATTRIBUTES keys.
87-
88-
// Update any existing keys first, then add any additional keys
89-
Map<String, String> currentKeys = new HashMap<String, String>();
90-
Map<String, String> newKeys = new HashMap<String, String>();
91-
92-
// Split into current and new keys
93-
for (Map.Entry<String, String> entry : keysAndValues.entrySet()) {
94-
String key = sanitizeKey(entry.getKey(), maxAttributeSize);
95-
String value =
96-
(entry.getValue() == null) ? "" : sanitizeAttribute(entry.getValue(), maxAttributeSize);
97-
if (keys_map.containsKey(key)) {
98-
currentKeys.put(key, value);
99-
} else {
100-
newKeys.put(key, value);
101-
}
102-
}
103-
104-
keys_map.putAll(currentKeys);
105-
106-
// Add new keys if there is space
107-
if (keys_map.size() + newKeys.size() > MAX_ATTRIBUTES) {
108-
int keySlotsLeft = MAX_ATTRIBUTES - keys_map.size();
109-
Logger.getLogger()
110-
.v("Exceeded maximum number of custom attributes (" + MAX_ATTRIBUTES + ").");
111-
List<String> newKeyList = new ArrayList<>(newKeys.keySet());
112-
newKeys.keySet().retainAll(newKeyList.subList(0, keySlotsLeft));
113-
}
114-
keys_map.putAll(newKeys);
115-
}
116-
117-
/** Checks that the key is not null then sanitizes it. */
118-
private static String sanitizeKey(String key, int maxAttributeSize) {
119-
if (key == null) {
120-
throw new IllegalArgumentException("Custom attribute key must not be null.");
121-
}
122-
return sanitizeAttribute(key, maxAttributeSize);
123-
}
124-
125-
/** Trims the string and truncates it to MAX_ATTRIBUTE_SIZE. */
126-
private static String sanitizeAttribute(String input, int maxAttributeSize) {
127-
if (input != null) {
128-
input = input.trim();
129-
if (input.length() > maxAttributeSize) {
130-
input = input.substring(0, maxAttributeSize);
131-
}
132-
}
133-
return input;
60+
internalKeys.setKey(key, value);
13461
}
13562
}

0 commit comments

Comments
 (0)