Client is in TREP environment , everytime when client start the program to fetch items.
The program get "Source unavailable" messages several times after the "all is well received" message received.
The "Source unavaiable" status generally is created by RFA to inform that the data's status is suspect because the requested service is down or unavailable and the item will be recovered when the service is up.
This log should be from the scenario that application requests item before the connection is establised so the requested service was not avialable at that time. This commonly be found in the application such as "StarterConsumer" example that request item imediately after login request without verifying service status.
With regard to the "received invalid item data from server." message, the message should not be received from API/feed. I understand that the message is the application's message. Is this correct?
Below is the snippet example code based on StarterConsumer to verify Service Status to solve this issue.
Step 1: Send the Directory Request after received login success response.
Handle* StarterConsumer::sendDirectoryRequest(){ ReqMsg reqMsg; AttribInfo attribInfo; Handle* dirHandle; OMMItemIntSpec ommItemIntSpec; // To request a specific service directory, set the serviceName on the request as follows: // attribInfo.setServiceName( RFA_String( "XYZ_SERVICE", 0, false) ); // Otherwise, the request by default will be for all available services. reqMsg.setMsgModelType(MMT_DIRECTORY); reqMsg.setInteractionType(ReqMsg::InitialImageFlag | ReqMsg::InterestAfterRefreshFlag); attribInfo.setServiceName(_cfgVars.serviceName);//Optional: Set the service name in request// attribInfo.setDataMask(rfa::rdm::SERVICE_INFO_FILTER | rfa::rdm::SERVICE_STATE_FILTER); reqMsg.setAttribInfo(attribInfo); ommItemIntSpec.setMsg(&reqMsg); AppUtil::log(__LINE__, AppUtil::TRACE, "Create Directory Request %s", _cfgVars.serviceName.c_str()); dirHandle = _pOMMConsumer->registerClient(_pEventQueue, &ommItemIntSpec, *this, NULL); return dirHandle;}
Step 2: Add the Directory response process, at this step we will send Item Request after we have received the Directory response.
void StarterConsumer::processRespMsg(const rfa::sessionLayer::OMMItemEvent& event, const RespMsg& respMsg){ switch(respMsg.getMsgModelType()) { case MMT_LOGIN: processLoginResponse(event, respMsg); break; case MMT_MARKET_PRICE: processMarketPriceResponse(event, respMsg); break; case MMT_DIRECTORY: processDirectoryResponse(event, respMsg);//Add the Directory Response handle break; default: AppUtil::log(__LINE__, AppUtil::WARN, "<- Received unhandled OMMItemEvent msgModelType: %u", (UInt32)respMsg.getMsgModelType()); break; }}void StarterConsumer::processDirectoryResponse(const rfa::sessionLayer::OMMItemEvent& event, const RespMsg& respMsg){ RespStatus respStatus = respMsg.getRespStatus(); // Check if we have refresh complete if (respMsg.getIndicationMask() & RespMsg::RefreshCompleteFlag) { // Check if the stream is open if (respMsg.getHintMask() & RespMsg::RespStatusFlag && respStatus.getStreamState() == RespStatus::OpenEnum) { // Check if we have a usable payload if ((respMsg.getHintMask() & RespMsg::PayloadFlag) && !respMsg.getPayload().isBlank()) { AppUtil::log(__LINE__, AppUtil::TRACE, "Received Directory Response"); _pDecoder->decodeData(respMsg.getPayload());// TO-DO: Client can process the service status here// sendItemRequest(_cfgVars.itemName, _cfgVars.serviceName); } } }}
This should have resolve the "Source unavailable" in case of service state on server side is actually up!
But for the completion, we can go further by checking that Service Status is actually up and ready for you to request items
Step 3: Decode Directory Response and check the Service State before sending Item Request, (Optional, but actually is the right thing to do), we will replace the TO-DO code in the Step 2)
//_pDecoder->decodeData(respMsg.getPayload());// TO-DO: Client can process the service status here////sendItemRequest(_cfgVars.itemName, _cfgVars.serviceName);RFA_String testService = _cfgVars.serviceName;UInt serviceState = 0;UInt acceptingRequest = 0;RespStatus stateStatus;UInt stateStatusFlag = 0;bool result = false;stateStatus.clear();result = getDirectoryServiceState(respMsg.getPayload(), testService, &serviceState, &acceptingRequest, &stateStatus, &stateStatusFlag);if (result == true){ AppUtil::log(__LINE__, AppUtil::TRACE, "Service: %s, ServiceState: %d, AcceptingRequest: %d, stateStatus: %s, stateStatusFlag", testService.c_str(), serviceState, acceptingRequest, stateStatus.getStatusText().c_str(), stateStatusFlag); if(serviceState == 1 && acceptingRequest == 1) { sendItemRequest(_cfgVars.itemName, _cfgVars.serviceName);// Send item request// AppUtil::log(__LINE__, AppUtil::TRACE, "Send item request"); }}else{ AppUtil::log(__LINE__, AppUtil::TRACE, "Service: %s not found", testService.c_str());}
This function is an example of how to decode and get the Service State and Accepting Request of the specified Service Name from Directory Response.
Note that our code is just an example serves as a guideline, the errors are omitted.
bool getDirectoryServiceState(const Data& inputData, const RFA_String service_name, UInt* _serviceState, UInt* _acceptingRequests, RespStatus* _stateStatus, UInt* _stateStatusFlag){ const Map& input = static_cast <const Map&>(inputData); int outputchecker = 0; bool result = false; MapReadIterator itMap; itMap.start(input); // decode entries while (!itMap.off()) { const MapEntry& mapEntry = static_cast <const MapEntry&>(itMap.value()); RFA_String _serviceName = static_cast<const DataBuffer&> (mapEntry.getKeyData()).getAsString(); if (_serviceName == service_name)// found service name { if (mapEntry.getData().getDataType() != FilterListEnum) { //ERROR Expected data datatype of FilterList return result; } const FilterList& filterList = static_cast<const FilterList&>(mapEntry.getData()); FilterListReadIterator flRI; flRI.start(filterList); while (!flRI.off()) { const FilterEntry& filterEntry = flRI.value(); if (filterEntry.getFilterID() == SERVICE_STATE_ID) { if (filterEntry.getData().getDataType() != ElementListEnum) { //ERROR Expected data datatype of ElementList return result; } const ElementList& elementList = static_cast<const ElementList&>(filterEntry.getData()); ElementListReadIterator elReadIter; elReadIter.start(elementList); while (!elReadIter.off()) { const ElementEntry& element = elReadIter.value(); const RFA_String& elementName = element.getName(); // get ServiceState - UInt if (elementName == ENAME_SVC_STATE) { *_serviceState = (static_cast<const DataBuffer&> (element.getData())).getUInt(); outputchecker |= 1; } // get AcceptingRequests - UInt else if (elementName == ENAME_ACCEPTING_REQS) { *_acceptingRequests = (static_cast<const DataBuffer&> (element.getData())).getUInt(); outputchecker |= 2; } // get AcceptingRequests - RespStatus else if (elementName == ENAME_STATUS) { *_stateStatus = (static_cast<const DataBuffer&> (element.getData())).getRespStatus(); *_stateStatusFlag = true; outputchecker |= 4; } if (outputchecker == (1 | 2 | 4)) { return true; } elReadIter.forth(); } } flRI.forth(); } } itMap.forth(); }}
For more information about this please refer to
RFA C++ Tutorial 9 (Directory message) and RFA C++ Tutorial 10 (Steps to request item after received Directory and Dictionary)