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;
    }
Exemplo n.º 3
0
    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;
    }
Exemplo n.º 5
0
    //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;
    }