Giter Site home page Giter Site logo

codestarx / controlflowdemo Goto Github PK

View Code? Open in Web Editor NEW
2.0 1.0 0.0 142 KB

Android Application to use control-flow library

Home Page: https://github.com/CodeStarX/ControlFlow

Kotlin 100.00%
amadeus-api clean-architecture clean-code control-flow dagger-hilt jetpack-compose kotlin-coroutines kotlin-flow mvi-android okhttp-interceptor

controlflowdemo's Introduction

Control Flow Demo

In this project, I have used clean architecture with a MVI pattern.

Libraries included in this project

control-flow jetpack compose kotlin coroutine coroutine flow retrofit okhttp view-model hilt timber

Modules

:core:data It includes classes that are used to communicate with the server.

:core:domain It includes use case classes between data module and presentation module.

:core:framework It includes the classes used in the presentation module.

:presentation It includes the ui to interact with the user and also contains the viewModel class.

Project Structure

In this project, the Amadeus website services facilitate obtaining a list of hotels, involving a series of three essential tasks:

Note: Please utilize your unique API_KEY and API_SECRET, as mine are concealed. Once obtained, insert them into the RemoteConfig Class

API_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

API_SECRET = "xxxxxxxxxxxxxxxx"

  1. Invoking the authorization web service to procure the crucial access_token
  2. Safeguarding the obtained access_token by storing it through the SharedPreferences functionality.
  3. Retrieving the catalog of hotels by utilizing the hotelsListByCity web service.

To orchestrate these asynchronous tasks effectively, the Control-Flow library assumes the responsibility of task management. In the provided code samples:

val engine = ControlFlow(object: WorkFlowTracker {

            override fun started(controlFlow: ControlFlow) {
                Timber.tag("TAG").e("flow Started")
                setState(state = ViewState.Loading)
            }

            override fun taskStatus(controlFlow: ControlFlow, taskFlow: TaskFlow, state: State) {
                when(state) {
                    State.Started -> {
                        when(taskFlow.isRollback) {
                            true -> {
                                Timber.tag("TAG").e("rollback task Started, name is: ${taskFlow.taskName}")
                            }
                            else -> {
                                Timber.tag("TAG").e("task Started, name is: ${taskFlow.taskName}")

                            }
                        }
                    }
                    State.InProgress -> {
                        when(taskFlow.isRollback) {
                            true -> {
                                Timber.tag("TAG").e("rollback task InProgress, name is: ${taskFlow.taskName}")
                            }
                            else -> {
                                Timber.tag("TAG").e("task InProgress, name is: ${taskFlow.taskName}")

                            }
                        }
                    }
                }
            }

            override fun completed(controlFlow: ControlFlow) {
                Timber.tag("TAG").e("flow completed" )
            }
        }).apply {
            startWith(first = AuthorizationTask(useCase = useCase))
            then(next = SaveAccessTokenTask(cashManager = sharedPrefCashManager))
            then(next = GetHotelsListTask(useCase = getHotelsUseCase))
        }

Note: To activate the Retry mechanism, I've configured the properties of the AuthorizationTask class. In case of a TimeoutException error, the task will be retried thrice, with a one-second interval between each attempt.

class AuthorizationTask(
    private val useCase: AuthorizationUseCase
) : Dispatcher(), TaskProcessor {
    override val info: TaskInfo
        get() = TaskInfo().apply {
            index = 0
            name = AuthorizationTask::class.java.name
            retry = RetryStrategy().apply {
                count = 3
                causes = setOf(TimeoutException::class)
                delay = 1000L
            }
            runIn = Dispatchers.IO
        }

    override suspend fun doProcess(param: Any?): Flow<TaskStatus> {
        ...
    }
}

Note: the output of the first task undergoes conversion via the transformer method before being passed to the second task.

class AuthorizationTask(
    private val useCase: AuthorizationUseCase
) : Dispatcher(), TaskProcessor {
    override val info: TaskInfo
        get() = ...

    override suspend fun doProcess(param: Any?): Flow<TaskStatus> {
        return launchFlow(action =  { useCase(params = BaseUseCase.None()) },
             transformer = { TransformData(data = it.body().toJson().fromJson<ResAuthorization>()?.accessToken) },
             actionCondition = {
                    when(it.isSuccessful) {
                        true -> {
                            ConditionData(status = Boolean.successMode())
                        }
                        else -> {
                            val jObjError: JSONObject? =
                                it.errorBody()?.string()
                                    ?.let { it1 -> JSONObject(it1) }
                            var errorDescription = ""
                            var errorCode: Int = -1
                            if(jObjError?.has("error_description") == true && jObjError.has("code")) {
                                errorDescription = jObjError.getString("error_description")
                                errorCode = jObjError.getInt("code")
                            }
                            ConditionData(status = Boolean.failureMode(), throwable = HttpException(code = errorCode, message = errorDescription))
                        }
                    }
        })
    }
}

Note: If an error occurs while calling the hotelsListByCity web service, the doRollbackProcess method run automatically. It effectively manages the removal of the previously acquired access-token, playing a crucial role in evaluating the rollback function.

class SaveAccessTokenTask(
    private val cashManager: SharedPrefCashManager
): Dispatcher(), RollbackTaskProcessor {
    override val info: TaskInfo
        get() = TaskInfo().apply {
            index = 1
            name = SaveAccessTokenTask::class.java.name
            runIn = Dispatchers.IO
        }
    override val rollbackInfo: RollbackInfo
        get() = RollbackInfo().apply {
            index = 1
            name = SaveAccessTokenTask::class.java.name
            runIn = Dispatchers.IO
        }

    override suspend fun doProcess(param: Any?): Flow<TaskStatus> {
        return launch { cashManager.putPreference(key = ACCESS_TOKEN, value = param) }
    }

    override suspend fun doRollbackProcess(): Flow<TaskStatus> {
        return launch { cashManager.putPreference(key = ACCESS_TOKEN, value = String.empty()) }
    }
}

To activate the rollback mechanism automatically after any task encounters an error, ensure to set the runAutomaticallyRollback flag to true within the start method. By default, the value of this flag is runAutomaticallyRollback= false

 // Create a ControlFlow instance
val controlFlow = ControlFlow(object : WorkFlowTracker {
// Implement work Flow callback methods
})

// Define your tasks
controlFlow.startWith(MyTask())
controlFlow.then(AnotherTask())
controlFlow.then(AnotherTask())

// Set up TaskStatusTracker if needed
controlFlow.useTaskStatusTracker(object : TaskStatusTracker {
// Implement callback methods
})

// Set up RollbackStatusTracker if needed
controlFlow.useRollbackStatusTracker(object : RollbackStatusTracker {
// Implement callback methods
})

// Start executing tasks
controlFlow.start(runAutomaticallyRollback= true)

Contributing

If you have a suggestion that would make this better, please fork the repo and create a pull request. Remember to show your support by giving the project a star. Thank you once more :)

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/YourFeatureName)
  3. Commit your Changes (git commit -m 'Add some YourFeatureName')
  4. Push to the Branch (git push origin feature/YourFeatureName)
  5. Open a Pull Request

You can contact me via email [email protected] I appreciate your interest.

Screenshots

| |

License

MIT License

Copyright (c) 2023 Related Code

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

controlflowdemo's People

Contributors

codestarx avatar

Stargazers

 avatar  avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.