bool CommunityHealthWorkerEventCoordinator::Distribute( IIndividualHumanEventContext* pIHEC ) { release_assert( m_pInterventionIndividual ); IDistributableIntervention *di = m_pInterventionIndividual->Clone(); release_assert(di); ICampaignCostObserver* p_icco = nullptr; if (s_OK != pIHEC->GetNodeEventContext()->QueryInterface(GET_IID(ICampaignCostObserver), (void**)&p_icco)) { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "pIHEC->GetNodeEventContext()", "ICampaignCostObserver", "INodeEventContext" ); } di->AddRef(); bool distributed = di->Distribute( pIHEC->GetInterventionsContext(), p_icco ); if( distributed ) { LOG_DEBUG_F("Distributed '%s' intervention to individual %d\n", m_InterventionName.c_str(), pIHEC->GetSuid().data ); } di->Release(); return distributed; }
bool StandardInterventionDistributionEventCoordinator::visitIndividualCallback( IIndividualHumanEventContext *ihec, float & incrementalCostOut, ICampaignCostObserver * pICCO ) { { // Add real checks on demographics based on intervention demographic targetting. // Return immediately if we hit a non-distribute condition if( qualifiesDemographically( ihec ) == false ) { LOG_DEBUG("Individual not given intervention because not in target demographic\n"); return false; } LOG_DEBUG("Individual meets demographic targeting criteria\n"); if (!TargetedIndividualIsCovered(ihec)) { incrementalCostOut = 0; return false; } else { incrementalCostOut = 0; // instantiate and distribute intervention LOG_DEBUG_F( "Attempting to instantiate intervention of class %s\n", std::string(json::QuickInterpreter(intervention_config._json)["class"].As<json::String>()).c_str() ); IDistributableIntervention *di = _di->Clone(); release_assert(di); if (di) { di->AddRef(); di->Distribute( ihec->GetInterventionsContext(), pICCO ); di->Release(); // a bit wasteful for now, could cache it for the next fellow LOG_DEBUG_F("Distributed an intervention %p to individual %d at a cost of %f\n", di, ihec->GetSuid().data, incrementalCostOut); } } } return true; }
bool MultiInterventionDistributor::Distribute(IIndividualHumanInterventionsContext *context, ICampaignCostObserver * const pICCO ) { // ---------------------------------------------------------------------------------- // --- Putting this here because we don't want anything to happen if we are aborting // ---------------------------------------------------------------------------------- if( AbortDueToDisqualifyingInterventionStatus( context->GetParent() ) ) { return false; } // Important: Use the instance method to obtain the intervention factory obj instead of static method to cross the DLL boundary IGlobalContext *pGC = nullptr; const IInterventionFactory* ifobj = nullptr; release_assert(context->GetParent()); if (s_OK == context->GetParent()->QueryInterface(GET_IID(IGlobalContext), (void**)&pGC)) { ifobj = pGC->GetInterventionFactory(); } if (!ifobj) { throw GeneralConfigurationException( __FILE__, __LINE__, __FUNCTION__, "The pointer to IInterventionFactory object is not valid (could be DLL specific)" ); } try { // Parse intervention_list const json::Array & interventions_array = json::QuickInterpreter(intervention_list._json).As<json::Array>(); LOG_DEBUG_F("interventions array size = %d\n", interventions_array.Size()); for( int idx=0; idx<interventions_array.Size(); idx++ ) { const json::Object& actualIntervention = json_cast<const json::Object&>(interventions_array[idx]); Configuration * tmpConfig = Configuration::CopyFromElement( actualIntervention, "campaign" ); assert( tmpConfig ); // Instantiate and distribute interventions LOG_DEBUG_F( "Attempting to instantiate intervention of class %s\n", std::string((*tmpConfig)["class"].As<json::String>()).c_str() ); IDistributableIntervention *di = const_cast<IInterventionFactory*>(ifobj)->CreateIntervention(tmpConfig); if (di) { if (!di->Distribute( context, pICCO ) ) { di->Release(); } } else { INodeDistributableIntervention* ndi = const_cast<IInterventionFactory*>(ifobj)->CreateNDIIntervention( tmpConfig ); release_assert(ndi); if( !ndi->Distribute( context->GetParent()->GetEventContext()->GetNodeEventContext(), nullptr ) ) { ndi->Release(); } } delete tmpConfig; tmpConfig = nullptr; } } catch(json::Exception &e) { // ERROR: ::cerr << "exception casting intervention_config to array! " << e.what() << std::endl; throw GeneralConfigurationException( __FILE__, __LINE__, __FUNCTION__, e.what() ); // ( "Intervention_List json problem: intervention_list is valid json but needs to be an array." ); } // Nothing more for this class to do... Expire(); return true; }
bool MultiInterventionEventCoordinator::visitIndividualCallback( IIndividualHumanEventContext *ihec, float & incrementalCostOut, ICampaignCostObserver * pICCO ) { // Less of this would need to be copied from the base class with a more thoughtful encapsulation of functions // In particular, only the give-intervention(s)-to-individual stuff inside the try statement is different. if( !demographic_restrictions.HasDefaultRestrictions() ) // don't waste any more time with checks if we're giving to everyone { if( qualifiesDemographically( ihec ) == false ) { LOG_DEBUG("Individual not given intervention because not in target demographic\n"); return false; } } LOG_DEBUG("Individual meets demographic targeting criteria\n"); if (!TargetedIndividualIsCovered(ihec)) { incrementalCostOut = 0; return false; } else { incrementalCostOut = 0; try { const json::Array & interventions_array = json::QuickInterpreter( intervention_config._json ).As<json::Array>(); LOG_DEBUG_F("interventions array size = %d\n", interventions_array.Size()); for( int idx=0; idx<interventions_array.Size(); idx++ ) { const json::Object& actualIntervention = json_cast<const json::Object&>(interventions_array[idx]); Configuration * tmpConfig = Configuration::CopyFromElement(actualIntervention); assert( tmpConfig ); // instantiate and distribute intervention LOG_DEBUG_F( "Attempting to instantiate intervention of class %s\n", std::string((*tmpConfig)["class"].As<json::String>()).c_str() ); IDistributableIntervention *di = InterventionFactory::getInstance()->CreateIntervention(tmpConfig); assert(di); delete tmpConfig; tmpConfig = nullptr; if (di) { if (!di->Distribute( ihec->GetInterventionsContext(), pICCO ) ) { di->Release(); // a bit wasteful for now, could cache it for the next fellow } LOG_DEBUG_F("Distributed an intervention %p to individual %d at a cost of %f\n", di, ihec->GetSuid().data, incrementalCostOut); } } } catch(json::Exception &e) { // ERROR: ::cerr << "exception casting intervention_config to array! " << e.what() << std::endl; throw GeneralConfigurationException( __FILE__, __LINE__, __FUNCTION__, e.what() ); // ( "InterventionConfigs json problem: intervention_config is valid json but needs to be an array." ); } } return true; }
//returns false if didn't get the intervention bool NodeLevelHealthTriggeredIV::notifyOnEvent( IIndividualHumanEventContext *pIndiv, const EventTrigger& trigger ) { // ---------------------------------------------------------------------- // --- Ignore events for nodes that don't qualify due to their properties // ---------------------------------------------------------------------- if( !node_property_restrictions.Qualifies( parent->GetNodeContext()->GetNodeProperties() ) ) { return false; } IIndividualHuman *p_human = nullptr; if (s_OK != pIndiv->QueryInterface(GET_IID(IIndividualHuman), (void**)&p_human)) { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "pIndiv", "IIndividualHuman", "IIndividualHumanEventContext" ); } bool missed_intervention = false ; if( distribute_on_return_home && (trigger == EventTrigger::Emigrating) ) { if( p_human->AtHome() ) { // ------------------------------------------------------------------------------------------------ // --- If the individual is leaving his node of residence, then we want to keep track that he left // --- so that when he returns we can give him the interventions that he missed. // ------------------------------------------------------------------------------------------------ release_assert( event_occurred_while_resident_away.count( pIndiv->GetSuid() ) == 0 ); event_occurred_while_resident_away.insert( make_pair( pIndiv->GetSuid(), false ) ); } return false ; } else if( distribute_on_return_home && (trigger == EventTrigger::Immigrating) ) { if( p_human->AtHome() ) { // ------------------------------------------------------------------------------ // --- If the individual has returned home and they missed the intervention, then // --- we want them to get it, assuming they qualify. // ------------------------------------------------------------------------------ release_assert( event_occurred_while_resident_away.count( pIndiv->GetSuid() ) > 0 ); missed_intervention = event_occurred_while_resident_away[ pIndiv->GetSuid() ] ; event_occurred_while_resident_away.erase( pIndiv->GetSuid() ); if( missed_intervention ) { LOG_DEBUG_F( "Resident %d came home and intervention was distributed while away.\n", pIndiv->GetSuid().data ); } } if( !missed_intervention ) { return false ; } } else // the trigger event { // -------------------------------------------------------------------------------------------- // --- If this is one of the non-migrating events that they intervention is listening for // --- and this is not a blackout period, then record that the residents that are away missed // --- the intervention. // -------------------------------------------------------------------------------------------- if( blackout_time_remaining <= 0.0f ) { for( auto& rEntry : event_occurred_while_resident_away ) { rEntry.second = true ; } } } if( !blackout_event_trigger.IsUninitialized() && (blackout_period > 0.0) ) { if( (event_occured_list[ trigger.GetIndex() ].count( pIndiv->GetSuid().data ) > 0) || (!missed_intervention && (blackout_time_remaining > 0.0f)) ) { INodeTriggeredInterventionConsumer * pNTIC = NULL; if (s_OK != parent->QueryInterface(GET_IID(INodeTriggeredInterventionConsumer), (void**)&pNTIC) ) { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent", "INodeTriggeredInterventionConsumer", "INodeEventContext" ); } pNTIC->TriggerNodeEventObservers( pIndiv, blackout_event_trigger ); return false; } } LOG_DEBUG_F("Individual %d experienced event %s, check to see if they pass the conditions before distributing actual_intervention \n", pIndiv->GetInterventionsContext()->GetParent()->GetSuid().data, trigger.c_str() ); assert( parent ); assert( parent->GetRng() ); bool distributed = false; if( _di != nullptr ) { //initialize this flag by individual (not by node) m_disqualified_by_coverage_only = false; if( qualifiesToGetIntervention( pIndiv ) == false ) { LOG_DEBUG_F("Individual failed to qualify for intervention, m_disqualified_by_coverage_only is %d \n", m_disqualified_by_coverage_only); if (m_disqualified_by_coverage_only == true) { onDisqualifiedByCoverage( pIndiv ); } return false; } // Query for campaign cost observer interface from INodeEventContext *parent ICampaignCostObserver *iCCO; if (s_OK != parent->QueryInterface(GET_IID(ICampaignCostObserver), (void**)&iCCO)) { throw QueryInterfaceException( __FILE__, __LINE__, __FUNCTION__, "parent", "ICampaignCostObserver", "INodeEventContext" ); } // Huge performance win by cloning instead of configuring. IDistributableIntervention *di = _di->Clone(); release_assert( di ); di->AddRef(); distributed = di->Distribute( pIndiv->GetInterventionsContext(), iCCO ); if( distributed ) { std::string classname = GetInterventionClassName(); LOG_DEBUG_F("A Node level health-triggered intervention (%s) was successfully distributed to individual %d\n", classname.c_str(), pIndiv->GetInterventionsContext()->GetParent()->GetSuid().data ); } else { LOG_DEBUG_F( "Intervention not distributed?\n" ); } di->Release(); } else { release_assert( _ndi ); // Huge performance win by cloning instead of configuring. INodeDistributableIntervention *ndi = _ndi->Clone(); release_assert( ndi ); ndi->AddRef(); distributed = ndi->Distribute( parent, nullptr ); if( distributed ) { std::string classname = GetInterventionClassName(); LOG_INFO_F("Distributed '%s' intervention to node %d\n", classname.c_str(), parent->GetExternalId() ); } ndi->Release(); } if( distributed ) { if( blackout_on_first_occurrence ) { blackout_time_remaining = blackout_period ; } else { notification_occured = true ; } event_occured_list[ trigger.GetIndex() ].insert( pIndiv->GetSuid().data ); } return distributed; }