diff --git a/android-core/build.gradle b/android-core/build.gradle index e92819e43..92ed9d593 100644 --- a/android-core/build.gradle +++ b/android-core/build.gradle @@ -112,7 +112,8 @@ task coreSdkJavadocs(type: Javadoc) { exclude { String filePath = it.toString() filePath.contains('/com/mparticle/internal/') || - filePath.contains('/com/mparticle/kits/') + filePath.contains('/com/mparticle/kits/') || + filePath.contains('/com/mparticle/modernization/') } } } @@ -135,6 +136,8 @@ dependencies { api 'androidx.annotation:annotation:[1.0.0,)' compileOnly 'androidx.core:core:[1.3.2, )' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4' + api 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0' lintPublish project( path: ':tooling:custom-lint-rules', configuration: 'lintBuild') diff --git a/android-core/src/main/java/com/mparticle/modernization/BatchManager.kt b/android-core/src/main/java/com/mparticle/modernization/BatchManager.kt new file mode 100644 index 000000000..660a46e8b --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/BatchManager.kt @@ -0,0 +1,13 @@ +package com.mparticle.modernization + +class BatchManager(private val api : MpApiClientImpl) { + + suspend fun createBatch() : MpBatch? = MpBatch("", Math.random().toLong()) + + suspend fun uploadBatch(batch : MpBatch) { + api.uploadBatch(batch) + } + +} + +class MpBatch(data : String, batchId : Long){} \ No newline at end of file diff --git a/android-core/src/main/java/com/mparticle/modernization/MParticleCallback.kt b/android-core/src/main/java/com/mparticle/modernization/MParticleCallback.kt new file mode 100644 index 000000000..b4ba7d71d --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/MParticleCallback.kt @@ -0,0 +1,16 @@ +package com.mparticle.modernization + +internal abstract class MParticleCallback { + var isSuccessFul: Boolean = false + var isCompleted: Boolean = false + + fun onSuccess(result: S) { + isSuccessFul = true + isCompleted = true + } + + fun onError(error: E) { + isSuccessFul = false + isCompleted = true + } +} diff --git a/android-core/src/main/java/com/mparticle/modernization/MpApiClientImpl.kt b/android-core/src/main/java/com/mparticle/modernization/MpApiClientImpl.kt new file mode 100644 index 000000000..d54041ac6 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/MpApiClientImpl.kt @@ -0,0 +1,6 @@ +package com.mparticle.modernization + +class MpApiClientImpl { + + suspend fun uploadBatch(data : MpBatch) {} +} \ No newline at end of file diff --git a/android-core/src/main/java/com/mparticle/modernization/Utils.kt b/android-core/src/main/java/com/mparticle/modernization/Utils.kt new file mode 100644 index 000000000..32e0df656 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/Utils.kt @@ -0,0 +1,9 @@ +package com.mparticle.modernization + +import com.mparticle.modernization.core.MParticleMediator +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +internal fun MParticleMediator.launch(block: suspend CoroutineScope.() -> Unit) { + this.coroutineScope.launch(this.coroutineDispatcher) { block } +} diff --git a/android-core/src/main/java/com/mparticle/modernization/WalkthroughTest.kt b/android-core/src/main/java/com/mparticle/modernization/WalkthroughTest.kt new file mode 100644 index 000000000..2b8cc344f --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/WalkthroughTest.kt @@ -0,0 +1,45 @@ +package com.mparticle.modernization + +import android.content.Context +import com.mparticle.MPEvent +import com.mparticle.MParticleOptions +import com.mparticle.commerce.CommerceEvent +import com.mparticle.commerce.Product +import com.mparticle.modernization.core.MParticle +import com.mparticle.modernization.eventlogging.MParticleEventLogging + + +class WalkthroughTest(private val context: Context) { + + private var eventLogging: MParticleEventLogging? = null + + //Only setup + fun initialize() { + val options = MParticleOptions.builder(context).credentials("key", "secret").build() + MParticle.start(options) + eventLogging = MParticle.getInstance().EventLogging() + } + + init { + initialize() + } + + //=================== + + fun runTest() { + logCommerceEvent() + logNormalEvent() + } + + fun logCommerceEvent() { + val product = Product.Builder("testName", "testSku", 100.0).build() + val commerceEvent = CommerceEvent.Builder(Product.CHECKOUT, product).build() + eventLogging?.logEvent(commerceEvent) + } + fun logNormalEvent() { + val customAttributes = + mutableMapOf(Pair("key1", "value1"), Pair("key2", 4), Pair("key3", null)) + val event = MPEvent.Builder("myEvent").customAttributes(customAttributes).build() + eventLogging?.logEvent(event) + } +} \ No newline at end of file diff --git a/android-core/src/main/java/com/mparticle/modernization/core/MParticle.kt b/android-core/src/main/java/com/mparticle/modernization/core/MParticle.kt new file mode 100644 index 000000000..b8394dc46 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/core/MParticle.kt @@ -0,0 +1,31 @@ +package com.mparticle.modernization.core + +import com.mparticle.MParticleOptions +import com.mparticle.modernization.data.MParticleDataRepository +import com.mparticle.modernization.eventlogging.MParticleEventLogging +import com.mparticle.modernization.identity.MParticleIdentity +import com.mparticle.modernization.kit.MParticleKitManager +import com.mparticle.modernization.datahandler.MParticleDataHandler + +internal class MParticle private constructor(private val options: MParticleOptions) { + private var mediator: MParticleMediator = MParticleMediator(MParticleDataRepository()) + + init { + mediator.configure(options) + } + + companion object { + private var _instance: MParticle? = null + + @Throws(Exception::class) + fun getInstance(): MParticle = _instance ?: throw Exception("MParticle must be started before getting the instance") + + fun start(options: MParticleOptions) { + _instance = MParticle(options) + } + } + + fun KitManager(): MParticleKitManager? = mediator.kitManager as MParticleKitManager? + fun Identity(): MParticleIdentity? = mediator.identity as MParticleIdentity? + fun EventLogging(): MParticleEventLogging? = mediator.eventLogging +} diff --git a/android-core/src/main/java/com/mparticle/modernization/core/MParticleComponent.kt b/android-core/src/main/java/com/mparticle/modernization/core/MParticleComponent.kt new file mode 100644 index 000000000..90249455d --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/core/MParticleComponent.kt @@ -0,0 +1,3 @@ +package com.mparticle.modernization.core + +internal interface MParticleComponent diff --git a/android-core/src/main/java/com/mparticle/modernization/core/MParticleMediator.kt b/android-core/src/main/java/com/mparticle/modernization/core/MParticleMediator.kt new file mode 100644 index 000000000..d9b83aae6 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/core/MParticleMediator.kt @@ -0,0 +1,73 @@ +package com.mparticle.modernization.core + +import com.mparticle.MParticleOptions +import com.mparticle.modernization.BatchManager +import com.mparticle.modernization.MpApiClientImpl +import com.mparticle.modernization.data.MParticleDataRepository +import com.mparticle.modernization.eventlogging.MParticleEventLogging +import com.mparticle.modernization.eventlogging.example.MParticleEventLoggingImpl +import com.mparticle.modernization.identity.InternalIdentity +import com.mparticle.modernization.identity.example.MParticleIdentityImpl +import com.mparticle.modernization.kit.KitManagerInternal +import com.mparticle.modernization.kit.MParticleKit +import com.mparticle.modernization.kit.MParticleKitManagerImpl +import com.mparticle.modernization.kit.example.MpKit +import com.mparticle.modernization.datahandler.MParticleDataStrategyManagerImpl +import com.mparticle.modernization.datahandler.MParticleDataHandlerStrategy +import com.mparticle.modernization.datahandler.example.MParticleCommerceHandler +import kotlinx.coroutines.CloseableCoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.asCoroutineDispatcher +import java.util.concurrent.Executors + +internal class MParticleMediator(private val dataRepository: MParticleDataRepository) { + internal var eventLogging: MParticleEventLogging? = null + internal var identity: InternalIdentity? = null + internal var kitManager: KitManagerInternal? = null + internal var batchManager : BatchManager = BatchManager(MpApiClientImpl()) + + private var mParticleUploadingStrategies: List> = listOf( + MParticleCommerceHandler(dataRepository, batchManager) + ) + + internal lateinit var coroutineScope: CoroutineScope + internal lateinit var coroutineDispatcher: CloseableCoroutineDispatcher + + /** + * Mediator register kits and components, acting as a "common layer" for the components internally, + * and also providing a single instance of the available and visible components to the MParticle + * facade. This will help also controlling which this we want to make accesible and which one we doesn't. + */ + fun configure(options: MParticleOptions) { + /** + * Creation of auto-cancellable thread-pool using coroutines. + * Using a utility, and due to the fact that the relationship between mediator-mPaticle instance + * is 1:1, we would be able to launch async operation managed by the thread pool of each mparticle + * instance + */ + coroutineScope = CoroutineScope(SupervisorJob()) + coroutineDispatcher = Executors.newCachedThreadPool().asCoroutineDispatcher() + + var kits: MutableList = registerKits(options) + /** + * Mediator has a reference to each component. The components mostly are instanciated with a + * dependency to the mediator, meaning that, if component A (running action 1) needs an action 3 from component B + * to be executed to complete action 1; component A can use the mediator to access component B + */ + registerComponent(MParticleKitManagerImpl(kits)) + registerComponent(MParticleIdentityImpl(this)) + registerComponent(MParticleEventLoggingImpl(this)) + } + + private fun registerKits(options: MParticleOptions): MutableList = + mutableListOf(MpKit(this, MParticleDataStrategyManagerImpl(mParticleUploadingStrategies))) + + private fun registerComponent(component: MParticleComponent) { + when (component) { + is InternalIdentity -> identity = component + is KitManagerInternal -> kitManager = component + is MParticleEventLogging -> eventLogging = component + } + } +} diff --git a/android-core/src/main/java/com/mparticle/modernization/data/MParticleDataRepository.kt b/android-core/src/main/java/com/mparticle/modernization/data/MParticleDataRepository.kt new file mode 100644 index 000000000..c2f9b8f64 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/data/MParticleDataRepository.kt @@ -0,0 +1,21 @@ +package com.mparticle.modernization.data + +import com.mparticle.internal.messages.BaseMPMessage +import com.mparticle.modernization.MpBatch + +/** + * This is based on the repository pattern to manage data sources (apiClients, daos, + * sharedPreferences, cache, memory, etc). + * Ideally we would inject our data sources here, and the repository would be incharge of preprocessing + * the data interacting with the data source, and post-process the data coming from data sources. + */ +internal class MParticleDataRepository { + + suspend fun insertCommerceDTO(data: BaseMPMessage) { + //TODO parses the event and saves it into the db + } + + suspend fun getEventsByType() : List? = emptyList() + + suspend fun getBatch() : MpBatch? = null +} diff --git a/android-core/src/main/java/com/mparticle/modernization/datahandler/DataHandlerType.kt b/android-core/src/main/java/com/mparticle/modernization/datahandler/DataHandlerType.kt new file mode 100644 index 000000000..13e6d9d75 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/datahandler/DataHandlerType.kt @@ -0,0 +1,16 @@ +package com.mparticle.modernization.datahandler + +enum class DataHandlerType { + MP_EVENT, COMMERCE_EVENT, BREADCRUMB; + + companion object { + fun getType(clazz: Class<*>): DataHandlerType? { + return when (clazz.javaClass.simpleName) { + "com.mparticle.MpEvent" -> MP_EVENT + "com.mparticle.commerce.CommerceEvent" -> COMMERCE_EVENT + else -> null + } + } + } + +} \ No newline at end of file diff --git a/android-core/src/main/java/com/mparticle/modernization/datahandler/MParticleDataHandler.kt b/android-core/src/main/java/com/mparticle/modernization/datahandler/MParticleDataHandler.kt new file mode 100644 index 000000000..93223f118 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/datahandler/MParticleDataHandler.kt @@ -0,0 +1,20 @@ +package com.mparticle.modernization.datahandler + +import com.mparticle.modernization.core.MParticleComponent +import org.jetbrains.annotations.NotNull + +internal interface MParticleDataHandler : MParticleComponent { + /** + *Save set of data using provided strategies. Decision made base on [type] + * + * @param data any type of data. Each strategy is responsible of converting and handling the data + * @param immediateUpload true or false depending if we want to force immediate data upload. By + * default this is false + */ + suspend fun saveData( + @NotNull data: Any, + @NotNull immediateUpload: Boolean = false + ) + + suspend fun configure() {} +} diff --git a/android-core/src/main/java/com/mparticle/modernization/datahandler/MParticleDataHandlerStrategy.kt b/android-core/src/main/java/com/mparticle/modernization/datahandler/MParticleDataHandlerStrategy.kt new file mode 100644 index 000000000..02229cb93 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/datahandler/MParticleDataHandlerStrategy.kt @@ -0,0 +1,44 @@ +package com.mparticle.modernization.datahandler + + +import com.mparticle.modernization.BatchManager +import org.jetbrains.annotations.NotNull + +/** + * Data uploading strategies for different data types + */ +internal interface MParticleDataHandlerStrategy { + /** Upload set of data + * + * @param data any type of data to upload + * @param immediateUpload true or false depending if we want to force immediate data upload. By + * default this is false + * @param uploadingConfiguration to handle auto-data uploads or other custom implementation based + * on a configuration. + */ + suspend fun saveData( + @NotNull data: Any, + @NotNull immediateUpload: Boolean + ) + + suspend fun retrieveData(): List + + fun I.toDto(): O? + + fun O.toModel(): I? + + /** + * @return strategy id + */ + fun type(): DataHandlerType + +} + +abstract class BaseMParticleDataHandlerStrategy(protected val batchManager: BatchManager) : + MParticleDataHandlerStrategy { + protected open suspend fun createAndUploadBatch() { + with(batchManager) { + createBatch()?.let { this.uploadBatch(it) } + } + } +} diff --git a/android-core/src/main/java/com/mparticle/modernization/datahandler/MParticleDataStrategyManagerImpl.kt b/android-core/src/main/java/com/mparticle/modernization/datahandler/MParticleDataStrategyManagerImpl.kt new file mode 100644 index 000000000..f2eec07ed --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/datahandler/MParticleDataStrategyManagerImpl.kt @@ -0,0 +1,18 @@ +package com.mparticle.modernization.datahandler + +internal class MParticleDataStrategyManagerImpl( + private val strategies: List>, +) : MParticleDataHandler { + + /** + * Based on the data type we will choose the corresponding strategy provided at config type, and + * execute an action on it. + */ + override suspend fun saveData(data: Any, immediateUpload: Boolean) { + data.javaClass.getStrategy()?.saveData(data, immediateUpload) + } + + private fun Class<*>.getStrategy(): MParticleDataHandlerStrategy<*, *>? = + strategies.firstOrNull { it.type() == DataHandlerType.getType(this) } + +} diff --git a/android-core/src/main/java/com/mparticle/modernization/datahandler/example/MParticleCommerceHandler.kt b/android-core/src/main/java/com/mparticle/modernization/datahandler/example/MParticleCommerceHandler.kt new file mode 100644 index 000000000..c85279938 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/datahandler/example/MParticleCommerceHandler.kt @@ -0,0 +1,62 @@ +package com.mparticle.modernization.datahandler.example + +import com.mparticle.commerce.CommerceEvent +import com.mparticle.commerce.Product +import com.mparticle.internal.messages.BaseMPMessage +import com.mparticle.modernization.BatchManager +import com.mparticle.modernization.data.MParticleDataRepository +import com.mparticle.modernization.datahandler.BaseMParticleDataHandlerStrategy +import com.mparticle.modernization.datahandler.DataHandlerType + +/** + * As an example, each data specific type would have a handler (using the strategy pattern), + * and inherit from a baseHandler with cross type capabilities (batch operations, etc) + * + * As an example I wrote a couple of operations to save/retrieve data and convert data from and to + * businessModel/DTO. + * Each type will create a concrete strategy implementing the defined operations and specifying its type + */ +internal class MParticleCommerceHandler( + private val dataRepository: MParticleDataRepository, + batchManager: BatchManager +) : BaseMParticleDataHandlerStrategy(batchManager) { + + override suspend fun saveData( + data: Any, + immediateUpload: Boolean + ) { + (data as CommerceEvent).toDto()?.let { + with(dataRepository) { insertCommerceDTO(it) } + } + if (immediateUpload) { + createAndUploadBatch() + } + } + + override suspend fun retrieveData(): List { + return with(dataRepository) { getEventsByType() ?: emptyList() } + } + + override fun type(): DataHandlerType = DataHandlerType.COMMERCE_EVENT + + override fun BaseMPMessage.toModel(): CommerceEvent? { + //Grab a String and convert it into a business model object + var strProduct = Product.fromString("") + var productAction = Product.ADD_TO_CART + return CommerceEvent.Builder(productAction, strProduct).build() + } + + override fun CommerceEvent.toDto(): BaseMPMessage? { + // val message = BaseMPMessage.Builder(Constants.MessageType.BREADCRUMB). +// .timestamp(mAppStateManager.getSession().mLastEventTime) +// .build(mAppStateManager.getSession(), mLocation, mConfigManager.getMpid()) +// +// message.put(MessageKey.EVENT_START_TIME, mAppStateManager.getSession().mLastEventTime) +// message.put( +// MessageKey.BREADCRUMB_SESSION_COUNTER, +// mConfigManager.getUserStorage().getCurrentSessionCounter() +// ) +// message.put(MessageKey.BREADCRUMB_LABEL, breadcrumb) + return null + } +} diff --git a/android-core/src/main/java/com/mparticle/modernization/eventlogging/MParticleEventLogging.kt b/android-core/src/main/java/com/mparticle/modernization/eventlogging/MParticleEventLogging.kt new file mode 100644 index 000000000..5f68ced75 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/eventlogging/MParticleEventLogging.kt @@ -0,0 +1,26 @@ +package com.mparticle.modernization.eventlogging + +import com.mparticle.BaseEvent +import com.mparticle.modernization.core.MParticleComponent +import org.jetbrains.annotations.NotNull +import org.jetbrains.annotations.Nullable +import java.math.BigDecimal + +internal interface MParticleEventLogging : MParticleComponent { + // All common, commerce, screen, pushRegistration, ltvIncrease, breadcrumb, exception, notification, notificationOpened and NetworkPerformance events should be logged with the same function + /** + * Log an event - TODO review EventBuilder to be able to build all type of events + * @param event to log + */ + fun logEvent(@NotNull event: BaseEvent) + + + /** + * Log an error + * @param message + * @param params optional by default null + * @param exception + */ + fun logError(@NotNull message: String, @Nullable params: Map? = null, @Nullable exception : Exception?) + +} diff --git a/android-core/src/main/java/com/mparticle/modernization/eventlogging/example/MParticleEventLoggingImpl.kt b/android-core/src/main/java/com/mparticle/modernization/eventlogging/example/MParticleEventLoggingImpl.kt new file mode 100644 index 000000000..a5b28c998 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/eventlogging/example/MParticleEventLoggingImpl.kt @@ -0,0 +1,28 @@ +package com.mparticle.modernization.eventlogging.example + +import com.mparticle.BaseEvent +import com.mparticle.modernization.core.MParticleMediator +import com.mparticle.modernization.eventlogging.MParticleEventLogging +import com.mparticle.modernization.kit.MParticleKit + +internal class MParticleEventLoggingImpl(private val mediator: MParticleMediator) : + MParticleEventLogging { + + /** + * The component is incharge of event logging itself, by delegation its responsability to the + * different kits (by using the kitManager component from the mediator). + * Because each kit migth have a different configuration to follow in order to "log an event", + * specifically us - we filter, create and handle projectsion, apply rules etc, this class should + * be only incharge of cross kit pre/post processing. + */ + override fun logEvent(event: BaseEvent) { + //pre-process stuff + mediator.kitManager?.logEvent(event) + //post-process stuff + } + + override fun logError(message: String, params: Map?, exception: Exception?) { + TODO("Not yet implemented") + } + +} diff --git a/android-core/src/main/java/com/mparticle/modernization/identity/IdentityCallback.kt b/android-core/src/main/java/com/mparticle/modernization/identity/IdentityCallback.kt new file mode 100644 index 000000000..637a7e0b0 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/identity/IdentityCallback.kt @@ -0,0 +1,10 @@ +package com.mparticle.modernization.identity + +import com.mparticle.identity.IdentityApiResult +import com.mparticle.modernization.MParticleCallback + +/** + * Example of the identity callback extending the standarized behavior of the MParticleCallback + * that defines success and error + */ +internal open class IdentityCallback : MParticleCallback() diff --git a/android-core/src/main/java/com/mparticle/modernization/identity/MParticleIdentity.kt b/android-core/src/main/java/com/mparticle/modernization/identity/MParticleIdentity.kt new file mode 100644 index 000000000..8f2c4179c --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/identity/MParticleIdentity.kt @@ -0,0 +1,93 @@ +package com.mparticle.modernization.identity + +import com.mparticle.identity.IdentityApiRequest +import com.mparticle.identity.IdentityApiResult +import com.mparticle.identity.MParticleUser +import com.mparticle.modernization.MParticleCallback +import com.mparticle.modernization.core.MParticleComponent +import org.jetbrains.annotations.NotNull +import org.jetbrains.annotations.Nullable + +internal interface MParticleIdentity : MParticleComponent { + + /** + * Login + * @param callback + */ + fun login(@NotNull callback: IdentityCallback) + + /** + * Logout + * @param callback + */ + fun logout(@NotNull callback: IdentityCallback) + + /** + * Returns the user by id or the current user if [mpId] is null + * @param mpId if null returns the current user, if not the user by id + * @param callback + */ + fun getUser(@Nullable mpId: Long?, @NotNull callback: IdentityCallback) + + /** + * Return all users + * @param callback + */ + fun getUsers(@NotNull callback: MParticleCallback, Unit>) + + /** + * Returns the user by id or the current user if [mpId] is null + * @param mpId if null returns the current user, if not the user by id + * @return identityApiResult + */ + suspend fun getUser(@Nullable mpId: Long?): IdentityApiResult + + /** + * Return all users + * @return mParicleUsers in a list + */ + suspend fun getUsers(): List + + /** + * Login + * @return identityApiResult + */ + suspend fun login(): IdentityApiResult + + /** + * Logout + * @return identityApiResult + */ + suspend fun logout(): IdentityApiResult +} + +internal interface InternalIdentity : MParticleIdentity { + /** + * Identify api request call + * @param request + * @return identityApiResult + */ + suspend fun identify(@NotNull request: IdentityApiRequest): IdentityApiResult + + /** + * Modify api request call + * @param request + * @return identityApiResult + */ + suspend fun modify(@NotNull request: IdentityApiRequest): IdentityApiResult + + /** + * Logout api request call + * @param request + * @return identityApiResult + */ + suspend fun logout(@NotNull request: IdentityApiRequest): IdentityApiResult + + /** + * Login api request call + * @param request + * @return identityApiResult + */ + suspend fun login(@NotNull request: IdentityApiRequest): IdentityApiResult +} + diff --git a/android-core/src/main/java/com/mparticle/modernization/identity/example/MParticleIdentityImpl.kt b/android-core/src/main/java/com/mparticle/modernization/identity/example/MParticleIdentityImpl.kt new file mode 100644 index 000000000..e63ccc711 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/identity/example/MParticleIdentityImpl.kt @@ -0,0 +1,64 @@ +package com.mparticle.modernization.identity.example + +import com.mparticle.identity.IdentityApiRequest +import com.mparticle.identity.IdentityApiResult +import com.mparticle.identity.MParticleUser +import com.mparticle.modernization.MParticleCallback +import com.mparticle.modernization.core.MParticleMediator +import com.mparticle.modernization.identity.IdentityCallback +import com.mparticle.modernization.identity.InternalIdentity + +/** + * I would recomend using two implementations coroutine/callbacks, being the coroutine one the internal. + * The one with callback could use the coroutine implementation. + */ +internal class MParticleIdentityImpl(private val mediator: MParticleMediator) : + InternalIdentity { + override suspend fun identify(request: IdentityApiRequest): IdentityApiResult { + TODO("Not yet implemented") + } + + override suspend fun modify(request: IdentityApiRequest): IdentityApiResult { + TODO("Not yet implemented") + } + + override suspend fun logout(request: IdentityApiRequest): IdentityApiResult { + TODO("Not yet implemented") + } + + override fun logout(callback: IdentityCallback) { + TODO("Not yet implemented") + } + + override suspend fun logout(): IdentityApiResult { + TODO("Not yet implemented") + } + + override suspend fun login(request: IdentityApiRequest): IdentityApiResult { + TODO("Not yet implemented") + } + + override fun login(callback: IdentityCallback) { + TODO("Not yet implemented") + } + + override suspend fun login(): IdentityApiResult { + TODO("Not yet implemented") + } + + override fun getUser(mpId: Long?, callback: IdentityCallback) { + TODO("Not yet implemented") + } + + override suspend fun getUser(mpId: Long?): IdentityApiResult { + TODO("Not yet implemented") + } + + override fun getUsers(callback: MParticleCallback, Unit>) { + TODO("Not yet implemented") + } + + override suspend fun getUsers(): List { + TODO("Not yet implemented") + } +} diff --git a/android-core/src/main/java/com/mparticle/modernization/kit/KitConfiguration.kt b/android-core/src/main/java/com/mparticle/modernization/kit/KitConfiguration.kt new file mode 100644 index 000000000..58d235300 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/kit/KitConfiguration.kt @@ -0,0 +1,8 @@ +package com.mparticle.modernization.kit + +/** + * Abstraction that should have the configuration for each kit (might be passed when creating the + * instance of the kit or onKitCreate if resolved after the instance is created) + */ +class KitConfiguration { +} \ No newline at end of file diff --git a/android-core/src/main/java/com/mparticle/modernization/kit/KitListeners.kt b/android-core/src/main/java/com/mparticle/modernization/kit/KitListeners.kt new file mode 100644 index 000000000..8b226dd26 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/kit/KitListeners.kt @@ -0,0 +1,25 @@ +package com.mparticle.modernization.kit + +import android.content.Context +import com.mparticle.MPEvent +import com.mparticle.commerce.CommerceEvent + +/** + * Listeners for the kits + */ +interface CommerceListener { + fun commerceEventLogged(event : CommerceEvent) +// fun ltvIncreaseEventLogged(event : LtvIncreaseEvent) +} +interface EventListener{ + fun eventLogged(event : MPEvent) + fun errorLogged(message: String, params: Map?, exception: Exception?) + //breadcrumbLogged, screen logged, etc. +} +interface MPLifecycle { + fun onKitCreate(settings : Map, context : Context) {} +} +interface IdentityListener {} +interface UserProfileListener {} +interface PushListener {} +interface ActivityListener{} diff --git a/android-core/src/main/java/com/mparticle/modernization/kit/MParticleKit.kt b/android-core/src/main/java/com/mparticle/modernization/kit/MParticleKit.kt new file mode 100644 index 000000000..ec9b43188 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/kit/MParticleKit.kt @@ -0,0 +1,8 @@ +package com.mparticle.modernization.kit + +internal abstract class MParticleKit : MPLifecycle { + abstract fun getConfiguration() : KitConfiguration +} +internal abstract class MParticleKitInternal : MParticleKit() { +} + diff --git a/android-core/src/main/java/com/mparticle/modernization/kit/MParticleKitManager.kt b/android-core/src/main/java/com/mparticle/modernization/kit/MParticleKitManager.kt new file mode 100644 index 000000000..0d5945ee0 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/kit/MParticleKitManager.kt @@ -0,0 +1,10 @@ +package com.mparticle.modernization.kit + +import com.mparticle.modernization.core.MParticleComponent +import com.mparticle.modernization.eventlogging.MParticleEventLogging + +internal abstract class MParticleKitManager : MParticleComponent + +internal abstract class KitManagerInternal : MParticleKitManager(), + MParticleEventLogging { +} diff --git a/android-core/src/main/java/com/mparticle/modernization/kit/MParticleKitManagerImpl.kt b/android-core/src/main/java/com/mparticle/modernization/kit/MParticleKitManagerImpl.kt new file mode 100644 index 000000000..70eb2d9cc --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/kit/MParticleKitManagerImpl.kt @@ -0,0 +1,39 @@ +package com.mparticle.modernization.kit + +import com.mparticle.BaseEvent +import com.mparticle.MPEvent +import com.mparticle.commerce.CommerceEvent +import com.mparticle.modernization.kit.example.MpKit + +internal class MParticleKitManagerImpl( + private val kits: MutableList +) : KitManagerInternal() { + + private fun doInKits(action: (kit: MParticleKit) -> Unit) { + kits.forEach { action.invoke(it) } + } + + private fun CommerceEvent.processEvent() { + doInKits{ if (it is CommerceListener) { it.commerceEventLogged(this) } } + } + private fun MPEvent.processEvent() { + doInKits{ if (it is EventListener) { it.eventLogged(this) } } + } + + + override fun logEvent(event: BaseEvent) { + when (event) { + is CommerceEvent -> event.processEvent() + is MPEvent -> event.processEvent() + else -> {} + } + } + + override fun logError( + message: String, + params: Map?, + exception: Exception? + ) { + doInKits { if (it is EventListener) { it.errorLogged(message, params, exception) } } + } +} diff --git a/android-core/src/main/java/com/mparticle/modernization/kit/example/MpKit.kt b/android-core/src/main/java/com/mparticle/modernization/kit/example/MpKit.kt new file mode 100644 index 000000000..ce5fdbb19 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/kit/example/MpKit.kt @@ -0,0 +1,41 @@ +package com.mparticle.modernization.kit.example + +import com.mparticle.MPEvent +import com.mparticle.commerce.CommerceEvent +import com.mparticle.modernization.core.MParticleMediator +import com.mparticle.modernization.kit.CommerceListener +import com.mparticle.modernization.kit.EventListener +import com.mparticle.modernization.kit.MParticleKitInternal +import com.mparticle.modernization.launch +import com.mparticle.modernization.datahandler.MParticleDataHandler +import com.mparticle.modernization.kit.KitConfiguration + +/** + * MParticle business related logic. The component should delegate to the kitManager, and the kit manager + * delegate to each kit (being MParticle a specific use case). + * While a third-party kit wrapper like OneTrust will operate against their SDK, this one will trigger + * their internal managers and structure to manage data pre-processing,storing/retrieval,mapping,parsing,upload. + */ +internal class MpKit( + private val mediator: MParticleMediator, + private val dataHandler: MParticleDataHandler +) : MParticleKitInternal(), + CommerceListener, EventListener { + + override fun commerceEventLogged(event: CommerceEvent) { + //TODO Filter, handle projections and save event + mediator.launch { dataHandler.saveData(event, true) } + } + + override fun eventLogged(event: MPEvent) { + mediator.launch { dataHandler.saveData(event) } + } + + override fun errorLogged(message: String, params: Map?, exception: Exception?) { + TODO("Not yet implemented") + } + + override fun getConfiguration(): KitConfiguration { + TODO("Not yet implemented") + } +} diff --git a/android-core/src/main/java/com/mparticle/modernization/kit/example/XKit.kt b/android-core/src/main/java/com/mparticle/modernization/kit/example/XKit.kt new file mode 100644 index 000000000..10bd64b66 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/kit/example/XKit.kt @@ -0,0 +1,23 @@ +package com.mparticle.modernization.kit.example + +import android.util.Log +import com.mparticle.MPEvent +import com.mparticle.modernization.kit.EventListener +import com.mparticle.modernization.kit.KitConfiguration +import com.mparticle.modernization.kit.MParticleKitInternal + +internal class XKit() : MParticleKitInternal(), EventListener { + + override fun getConfiguration(): KitConfiguration { + TODO("Not yet implemented") + } + + override fun eventLogged(event: MPEvent) { + Log.d("MP_EVENT", event.toString()) + } + + override fun errorLogged(message: String, params: Map?, exception: Exception?) { + TODO("Not yet implemented") + } + +} diff --git a/android-core/src/main/java/com/mparticle/modernization/uploading/example/MParticleUploaderTypes.kt b/android-core/src/main/java/com/mparticle/modernization/uploading/example/MParticleUploaderTypes.kt new file mode 100644 index 000000000..2fd8e3e68 --- /dev/null +++ b/android-core/src/main/java/com/mparticle/modernization/uploading/example/MParticleUploaderTypes.kt @@ -0,0 +1,5 @@ +package com.mparticle.modernization.uploading.example + +internal enum class MParticleUploaderTypes(val type: Int) { + EVENT(1), BREADCRUMB(2), DEFAULT(-1); +}