From e05eb5ebbed6f04f0a43ec7e0e1cbf26781394c2 Mon Sep 17 00:00:00 2001 From: "Suresh, Kamlesh" Date: Thu, 11 Mar 2021 15:21:24 -0500 Subject: [PATCH] handler fix --- MVMCore/MVMCore.xcodeproj/project.pbxproj | 4 + .../ActionHandling/MVMCoreActionHandler.m | 4 +- .../ClientParameterHandler.swift | 108 ++++++++++++++++++ .../ClientParameterRegistry.swift | 98 +--------------- 4 files changed, 116 insertions(+), 98 deletions(-) create mode 100644 MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterHandler.swift diff --git a/MVMCore/MVMCore.xcodeproj/project.pbxproj b/MVMCore/MVMCore.xcodeproj/project.pbxproj index 449ae7c..a3ac7c6 100644 --- a/MVMCore/MVMCore.xcodeproj/project.pbxproj +++ b/MVMCore/MVMCore.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 016CF36925FA6DD400B82A1F /* ClientParameterHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016CF36825FA6DD400B82A1F /* ClientParameterHandler.swift */; }; 016FF6EE259A4E6300F5E4AA /* ClientParameterModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016FF6ED259A4E6300F5E4AA /* ClientParameterModelProtocol.swift */; }; 016FF6F2259A4FCC00F5E4AA /* ClientParameterModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016FF6F1259A4FCC00F5E4AA /* ClientParameterModel.swift */; }; 016FF6F6259B9AED00F5E4AA /* ClientParameterRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 016FF6F5259B9AED00F5E4AA /* ClientParameterRegistry.swift */; }; @@ -152,6 +153,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 016CF36825FA6DD400B82A1F /* ClientParameterHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientParameterHandler.swift; sourceTree = ""; }; 016FF6ED259A4E6300F5E4AA /* ClientParameterModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientParameterModelProtocol.swift; sourceTree = ""; }; 016FF6F1259A4FCC00F5E4AA /* ClientParameterModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientParameterModel.swift; sourceTree = ""; }; 016FF6F5259B9AED00F5E4AA /* ClientParameterRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientParameterRegistry.swift; sourceTree = ""; }; @@ -309,6 +311,7 @@ 016FF6ED259A4E6300F5E4AA /* ClientParameterModelProtocol.swift */, 016FF6F1259A4FCC00F5E4AA /* ClientParameterModel.swift */, 016FF6F5259B9AED00F5E4AA /* ClientParameterRegistry.swift */, + 016CF36825FA6DD400B82A1F /* ClientParameterHandler.swift */, 01934FE625A4FFC2003DCD67 /* ClientParameterActionProtocol.swift */, ); path = "Client Parameters"; @@ -857,6 +860,7 @@ AFBB96351FBA34310008D868 /* MVMCoreErrorConstants.m in Sources */, AF43A5881FBB67D6008E9347 /* MVMCoreActionUtility.m in Sources */, AFED77A61FCCA29400BAE689 /* MVMCoreViewControllerStoryBoardMappingObject.m in Sources */, + 016CF36925FA6DD400B82A1F /* ClientParameterHandler.swift in Sources */, AF43A57C1FBA5E6A008E9347 /* MVMCoreHardcodedStringsConstants.m in Sources */, 0AFF597A23FC6E60005C24E8 /* ActionShareModel.swift in Sources */, AFEEE81F1FCDF3CA00B5EDD0 /* MVMCoreLoggingHandler.m in Sources */, diff --git a/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.m b/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.m index 8b9a3aa..8072091 100644 --- a/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.m +++ b/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.m @@ -112,7 +112,9 @@ NSString * const KeyActionTypeOpen = @"openPage"; NSError *error = nil; [MVMCoreLoggingHandler logDebugMessageWithDelegate:@"Fetching client parameters"]; - [[[MVMCoreObject sharedInstance] clientParameterRegistry] getParametersWith:clientParametersMap + + ClientParameterHandler* clientParameterHandler = [[ClientParameterHandler alloc] init]; + [clientParameterHandler getParametersWith:clientParametersMap requestParameters:requestParameters error:&error completionHandler:^(NSDictionary * _Nullable clientParameters) { diff --git a/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterHandler.swift b/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterHandler.swift new file mode 100644 index 0000000..083724c --- /dev/null +++ b/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterHandler.swift @@ -0,0 +1,108 @@ +// +// ClientParameterHandler.swift +// MVMCore +// +// Created by Suresh, Kamlesh on 3/11/21. +// Copyright © 2021 myverizon. All rights reserved. +// + +import Foundation + + +@objcMembers open class ClientParameterHandler: NSObject { + + var parameterHandlerList: [ClientParameterProtocol] = [] + let parametersWorkQueue = DispatchQueue(label: "com.mva.clientparameter", autoreleaseFrequency: .workItem) + //DispatchQueue(label: "com.mva.clientparameter") + let group = DispatchGroup() + + open func createParametersHandler(_ clientParameterModel: ClientParameterModelProtocol) -> ClientParameterProtocol? { + guard let parameterType = MVMCoreObject.sharedInstance()?.clientParameterRegistry?.mapping[clientParameterModel.type] else { return nil } + return parameterType.init(clientParameterModel) + } + + func getClientParameterModel(_ clientParameters: [String: Any]) throws -> ClientParameterModel? { + let data = try JSONSerialization.data(withJSONObject: clientParameters) + return try JSONDecoder().decode(ClientParameterModel.self, from: data) + } + + /// Sample clientParameters + ///{ + /// "timeout": 30, + /// "list": [ + /// { + /// "type": "currentLocation", + /// "inputParameters": { + /// "accuracy": 10, + /// "timeThreshold": 600 + /// } + /// } + /// ] + ///} + /// completionHandler can return flat dictinary or a map. It depends on the paramters handler + open func getParameters(with clientParameters: [String: Any], requestParameters: [String: Any], completionHandler:@escaping ([String: Any]?) -> ()) throws { + + guard let clientParameterModel = try getClientParameterModel(clientParameters) else { + completionHandler(nil) + return + } + + let timeout = clientParameterModel.timeout ?? 30.0 + + + // Dispatch setup on queue to ensure setup is complete before completion callbacks. + parametersWorkQueue.async(group: group, qos: .userInitiated) { + // Create the handler list so that same object can be used when merging. Merging needs default value in case of timeout + for parameterModel in clientParameterModel.list { + if let parameterHandler = self.createParametersHandler(parameterModel) { + self.parameterHandlerList.append(parameterHandler) + } + } + + var returnedList = [[String: AnyHashable]?](repeating: nil, count: self.parameterHandlerList.count) + + var mergedParametersList: [String: AnyHashable] { + var parametersList: [String: AnyHashable] = [:] + for (index, item) in returnedList.enumerated() { + let parameter = item ?? self.parameterHandlerList[index].valueOnTimeout() + parametersList = parametersList.merging(parameter) { (_, new) in new } + } + return parametersList + } + + // Setup completion handlers. Barriered to ensure one happens after the other. + var complete = false + let timeoutWorkItem = DispatchWorkItem(qos: .userInitiated) { + // Holding self. so that its not deallocated in the deispatch queue + completionHandler(mergedParametersList); + complete = true + } + let completionWorkItem = DispatchWorkItem(qos: .userInitiated) { + timeoutWorkItem.cancel() + if !complete { // In the case of firing after timeout. + completionHandler(mergedParametersList); + complete = true + } + } + + // Setup timeout. + self.parametersWorkQueue.asyncAfter(deadline: .now() + .seconds(Int(timeout)), execute: timeoutWorkItem) + + // Setup the parameter execution. + for (index, parameterHandler) in self.parameterHandlerList.enumerated() { + self.group.enter() + parameterHandler.fetchClientParameters(requestParameters: requestParameters, + timingOutIn: timeout) { (receivedParameter) in + // Queue the results for merge. + self.parametersWorkQueue.async { + returnedList[index] = receivedParameter + self.group.leave() // Leaving is only done after setup (barriered). + } + } + } + + // Callback when all parameters have been merged. + self.group.notify(queue: self.parametersWorkQueue, work: completionWorkItem); + } + } +} diff --git a/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterRegistry.swift b/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterRegistry.swift index a211675..bfb9410 100644 --- a/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterRegistry.swift +++ b/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterRegistry.swift @@ -11,8 +11,7 @@ import Foundation @objcMembers open class ClientParameterRegistry: NSObject { - private var mapping: [String: ClientParameterProtocol.Type] = [:] - + var mapping: [String: ClientParameterProtocol.Type] = [:] public override init() { super.init() @@ -23,101 +22,6 @@ import Foundation mapping[T.name] = handler } - open func createParametersHandler(_ clientParameterModel: ClientParameterModelProtocol) -> ClientParameterProtocol? { - guard let parameterType = mapping[clientParameterModel.type] else { return nil } - return parameterType.init(clientParameterModel) - } - - static func getClientParameterModel(_ clientParameters: [String: Any]) throws -> ClientParameterModel? { - let data = try JSONSerialization.data(withJSONObject: clientParameters) - return try JSONDecoder().decode(ClientParameterModel.self, from: data) - } - - /// Sample clientParameters - ///{ - /// "timeout": 30, - /// "list": [ - /// { - /// "type": "currentLocation", - /// "inputParameters": { - /// "accuracy": 10, - /// "timeThreshold": 600 - /// } - /// } - /// ] - ///} - /// completionHandler can return flat dictinary or a map. It depends on the paramters handler - open func getParameters(with clientParameters: [String: Any], requestParameters: [String: Any], completionHandler:@escaping ([String: Any]?) -> ()) throws { - - guard let clientParameterModel = try ClientParameterRegistry.getClientParameterModel(clientParameters) else { - completionHandler(nil) - return - } - - let timeout = clientParameterModel.timeout ?? 30.0 - - let parametersWorkQueue = DispatchQueue(label: "com.mva.clientparameter") - let group = DispatchGroup() - - // Dispatch setup on queue to ensure setup is complete before completion callbacks. - parametersWorkQueue.async(group: group, qos: .userInitiated) { [weak self] in - guard let self = self else { return } - - var parameterHandlerList: [ClientParameterProtocol] = [] - - // Create the handler list so that same object can be used when merging. Merging needs default value in case of timeout - for parameterModel in clientParameterModel.list { - if let parameterHandler = self.createParametersHandler(parameterModel) { - parameterHandlerList.append(parameterHandler) - } - } - - var returnedList = [[String: AnyHashable]?](repeating: nil, count: parameterHandlerList.count) - - var mergedParametersList: [String: AnyHashable] { - var parametersList: [String: AnyHashable] = [:] - for (index, item) in returnedList.enumerated() { - let parameter = item ?? parameterHandlerList[index].valueOnTimeout() - parametersList = parametersList.merging(parameter) { (_, new) in new } - } - return parametersList - } - - // Setup completion handlers. Barriered to ensure one happens after the other. - var complete = false - let timeoutWorkItem = DispatchWorkItem(qos: .userInitiated) { - completionHandler(mergedParametersList); - complete = true - } - let completionWorkItem = DispatchWorkItem(qos: .userInitiated) { - timeoutWorkItem.cancel() - if !complete { // In the case of firing after timeout. - completionHandler(mergedParametersList); - complete = true - } - } - - // Setup timeout. - parametersWorkQueue.asyncAfter(deadline: .now() + .seconds(Int(timeout)), execute: timeoutWorkItem) - - // Setup the parameter execution. - for (index, parameterHandler) in parameterHandlerList.enumerated() { - group.enter() - parameterHandler.fetchClientParameters(requestParameters: requestParameters, - timingOutIn: timeout) { (receivedParameter) in - // Queue the results for merge. - parametersWorkQueue.async { - returnedList[index] = receivedParameter - group.leave() // Leaving is only done after setup (barriered). - } - } - } - - // Callback when all parameters have been merged. - group.notify(queue: parametersWorkQueue, work: completionWorkItem); - } - } - /// Add all registry here. open func registerParameters() { }