var apiConfig = variables.api.getAPIConfig(); var result = structNew(); var logStruct = structNew(); var logArray = arrayNew(1); var thisElementConfig = structNew(); var contentStruct = structNew(); var apiResponse = ""; var loggingEnabled = true; var logFileName = "API_Element_populateCustom.log"; var logErrorFileName = ListFirst(logFileName,".") & "_error." & ListLast(logFileName,"."); var populateCustomLockName = "CCAPIPopulateContent-#Request.SiteID#"; var runPopulateCustom = true; var verbose = false; var usePagePool = false; var pagePoolRequestID = ""; var poolPageReleased = false; var pagePoolRequestStart = ""; var pagePoolRequestEndBy = ""; var pagePoolRequestCurrentTime = ""; var pagePoolParams = StructNew(); var pagePoolMaxAttempts = 20; var pagePoolAttemptCount = 0; var pagePoolRequestWaitTime = variables.apiConduitPool.getRequestWaitTimeSetting(); // ms var pagePoolRequestTimeout = variables.apiConduitPool.getGlobalTimeoutSetting(); // seconds var pagePoolLogging = variables.apiConduitPool.getLoggingSetting(); // boolean var pagePoolLog = StructNew(); var pagePoolLogText = ""; pagePoolLog.msg = ""; pagePoolLog.logFile = ListFirst(logFileName,".") & "_pagePool." & ListLast(logFileName,"."); // Init the return data structure result.status = false; result.msg = ""; result.data = StructNew(); // Set the logging flag if ( isStruct(apiConfig) AND StructKeyExists(apiConfig, "logging") AND StructKeyExists(apiConfig.logging, "enabled") AND IsBoolean(apiConfig.logging.enabled) ) loggingEnabled = apiConfig.logging.enabled; else loggingEnabled = false; // Check to make sure element config name is in the API Config file // - Get the configuration options from the specified element node if ( isStruct(apiConfig) AND StructKeyExists(apiConfig, "elements") AND StructKeyExists(apiConfig.elements,arguments.elementName) ) thisElementConfig = apiConfig.elements[arguments.elementName]; // -- START - Page Pool Logic -- // // If conduit pages are configured use the Page Pool system to get the conduit pageID for the request if ( StructKeyExists(apiConfig.elements[arguments.elementName],"elementType") AND apiConfig.elements[arguments.elementName].elementType EQ "custom" AND StructKeyExists(apiConfig.elements[arguments.elementName],"gceConduitConfig") AND IsStruct(apiConfig.elements[arguments.elementName].gceConduitConfig) ) { usePagePool = true; // Get the current Page Request and store it locally; //pagePoolRequestID = Request.ADF.apiPagePool.requestID; pagePoolRequestID = CreateUUID(); pagePoolRequestStart = variables.apiConduitPool.pagePoolDateTimeFormat(Now()); pagePoolRequestTimeout = variables.apiConduitPool.getElementConfigTimeout(CEconfigName=arguments.elementName); pagePoolRequestEndBy = DateAdd("s",pagePoolRequestTimeout,pagePoolRequestStart); if ( verbose ) { variables.utils.doDUMP(pagePoolRequestID,"pagePoolRequestID"); variables.utils.doDUMP(pagePoolRequestStart,"pagePoolRequestStart"); variables.utils.doDUMP(pagePoolRequestEndBy,"pagePoolRequestEndBy"); } // Run REQUEST until a Conduit page becomes available while( true ) { pagePoolParams = variables.apiConduitPool.getConduitPageFromPool(CEconfigName=arguments.elementName, requestID=pagePoolRequestID); if ( verbose ) { variables.utils.doDUMP(pagePoolParams.pageID,"page Pool pageID"); variables.utils.doDUMP(pagePoolParams,"pagePoolParams"); variables.utils.doDUMP(Application.ADF.apipool,"Application.ADF.apipool"); } if ( pagePoolLogging ) { pagePoolLogText = "Element [#arguments.elementName#] RequestID: #pagePoolRequestID# - Conduit PageID Requested: #pagePoolParams.pageID#"; pagePoolLog.msg = _apiLogMsgWrapper(logMsg=pagePoolLog.msg,logEntry=pagePoolLogText); } // check if slot in pool is returned if ( pagePoolParams.pageID neq 0 ) { arguments.forcePageID = pagePoolParams.pageID; arguments.forceSubsiteID = pagePoolParams.subsiteID; arguments.forceControlID = variables.apiConduitPool.getCCAPIcontrolID( csPageID=pagePoolParams.pageID ,formID=pagePoolParams.FormID ,controlName="ccapiGCEPoolControl_#pagePoolParams.pageID#_#pagePoolParams.FormID#" ); arguments.forceUsername = pagePoolParams.csuserid; // TODO: add decryption to the lookup of this pagePool password - should be stored encrypted in the config file arguments.forcePassword = variables.apiConduitPool.getConduitPoolPagePasswordFromAPIConfig(pageID=pagePoolParams.pageID); // If a valid pageID is returned then BREAK the WHILE loop break; } else { pagePoolRequestCurrentTime = variables.apiConduitPool.pagePoolDateTimeFormat(Now()); // Befroe moving on check to make sure the request has not timed out - Default: 15 secs if ( DateCompare(pagePoolRequestCurrentTime,pagePoolRequestEndBy,"s") GTE 1 ) { runPopulateCustom = false; if ( pagePoolLogging ) { pagePoolLogText = "Element [#arguments.elementName#] RequestID: #pagePoolRequestID# - NO OPEN PAGE FOUND! Request Timed Out!!"; pagePoolLog.msg = _apiLogMsgWrapper(logMsg=pagePoolLog.msg,logEntry=pagePoolLogText); } break; } if ( pagePoolLogging ) { pagePoolLogText = "Element [#arguments.elementName#] RequestID: #pagePoolRequestID# - NO OPEN PAGE FOUND! Sleeping..."; pagePoolLog.msg = _apiLogMsgWrapper(logMsg=pagePoolLog.msg,logEntry=pagePoolLogText); } // Wait for a page to be available from the conduit page pool sleep(pagePoolRequestWaitTime); // default: 200 if ( pagePoolLogging ) { pagePoolLogText = "Element [#arguments.elementName#] RequestID: #pagePoolRequestID# - NO OPEN PAGE FOUND! Waking up to try again..."; pagePoolLog.msg = _apiLogMsgWrapper(logMsg=pagePoolLog.msg,logEntry=pagePoolLogText); } } // Count the attempt to request a conduit page from the pool pagePoolAttemptCount = pagePoolAttemptCount + 1; // If the attempts are greater than the max attempts KILL THE WHOLE REQUEST // TODO: Maybe instead of killing the request we should pass the request to the standard conduit page and just get in line and wait for our turn if ( pagePoolAttemptCount GTE pagePoolMaxAttempts) { // Log the issue!! runPopulateCustom = false; if ( pagePoolLogging ) { pagePoolLogText = "Element [#arguments.elementName#] RequestID: #pagePoolRequestID# - Warning: Requested a Conduit Page #pagePoolAttemptCount# Times. Max Exceeded!"; pagePoolLog.msg = _apiLogMsgWrapper(logMsg=pagePoolLog.msg,logEntry=pagePoolLogText); } break; } } } // -- END - Page Pool Logic --// // Check if the "forceControlName", "forceSubsiteID", and "forcePageID" arguments are defined, // then setup the element config to bypass the config file. if ( arguments.forcePageID GT 0 AND ( LEN(TRIM(arguments.forceControlName)) OR arguments.forceControlID GT 0 ) ) { // Override any value set from the config thisElementConfig['pageID'] = arguments.forcePageID; if ( IsNumeric(arguments.forceSubsiteID) AND arguments.forceSubsiteID GT 0 ) thisElementConfig['subsiteID'] = arguments.forceSubsiteID; else thisElementConfig['subsiteID'] = variables.csData.getSubsiteIDByPageID(pageid=thisElementConfig['pageID']); thisElementConfig['elementType'] = "custom"; // Check if we want to use the control name of control id if ( LEN(TRIM(arguments.forceControlName)) ) thisElementConfig['controlName'] = arguments.forceControlName; else if ( arguments.forceControlID GT 0 ) thisElementConfig['controlID'] = arguments.forceControlID; } else if ( StructKeyExists( arguments.data,"pageID" ) AND IsNumeric(arguments.data.pageID) AND arguments.data.pageID GT 0 ) { // Override with the PageID passed in from the arguments.data thisElementConfig["pageID"] = arguments.data.pageID; thisElementConfig['subsiteID'] = variables.csData.getSubsiteIDByPageID(pageid=thisElementConfig['pageID']); thisElementConfig['elementType'] = "custom"; // Check if controlName or the controlID were passed in via the data structure if ( StructKeyExists(arguments.data,"controlName") AND LEN(TRIM(arguments.data.controlName)) ) thisElementConfig['controlName'] = arguments.data.controlName; else if ( StructKeyExists(arguments.data,"controlID") AND arguments.data.controlID GT 0 ) thisElementConfig['controlID'] = arguments.data.controlID; } else if ( isStruct(apiConfig) AND StructKeyExists(apiConfig, "elements") AND StructKeyExists(apiConfig.elements,arguments.elementName) ) { if ( StructKeyExists(thisElementConfig,"pageID") AND IsNumeric(thisElementConfig['pageID']) AND thisElementConfig['pageID'] GT 0 ) thisElementConfig["subsiteID"] = variables.csData.getSubsiteIDByPageID(pageid=thisElementConfig['pageID']); } else { // Log the error message also if ( loggingEnabled ) { logStruct.msg = "#request.formattedTimestamp# - Element [#arguments.elementName#] is not defined in the API Configuration."; logStruct.logFile = logErrorFileName; arrayAppend(logArray, logStruct); variables.utils.bulkLogAppend(logArray); } result.msg = "Element [#arguments.elementName#] is not defined in the API Configuration. arguments.forceSubsiteIDID = #arguments.forceSubsiteID# - arguments.forcePageID = #arguments.forcePageID# - arguments.forceControlID = #arguments.forceControlID#"; return result; } // Check that we are updating a custom element if( thisElementConfig["elementType"] NEQ "custom" ) { if ( loggingEnabled ) { // Log the error message also logStruct.msg = "#request.formattedTimestamp# - Element [#arguments.elementName#] is not defined as a custom element in the API Configuration."; logStruct.logFile = logErrorFileName; arrayAppend(logArray, logStruct); variables.utils.bulkLogAppend(logArray); } result.msg = "Element [#arguments.elementName#] is not defined as a custom element in the API Configuration."; return result; } // Construct REQUIRED keys for the content creation API contentStruct.subsiteID = thisElementConfig["subsiteID"]; contentStruct.pageID = thisElementConfig["pageID"]; // 2013-06-24 - Each check needs to be done separately. if ( StructKeyExists(thisElementConfig, "controlID") ) contentStruct.controlID = thisElementConfig["controlID"]; if ( StructKeyExists(thisElementConfig, "controlName") ) contentStruct.controlName = thisElementConfig["controlName"]; // If we find the option to submit change in the data if( StructKeyExists(arguments.data, "submitChange") ) contentStruct.submitChange = arguments.data.submitChange; else contentStruct.submitChange = "1"; // If we find the comment for the submission in the data struct if( StructKeyExists(arguments.data, "submitChangeComment") ) contentStruct.submitChange_comment = arguments.data.submitChangeComment; else contentStruct.submitChange_comment = "Submit data for Custom element through API"; // Following structure contains the data. The structure keys are the 'field names' contentStruct.data = arguments.data; if ( verbose ) variables.utils.doDUMP(contentStruct,"contentStruct",0); // Error handling try { // Call the API to run the CCAPI Command if ( LEN(TRIM(arguments.forceUsername)) AND LEN(TRIM(arguments.forcePassword)) ) { apiResponse = variables.api.runCCAPI(method="populateCustomElement", sparams=contentStruct, forceUserName=arguments.forceUsername, forcePassword=arguments.forcePassword, forceRemote=arguments.forceRemote); } else { apiResponse = variables.api.runCCAPI(method="populateCustomElement", sparams=contentStruct, forceRemote=arguments.forceRemote); } // Check that the API ran if ( apiResponse.status ) { // Pass back the API return to the results result = apiResponse; // Log the success if ( listFirst(result.data, ":") eq "Success" ) { logStruct.msg = "#request.formattedTimestamp# - Element Updated/Created: #thisElementConfig['elementType']# [#arguments.elementName#]. ContentUpdateResponse: #result.data#"; logStruct.logFile = logFileName; arrayAppend(logArray, logStruct); if ( pagePoolLogging ) { pagePoolLogText = "Element [#arguments.elementName#] RequestID: #pagePoolRequestID# - Success Populating Element..."; pagePoolLog.msg = _apiLogMsgWrapper(logMsg=pagePoolLog.msg,logEntry=pagePoolLogText); } } else { // Log the error message also result.msg = listRest(result.data, ":"); logStruct.msg = "#request.formattedTimestamp# - Error updating element: #thisElementConfig['elementType']# [#arguments.elementName#]. Error recorded: #result.msg#"; logStruct.logFile = logErrorFileName; arrayAppend(logArray, logStruct); if ( pagePoolLogging ) { pagePoolLogText = "Element [#arguments.elementName#] RequestID: #pagePoolRequestID# - Error Populating Element..."; pagePoolLog.msg = _apiLogMsgWrapper(logMsg=pagePoolLog.msg,logEntry=pagePoolLogText); } } } else { // Error while running the API Command result = apiResponse; // Log the error message logStruct.msg = "#request.formattedTimestamp# - Error"; if ( StructKeyExists(result,"msg") ) logStruct.msg = logStruct.msg & " [Message: #result.msg#]"; if ( StructKeyExists(result,"data") AND IsSimpleValue(result.data) ) logStruct.msg = logStruct.msg & " [Details: #result.data#]"; else if ( StructKeyExists(result,"data") AND StructKeyExists(result.data, "detail") ) logStruct.msg = logStruct.msg & " [Details: #result.data.detail#]"; logStruct.logFile = logErrorFileName; arrayAppend(logArray, logStruct); } } catch ( ANY e ) { // Error caught, send back the error message result.status = false; result.msg = e.message; result.data = e; logStruct.msg = "#request.formattedTimestamp# - Error"; if ( StructKeyExists(e,"message") ) logStruct.msg = logStruct.msg & " [Message: #e.message#]"; if ( StructKeyExists(e, "detail") ) logStruct.msg = logStruct.msg & " [Details: #e.detail#]"; //logStruct.msg = "#request.formattedTimestamp# - Error [Message: #e.message#] [Details: #e.detail#]"; logStruct.logFile = logErrorFileName; arrayAppend(logArray, logStruct); } if ( usePagePool ) { poolPageReleased = variables.apiConduitPool.markRequestComplete(requestID=pagePoolRequestID); if ( pagePoolLogging ) { if ( poolPageReleased ) pagePoolLogText = "Element [#arguments.elementName#] RequestID: #pagePoolRequestID# - Conduit PageID Released: #contentStruct.pageID#"; else pagePoolLogText = "Element [#arguments.elementName#] RequestID: #pagePoolRequestID# - Error: Issue releasing Conduit PageID: #contentStruct.pageID#"; pagePoolLog.msg = _apiLogMsgWrapper(logMsg=pagePoolLog.msg,logEntry=pagePoolLogText); } if ( pagePoolLogging ) variables.utils.logAppend(msg=pagePoolLog.msg,logfile=pagePoolLog.logFile,useUTC=false); if ( verbose ) variables.utils.doDUMP(Application.ADF.apipool,"Application.ADF.apipool"); } // Write the log files if ( loggingEnabled and arrayLen(logArray) ) variables.utils.bulkLogAppend(logArray); // Check if we want to force the logout if ( arguments.forceLogout ) variables.api.ccapiLogout(); return result; var timeStamp = "#DateFormat(Now(), 'yyyy-mm-dd')# #TimeFormat(Now(), 'HH:mm:ss.L')#"; if ( LEN(TRIM(arguments.logEntry)) ) return arguments.logMsg & CHR(13) & timeStamp & " - " & arguments.logEntry; else return arguments.logMsg & CHR(13) & timeStamp;