/** * Looks in the current set of triggers for the trigger with the latest (most recent) trigger * time. Assumes that the trigger collection has been sorted and are currently stored in ascending * trigger timestamp sorted order. Latest time will be the last one in the list. */ long getLatestCurrentTriggerTime() { // Method implementation comments go here ... BeliefUpdateTrigger last_trigger; try { last_trigger = (BeliefUpdateTrigger) _current_triggers.get(_current_triggers.size() - 1); } catch (IndexOutOfBoundsException ioobe) { if (_logger.isInfoEnabled()) _logger.info("Cannot get latest trigger time from empty list."); return System.currentTimeMillis(); } return last_trigger.getTriggerTimestamp(); } // method getLatestCurrentTriggerTime
/** * Add a trigger to this current history. * * @param trigger The new trigger to be added. * @return False if the trigger is not added. This happens if the timestamp of the trigger * precedes the last computed belief state timestamp. */ boolean add(BeliefUpdateTrigger trigger) { // Method implementation comments go here ... // I am pretty sure having an inequality here is better. I // originally had "<=", which caused some problems for // simultaneous actions/diagnosis. Anyway, if you are // debugging a problem and happen to look here, this might be // useful information for you. // if ((_last_computed_belief != null) && (trigger.getTriggerTimestamp() < _last_computed_belief.getTimestamp())) { if (_logger.isDetailEnabled()) _logger.detail("Found late arriving trigger."); if (!shouldAddLateArrivingTrigger(trigger)) { return false; } if (_logger.isDetailEnabled()) _logger.detail("Decided to add late arriving trigger."); } // if late arriving trigger // This will simply append it, though we will sort it by // timestamp later. // _current_triggers.add(trigger); // BelievabilityDiagnosis objects require some special // handling as far as ensuring that our data structures stay // current. // if (trigger instanceof BelievabilityDiagnosis) { BelievabilityDiagnosis diag = (BelievabilityDiagnosis) trigger; // Must track the last explicit diagnosis for sensors in // case we find that we need to add implicit diagnoses for // them. // _last_explicit_diagnosis.put(diag.getSensorName(), trigger); // An explict diagnosis should clear out the last implict // diagosis if there was any. // _last_implicit_diagnosis_time.remove(diag.getSensorName()); // Also need to track all the sensor names, so that we can // handle the case of having received diagnoses from all // sensors before the sensor latency window alarm expires. // _current_sensors.add(diag.getSensorName()); } // If this is a diagnosis trigger return true; } // method add
public int compare(Object o1, Object o2) { if (!(o1 instanceof BeliefUpdateTrigger) || !(o2 instanceof BeliefUpdateTrigger)) throw new ClassCastException("Cannot compare objects. Not BeliefUpdateTriggers."); BeliefUpdateTrigger t1 = (BeliefUpdateTrigger) o1; BeliefUpdateTrigger t2 = (BeliefUpdateTrigger) o2; if (t1.getTriggerTimestamp() < t2.getTriggerTimestamp()) return -1; if (t1.getTriggerTimestamp() > t2.getTriggerTimestamp()) return 1; // If the timestamps are the same, then we define an action to // preceed a diagnosis. // if ((o1 instanceof BelievabilityAction) && (o2 instanceof DiagnosisTrigger)) return -1; // Equality case is zero return value. // return 0; } // method compare
/** * This is the main crank to turn on this history. It will factor in everything it knows about the * current triggers and produce a new belief state. */ void updateBeliefState() throws BelievabilityException { // Iterate over the collection of triggers and compute a // series of belief states until we get to the end of the // list. This final belief state is the one we want. // // This 'no trigger' case should not really hapen, since we // should call this only after adding at least one trigger. // However, better to explicitly check for this and deal with // it gracefully then have the system bomb when the // assumptions are violated. Here we simply do not update the // belief state. // if (_current_triggers.size() < 1) { if (_logger.isInfoEnabled()) _logger.info("Ignoring belief update due to zero triggers."); return; } if (_logger.isInfoEnabled()) _logger.info("Belief Update Starting for: " + _asset_id); // We should first sort this trigger collection, as // everything else here will require it to be sorted. // Collections.sort(_current_triggers, new TriggerComparator()); if (_logger.isDetailEnabled()) _logger.detail("Explicit trigger count is " + _current_triggers.size() + " for " + _asset_id); // Before updating the belief state, we need to check whether // or not we will need to add any implicit diagnoses. Some // sensors do not report infomration when it is the same for // efficiency reasons, so we need to make sure we treat this // case correctly. This works by simply adding extra triggers // to the list at the end. // addImplicitDiagnoses(getLatestCurrentTriggerTime()); if (_logger.isDetailEnabled()) _logger.detail( "Updating belief based on " + _current_triggers.size() + " triggers for " + _asset_id); // Handle case where we might be computing the first belief // state. // if (_last_computed_belief == null) { // The default belief to use when we have no record of a // previous belief is defined in the constructor, based on // the state of the plugin. // _last_computed_belief = _default_belief; _last_computed_belief.setTimestamp(getEarliestCurrentTriggerTime()); } BeliefState latest_belief = _last_computed_belief; if (_logger.isDetailEnabled()) _logger.detail("Initial belief before trigger list: " + latest_belief.toString()); // This iterator will return items in ascending order (by // trigger time). // Iterator trigger_iter = _current_triggers.iterator(); while (trigger_iter.hasNext()) { BeliefUpdateTrigger trigger = (BeliefUpdateTrigger) trigger_iter.next(); if (_logger.isDetailEnabled()) _logger.detail("Processing trigger: " + trigger.toString()); latest_belief = _model_manager.updateBeliefState(latest_belief, trigger); if (_logger.isDetailEnabled()) _logger.detail("Belief after trigger: " + latest_belief.toString()); } // while trigger_iter // Once we have incorporated all the triggers into the // computed belief state, we should clear them out, along with // anything else that is associated with this latency window // we have maintained. // clearTriggerHistory(); _last_computed_belief = latest_belief; // Note that we choose not to worry about what to do with this // belief state here. The decision whether to publish or not // should be made by whatever routine is actually calling this // update method. // if (_logger.isInfoEnabled()) _logger.info("Belief Update Ended for: " + _asset_id); } // method updateBeliefState
/** * Main method for handling the arrival of a belief update trigger. * * @param trigger The newly arriving trigger t be handled. */ synchronized void handleBeliefTrigger(BeliefUpdateTrigger trigger) throws BelievabilityException { // Method implementation comments go here ... if (_logger.isDetailEnabled()) _logger.detail("Handling trigger: " + trigger.toString()); // There are two events that can happen which impact the // details about how to deal with triggers: rehydration and // unleashing. In both cases, these effect what we use for // the initial belief state (the first belief update after // these events.) The model manager has the status of whether // or not rehydration or unleashing is happening, so we use // this opportunity to check those and arrange our internal // variables so that the right thing will happen when we do a // belief update. handleSpecialEvents(); // First step is to add the trigger (no matter what type of // trigger this is, we add it). // if (!add(trigger)) { if (_logger.isDebugEnabled()) _logger.debug("Trigger not added to history " + _asset_id + " (happened in the past?)"); return; } // Now we run through the possible conditions under which we // may want to compute a new belief state, predominantly based // upon the type of trigger we are seeing.. // We only publish in response to a timer/alarm going off. // However, there are four types of possible alarms that // could trigger publishing: PublishDelayTimeTrigger, // PublishIntervalTimeTrigger, ForceUpdateTimeTrigger and // SensorLatencyTimeTrigger. // if (trigger instanceof TimeUpdateTrigger) { if (_logger.isDetailEnabled()) _logger.detail( "Time-based update trigger " + trigger.getClass().getName() + ". Updating and publishing for asset " + _asset_id); // When we are forcing an update, we want to ensure that // any alarams started to delay the belief computation are // cancelled. // if (trigger instanceof ForceUpdateTimeTrigger) { cancelAlarm(_delay_alarm); _delay_alarm = null; cancelAlarm(_latency_alarm); _latency_alarm = null; // Note that we do not want to cancel the publish // interval alarm, since we are not sure if this // updated belief will actually be published. If it // will be published, then the code that will publish // it will handle cancleling any outstanding alarm for // that. } updateBeliefState(); publishLatestBelief(); return; } // if an alarm trigger type occurs // On actions, we do not want to release a state estimation // until we have waited long enough for the sensors to give a // diagnosis for the new state that could result from this // action having successfully completed. Thus, we want to // start a sensor latency timer when we see this so that we // wait at least this long. The main complication, is that we // may already have some diagnoses queued up in the trigger // history. The solution here is to bring the belief state // up-to-date through this current action, but without // publishing it. We then start a sensor latency timer which // will wait a while before publishing a new state // estimation, in hopes we will get diagnoses from the asset's // sensors. // if (trigger instanceof BelievabilityAction) { // We always want to start with a fresh latency timer for // an action, because we relay on the sensors to give us // the feedback on the results of actions. Thus, we // always want to wait for all sensors to report after an // action completes before we publish a new state // estimation. // cancelAlarm(_latency_alarm); _latency_alarm = null; if (_logger.isDetailEnabled()) _logger.detail("Action trigger handling: internal update for: " + _asset_id); // We bring the belief sate up-to-date for any and all // existing triggers in the history (clearing out the // history as well). Do not publish though. // updateBeliefState(); // Now force a state estiation publication in the future. // if (_logger.isDetailEnabled()) _logger.detail("Action trigger handling: latency timer for: " + _asset_id); startSensorLatencyTimer(); return; } // if trigger instanceof BelievabilityAction // If we have seen a diagnosis from all sensors, then we // should not wait until the end of the max sensor latency // period. Note that if there is only one sensor, this wil // return true on the first diagnosis addition and thus cause // an immediate belief computation. // if (seenAllSensors()) { cancelAlarm(_latency_alarm); _latency_alarm = null; if (USE_DELAY_TIMER) { if (_logger.isDetailEnabled()) _logger.detail("Seen all sensors. " + "Starting publish delay timer for: " + _asset_id); startPublishDelayTimer(); } else { if (_logger.isDetailEnabled()) _logger.detail("Seen all sensors. " + "Updating and publishing for asset " + _asset_id); updateBeliefState(); publishLatestBelief(); } return; } // if seen all sensors // If this is the first sensor we are seeing (and there are // more than one for this asset), then we need to start a // timer to wait for the maximum latency time before actually // generating a new belief state. // if (trigger instanceof BelievabilityDiagnosis) { // If we receive a diagnoses, *and* there is no latency // alarm, then this must be the first diagnoses we are // adding to the set of current triggers. // // However, the converse is not true: it is possible for // the sensor latency timer to exist even though this is // the first diagnosis being added. This case happens // after the arrival of a SuccessfulAction object, where // we immediate start a time rot wait for all new sensor // values that should occur after the action takes place. // if (_latency_alarm == null) { if (_logger.isDetailEnabled()) _logger.detail("First, diagnosis, starting latency timer for: " + _asset_id); startSensorLatencyTimer(); return; } else { if (_logger.isDetailEnabled()) _logger.detail("Deferring belief update (diagnosis) for: " + _asset_id); return; } } // if BelievabilityDiagnosis else { if (_logger.isDebugEnabled()) _logger.debug("unknown trigger for: " + _asset_id); } } // method handleBeliefTrigger