Okay, I'm stumped, or probably more likely beating my head against a wall because I should be going a different direction.
I have a resource which accepts an expression, to utilize this I have created an expression which will take the path to the resource and run the expression (Think runScript only not script). This all works except that I can't get it to update past the initial execution.
So my questions are:
Is this a good approach, or should I be going more of a Named Query Binding route? If that's the case where do I need to look for a starting point to adding a Type of Binding?
If this is a reasonable approach, where do I need to look to have an expression which updates on Tag and Property changes? I understand that I need a Change Listener of some sort, what I can't seem to find is what shape that needs to take. I have looked into a BoundTagExpression but I can't seem to get that to work.
.subscribeAsync() is the right path to follow, but I see grief in your future if you try to re-implement expression bindings. Is there a reason these bindings cannot be set up in the designer? Can you elaborate on how this flows?
What I am working towards is not intended to be a re-implementation of expression bindings, but an extension to them. The problem I'm trying to solve is when there are "generalized" expression bindings which perhaps only differ by the tag path used or property, but are used across multiple components.
So for instance you have a complex expression with many branches or what not, something like a status indicator for a motor or valve. With the exception of the tag/property which is being examined the expression is identical. Current work flow is to copy and paste bindings or retype them in some cases and then edit them to look at the correct tag/property.
So at this point, you create a resource and then use an expression binding with a special expression which calls the resource.
Okay, so I have perhaps gone down a different road in my navigation of this particular hurdle. Looking through the API, it looks like what I'm really after is implementing InteractionListener on my class, and then using the connect() method.
This is working, as far as the childInteractionUpdated() method is being called, however, what I am struggling to do now is actually update the value.
Am I missing something obvious?
When stepping through the code, I can see the correct tag value being read, and returned, however, the component value (at least in the designer, I haven't checked in a client yet but since I am doing this testing in Vision I would expect it to be very similar), never updates.
The typical pattern is to receive an InteractionListener when your function's connect() method is called. Which you save and use to retrigger the expression containing your function. If appropriate. A function's .execute() method is called by its containing expression to actually perform a calculation.
Keep in mind that the kinds of functions that use a connected InteractionListener are the ones that either a) poll at some interval, or b) subscribe to some other event source for which new values require recomputing.
Also keep in mind that the .connect() operation does not happen to anything inside one of my iteration function's repeating subexpressions. Iteration is fundamentally incompatible with re-triggering. You probably should approach "macro" execution with the same limitation.
I believe I understand what you're trying to tell me, however, I suppose I am unsure of how to apply it.
The issue that I have, is that my function potentially only takes a single string parameter (the path to the resource). I was hoping to allow for the use of tag paths in the expression structure there.
All of this works when the binding is first fired. However, I can not get tag changes to cause a re-trigger of my function, because the argument in the expression is (correctly) a constant expression.
In other words, because the resource path doesn't change so the containing expression is never re-evaluated.
If I force the use of an argument for anything that needs to be dynamically updated, then everything works as expected, it just felt clunky to me to force a Tag to be passed in as an argument. Perhaps I am causing myself pain for something that isn't achievable as an extension.
You must parse your expression to identify the "changeable" items and subscribe to them. When the subscriptions deliver new values, you stash them in your function instance and tell the InteractionListener to trigger. Your code then gets asked to recompute itself and deliver the result to the caller.
Your code must be smart enough to notice when the expression itself changes, so can unsubscribe from things it no longer needs, and to unsubscribe from everything when the function is shut down.
I should repeat that my iteration functions explicitly disallow any nested subscription expressions (nested functions never receive the .connect() call).
I suspect you will choke on the need to track subscriptions per macro caller, not just per macro definition.