# Implementation Details: Trigger Detection with JDT ## 1. Finding `sendEvent` Calls We can use an `ASTVisitor` to find all `MethodInvocation` nodes. ```java public class SendEventVisitor extends ASTVisitor { @Override public boolean visit(MethodInvocation node) { if ("sendEvent".equals(node.getName().getIdentifier())) { // Found a call! // 1. Extract event (first argument) // 2. Identify the enclosing method and class } return super.visit(node); } } ``` ### Challenges in Event Extraction Events can be: - Enum constants: `Events.SUBMIT` - Strings: `"SUBMIT"` - Variables: `sm.sendEvent(eventFromPayload)` (Hard to resolve statically) We should reuse `CodebaseContext.resolveState` logic (which is basically resolving an expression to a value/fqn). ## 2. Identifying Enclosing Context Once a `sendEvent` is found, we can traverse up the AST to find the `MethodDeclaration` and `TypeDeclaration`. ```java ASTNode parent = node.getParent(); while (parent != null && !(parent instanceof MethodDeclaration)) { parent = parent.getParent(); } // parent is now the MethodDeclaration ``` ### 2. Extracting Annotations From `MethodDeclaration`, we can check for mappings: - `@PostMapping`, `@GetMapping`, etc. - `@KafkaListener`: Extract `topics`, `groupId`. - `@RabbitListener`: Extract `queues`, `bindings` (Exchange/RoutingKey). From `TypeDeclaration`, we can check for: - `@RestController`, `@Controller` - `@RequestMapping` at class level (to get base path) ## 3. Specialized WebFlux Analysis ### Annotation-based WebFlux This is largely identical to Spring MVC. The challenge is if the `sendEvent` is wrapped in a reactive operator. ```java public Mono submit(Order order) { return service.save(order) .doOnNext(o -> stateMachine.sendEvent(Events.SUBMIT)) .then(); } ``` **Static Strategy**: We need to look inside `LambdaExpression` nodes passed to reactive operators (`doOnNext`, `flatMap`, `map`, `subscribe`). The `ASTVisitor` should traverse into these lambdas. ### Functional WebFlux (RouterFunctions) Functional endpoints are often defined as Beans returning `RouterFunction`. ```java @Bean public RouterFunction route(OrderHandler handler) { return RouterFunctions.route(POST("/orders"), handler::submitOrder); } ``` **Static Strategy**: 1. Find methods returning `RouterFunction`. 2. Analyze the `MethodInvocation` chain (`route`, `andRoute`, `nest`). 3. Extract the URI pattern and the `HandlerFunction` reference. 4. If the handler is a method reference (`handler::submitOrder`), link it to the corresponding `MethodDeclaration`. ## 4. Specialized RabbitMQ Analysis `@RabbitListener` can be complex: ```java @RabbitListener(bindings = @QueueBinding( value = @Queue(value = "orderQueue", durable = "true"), exchange = @Exchange(value = "orderExchange"), key = "order.created" )) public void onOrder(Order order) { ... } ``` **Static Strategy**: 1. Find `@RabbitListener`. 2. If it has `bindings`, drill down into `@QueueBinding`, `@Queue`, `@Exchange` to extract the topology. 3. If it only has `queues`, resolve the queue name (might be a SpEL expression or property placeholder, which we can try to resolve or just keep as-is). ## 5. Indirect Flow Detection (The "Service Link") If the project has multiple state machines, we need to know which one is being targeted. Usually, this is done via: - Autowiring by type: `StateMachine sm;` - Autowiring by name: `@Qualifier("mySm") StateMachine sm;` We can look at the fields of the class where `sendEvent` is called. ## 6. Output Enhancement The `Exporter` should be modified to: - In DOT: Add nodes for Endpoints/Listeners and link them to the Events/Transitions. - In SCXML: Add metadata to transitions.