Skip to content

Object Update Trigger - #40

Open
milt wants to merge 30 commits into
mainfrom
object_update_trigger
Open

Object Update Trigger#40
milt wants to merge 30 commits into
mainfrom
object_update_trigger

Conversation

@milt

@milt milt commented Jul 27, 2026

Copy link
Copy Markdown
Member

Trigger statement emission from object updates

  • Make Object Cache reflection writes atomic
  • Introduce three new trigger types: ObjectCreate, ObjectUpdate and ObjectDelete
    • ObjectCreate is fired at most once when an object is created, upon the first reflection of requested attributes
    • ObjectUpdate is fired on every update (including the first reflection).
      • The previous expression is now available in ObjectUpdate to refer to the previous state of the object. This can be used to implement change detection.
    • ObjectDelete is fired at most once when an object is deleted.
      • The trigger expression in ObjectDelete can access a snapshot of the object's attributes prior to deletion.
  • Overhaul object subscription to merge requested class attributes via their hierarchy
  • prevent cache misses across class hierarchies in queries

@milt
milt marked this pull request as ready for review July 28, 2026 20:31
@milt
milt requested a review from cliffcaseyyet July 28, 2026 20:31

@cliffcaseyyet cliffcaseyyet left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool, I understand this iteration better than the ones before it. Most of my stuff is organizational or minor but what it's actually doing makes sense.

Comment thread doc/xapi-config.md Outdated
- `type`: Type of trigger. `Interaction` is currently wired into RTI subscriptions and statement processing. `ObjectUpdate` is parsed by the config model but object updates currently feed the object cache rather than firing statement triggers directly.
- `class`: The local HLA interaction class name. For interactions this is matched against the final segment of the RTI interaction class name.
- `type`: One of `Interaction`, `ObjectCreate`, `ObjectUpdate`, or `ObjectDelete`.
- `class`: Local HLA interaction or object class name. Matching is exact: an object trigger for `SimEntity` does not also fire for a reflection reported as `Rabbit`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you removed the text about the final segment of the interaction classname. Did that change or get moved somewhere else?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that was just accidentally removed from the docs and is still the case, but we might actually want to use the same convention as Object classes, ie we don't require root but fully qualify below that? dunno

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A conflict is possible in a complex fom with multiple intermediate interaction classes is my point

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, if we want to lean FQN then I'm fine with that. Does that mean most of the examples should be SimEntity.Rabbit or whatever?

import org.springframework.stereotype.Component;

@Component
public class StatementTriggerDispatcher {

@cliffcaseyyet cliffcaseyyet Jul 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From prior conversation, I am still not convinced this needs to be a component or even a class, and can probably just go as functions right into the TriggerProcessor. This is pretty low priority on my list though.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no problem with that

private List<Object> statementPath = List.of();
private boolean embedded = false;
private String objectType;
private StatementTrigger.Type triggerType;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eeeep this is problematic. We were using inheritance to determine between Interaction and Object when we only had two. This property provides the ability for it to get janky, i.e. an InteractionInjectionContext with a OBJECT_DELETE trigger type. It creates ambiguity as to what determines the type. Following the existing convention you should just make two more extensions from InjectionContext (or have three extend ObjectInjectionContext which you make abstract to get the attributes fields). Or at the very least this should be a field in ObjectInjectionContext only and have an enum with UPDATE, CREATE, DELETE only.

On the complete other end you could refactor to not use inheritance at all but then you would need to account for the differences in a single class AND you would lose the intentional overloads in injectionhandler and have to replace them with more logic.

if (injectionContext instanceof TestInjectionContext) {
return handler.handleLookup(null, target, injectionContext);
if (injectionContext instanceof TestInjectionContext testContext) {
return handler.handleLookup(alias, definitions.get(alias), target, testContext);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm having trouble figuring out what this is doing, perhaps i didn't understand what it was doing before either and why it needs to be different from the non-validation runs.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did catch up to this in another comment but i'll leave it here until that one is figured out.

: interactionTargetDefinition(hlaClass, target);
}

private EventTargetDefinition requireEventTargetDefinition(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A good amount of this stuff seems like essentially syntax validation against the FOM, which I would have expected more at the parse stage than the execution stage? It seems to be doing deep FOM inspection of every layer of target validity in the middle of actual processing here. Was there a particular reason that it needed to be processing-time?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is called during validation by TriggerProcessor.renderTemplateForValidation() but not during a run, I think that is bypassed, but I can chase it down and get a more satisfying answer.

return objectCache.findValueResolution(object, attrTarget);
}

public ValueResolution handleLookup(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah ok i think i get it now per my other question. It cannot pass a CachedObject as the others do beacuse it doesn't have one.

I think part of why this is weird is that it's chosen to already resolve the cachedobject outside the injection handler instead of having the injectionhandler do that work on receiving the details of an injection. Might be worth considering a refactor there, but perhaps there is another structural reason it needs to be done before the injection is being handled?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants