Skip to content

Commit f540bd1

Browse files
refactor: Migrate Internal ProviderPersistence class to kotlin
1 parent 35ae7c8 commit f540bd1

File tree

2 files changed

+132
-149
lines changed

2 files changed

+132
-149
lines changed

android-core/src/main/java/com/mparticle/internal/ProviderPersistence.java

Lines changed: 0 additions & 149 deletions
This file was deleted.
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package com.mparticle.internal
2+
3+
import android.content.Context
4+
import com.mparticle.internal.MPUtility.isEmpty
5+
import org.json.JSONObject
6+
import java.security.SecureRandom
7+
import java.util.Locale
8+
import java.util.UUID
9+
import java.util.regex.Pattern
10+
11+
/**
12+
* This class is responsible for pulling persistence from files from *other* SDKs, and serializing itself as a part of a batch.
13+
* The idea here is that a customer may want to remove an SDK from their app and move it
14+
* server side via mParticle. Rather than start from stratch, it's crucial that we can query data that
15+
* the given SDK had been storing client-side.
16+
*/
17+
internal class ProviderPersistence(config: JSONObject, context: Context) : JSONObject() {
18+
init {
19+
val configPersistence = config.getJSONArray(KEY_PERSISTENCE)
20+
for (i in 0 until configPersistence.length()) {
21+
val values = JSONObject()
22+
if (configPersistence.getJSONObject(i).has(KEY_PERSISTENCE_ANDROID)) {
23+
val files = configPersistence.getJSONObject(i).getJSONArray(KEY_PERSISTENCE_ANDROID)
24+
25+
for (fileIndex in 0 until files.length()) {
26+
val fileObject = files.getJSONObject(fileIndex)
27+
val preferences =
28+
context.getSharedPreferences(fileObject.getString(KEY_PERSISTENCE_FILE), fileObject.getInt(KEY_PERSISTENCE_MODE))
29+
val fileObjects = fileObject.getJSONArray(KEY_PERSISTENCE_KEY_LIST)
30+
val editor = preferences.edit()
31+
for (keyIndex in 0 until fileObjects.length()) {
32+
val type = fileObjects.getJSONObject(keyIndex).getInt(KEY_PERSISTENCE_TYPE)
33+
val key = fileObjects.getJSONObject(keyIndex).getString(KEY_PERSISTENCE_KEY)
34+
val mpKey = fileObjects.getJSONObject(keyIndex).getString(KEY_PERSISTENCE_MPVAR)
35+
val mpPersistenceKey = MPPREFIX + mpKey
36+
if (preferences.contains(mpPersistenceKey)) {
37+
values.put(mpKey, preferences.getString(mpPersistenceKey, null))
38+
} else {
39+
var resolvedValue: String? = null
40+
if (preferences.contains(key)) {
41+
when (type) {
42+
PERSISTENCE_TYPE_STRING -> resolvedValue = preferences.getString(key, resolvedValue)
43+
PERSISTENCE_TYPE_INT -> resolvedValue = preferences.getInt(key, 0).toString()
44+
PERSISTENCE_TYPE_BOOLEAN -> resolvedValue = preferences.getBoolean(key, false).toString()
45+
PERSISTENCE_TYPE_FLOAT -> resolvedValue = preferences.getFloat(key, 0f).toString()
46+
PERSISTENCE_TYPE_LONG -> resolvedValue = preferences.getLong(key, 0).toString()
47+
}
48+
} else {
49+
resolvedValue = applyMacro(fileObjects.getJSONObject(keyIndex).getString(KEY_PERSISTENCE_DEFAULT))
50+
}
51+
52+
editor.putString(mpPersistenceKey, resolvedValue)
53+
editor.apply()
54+
values.put(mpKey, resolvedValue)
55+
}
56+
}
57+
}
58+
}
59+
put(configPersistence.getJSONObject(i).getInt(KEY_PERSISTENCE_ID).toString(), values)
60+
}
61+
}
62+
63+
companion object {
64+
const val KEY_PERSISTENCE: String = "cms"
65+
private const val KEY_PERSISTENCE_ID = "id"
66+
private const val KEY_PERSISTENCE_ANDROID = "pr"
67+
private const val KEY_PERSISTENCE_FILE = "f"
68+
private const val KEY_PERSISTENCE_MODE = "m"
69+
private const val KEY_PERSISTENCE_KEY_LIST = "ps"
70+
private const val KEY_PERSISTENCE_KEY = "k"
71+
private const val KEY_PERSISTENCE_TYPE = "t"
72+
private const val KEY_PERSISTENCE_MPVAR = "n"
73+
private const val KEY_PERSISTENCE_DEFAULT = "d"
74+
private const val MPPREFIX = "mp::"
75+
76+
private const val PERSISTENCE_TYPE_STRING = 1
77+
private const val PERSISTENCE_TYPE_INT = 2
78+
private const val PERSISTENCE_TYPE_BOOLEAN = 3
79+
private const val PERSISTENCE_TYPE_FLOAT = 4
80+
private const val PERSISTENCE_TYPE_LONG = 5
81+
82+
83+
private const val MACRO_GUID_NO_DASHES = "%gn%"
84+
private const val MACRO_OMNITURE_AID = "%oaid%"
85+
private const val MACRO_GUID = "%g%"
86+
private const val MACRO_TIMESTAMP = "%ts%"
87+
private const val MACRO_GUID_LEAST_SIG = "%glsb%"
88+
89+
/**
90+
* Macros are used so that the /config API call can come from a CDN (not user-specific).
91+
*/
92+
private fun applyMacro(defaultString: String): String {
93+
var defaultString = defaultString
94+
if (!isEmpty(defaultString) && defaultString.startsWith("%")) {
95+
defaultString = defaultString.lowercase(Locale.getDefault())
96+
if (defaultString.equals(MACRO_GUID_NO_DASHES, ignoreCase = true)) {
97+
return UUID.randomUUID().toString().replace("-", "")
98+
} else if (defaultString == MACRO_OMNITURE_AID) {
99+
return generateAID()
100+
} else if (defaultString == MACRO_GUID) {
101+
return UUID.randomUUID().toString()
102+
} else if (defaultString == MACRO_TIMESTAMP) {
103+
return System.currentTimeMillis().toString()
104+
} else if (defaultString == MACRO_GUID_LEAST_SIG) {
105+
return UUID.randomUUID().leastSignificantBits.toString()
106+
}
107+
}
108+
return defaultString
109+
}
110+
111+
private fun generateAID(): String {
112+
var uuid = UUID.randomUUID().toString().replace("-", "")
113+
uuid = uuid.uppercase(Locale.getDefault())
114+
115+
val firstPattern = Pattern.compile("^[89A-F]")
116+
val secondPattern = Pattern.compile("^[4-9A-F]")
117+
val firstMatcher = firstPattern.matcher(uuid.substring(0, 16))
118+
val secondMatcher = secondPattern.matcher(uuid.substring(16, 32))
119+
120+
val r = SecureRandom()
121+
val vi_hi = firstMatcher.replaceAll(r.nextInt(7).toString())
122+
val vi_lo = secondMatcher.replaceAll(r.nextInt(3).toString())
123+
124+
val aidBuilder = StringBuilder(33)
125+
aidBuilder.append(vi_hi)
126+
aidBuilder.append("-")
127+
aidBuilder.append(vi_lo)
128+
129+
return aidBuilder.toString()
130+
}
131+
}
132+
}

0 commit comments

Comments
 (0)