aspect RagConnectObserver { class RagConnectObserver implements ASTState.Trace.Receiver { ASTState.Trace.Receiver oldReceiver; class RagConnectObserverEntry { ASTNode node; String attributeString; Runnable attributeCall; RagConnectObserverEntry(ASTNode node, String attributeString, Runnable attributeCall) { this.node = node; this.attributeString = attributeString; this.attributeCall = attributeCall; } } java.util.List observedNodes = new java.util.ArrayList<>(); RagConnectObserver(ASTNode node) { // set the receiver. potentially dangerous because overriding existing receiver! oldReceiver = node.trace().getReceiver(); node.trace().setReceiver(this); } void add(ASTNode node, String attributeString, Runnable attributeCall) { System.out.println("** observer add " + node + " on " + attributeString); observedNodes.add(new RagConnectObserverEntry(node, attributeString, attributeCall)); } void remove(ASTNode node, String attributeString, Runnable attributeCall) { observedNodes.remove(new RagConnectObserverEntry(node, attributeString, attributeCall)); } @Override public void accept(ASTState.Trace.Event event, ASTNode node, String attribute, Object params, Object value) { oldReceiver.accept(event, node, attribute, params, value); // ignore all events but INC_FLUSH_ATTR if (event != ASTState.Trace.Event.INC_FLUSH_ATTR) { return; } System.out.println("** observer check INC_FLUSH_ATTR event"); // iterate through list, if matching pair. could maybe be more efficient. for (RagConnectObserverEntry entry : observedNodes) { if (entry.node.equals(node) && entry.attributeString.equals(attribute)) { // hit. call the attribute/nta-token System.out.println("** observer hit " + entry.node + " on " + entry.attributeString); entry.attributeCall.run(); } } } } private static RagConnectObserver ASTNode._ragConnectObserverInstance; RagConnectObserver ASTNode._ragConnectObserver() { if (_ragConnectObserverInstance == null) { // does not matter, which node is used to create the observer as ASTState/tracing is also static _ragConnectObserverInstance = new RagConnectObserver(this); } return _ragConnectObserverInstance; } }