No matter what I have tried, I am still required to refresh the binding in order to receive my newly created values into a component property. After reviewing the debug logs, I noticed this:
09:57:47.790 [DesignerExecEngine-1] DEBUG tags.subscriptions -- Subscribing, paths=
[[default]Blink 1.browseValue, [default]Blink.browseValue, [default]Blink 2.browseValue, [default]Blink 3.browseValue, listeners=[Blink 1, Blink, Blink 2, Blink 3, default]
I also noticed this:
09:58:31.220 [AWT-EventQueue-0] DEBUG vision.binding.tag-binding -- [component=LED Display 15,property=value] Subscribing to "[default]Blink 1" (LED Display 15.value)
09:58:31.220 [AWT-EventQueue-0] DEBUG tags.subscriptions -- Subscribing, paths=[[default]Blink 1], listeners=[[default]Blink 1 --> LED Display 15.value]
This happens upon window load. Currently I am running my tests on [default]Blink 1
. Even if I do initialize my tag subscriptions correctly, it all happens after the binding has been initialized between the existing 'default' provider and the component. The binding system has no reason to relinquish the binding between the component and the original 'default' tag provider (which still exists underneath the client provider I instantiate).
I know that my code works for processing realtime values when the simulation is running, because the component only receives events from my simulation. Then when I disable the simulation, the property value returns to displaying realtime values. But this ONLY WORKS if I first refresh the binding after activating the simulation.
So my question remains. Either I need to programmatically refresh the binding, initialize my simulation tag provider so it takes precedent automatically, or change my tagChanged override somehow. Here is my tagChanged override:
@Override
public void tagChanged(TagChangeEvent event) {
QualifiedValue newValue = event.getValue();
if (newValue == null) {
logger.warn("Received null value in tagChanged for tag: {}", tagPath);
return;
}
// Check if this is a historical or real-time value
if (!processingHistoricalValue) {
// This is a real-time value
lastRealTimeValue = newValue;
logger.debug("Received real-time value for tag {}: {}", tagPath, newValue);
// Only notify listeners of real-time values when not in simulation mode
if (!simMode) {
logger.debug("Forwarding real-time value (not in simulation mode) for tag: {}", tagPath);
notifyListeners(newValue);
} else {
logger.debug("Ignoring real-time value (in simulation mode) for tag: {}", tagPath);
}
} else {
// This is a historical value from the presenter
logger.debug("Received historical value for tag {}: {}", tagPath, newValue);
if (simMode) {
logger.debug("Forwarding historical value (in simulation mode) for tag: {}", tagPath);
notifyListeners(newValue);
} else {
logger.debug("Ignoring historical value (not in simulation mode) for tag: {}", tagPath);
}
}
}
Could I use something like public CompletableFuture<List<QualityCode>> reinitializeTagsAsync(List<TagPath> paths)
?