@ReadOperation
    @Operation(summary = "Get Spring webflow report using an optional flow id",
        parameters = {@Parameter(name = "flowId", description = "The webflow id"), @Parameter(name = "stateId", description = "The state id")})
    public Map<?, ?> getReport(@Nullable final String flowId, @Nullable final String stateId) {
        val jsonMap = new LinkedHashMap<String, Object>();

        val executionPlan = applicationContext.getBean(CasWebflowExecutionPlan.BEAN_NAME, CasWebflowExecutionPlan.class);
        executionPlan.execute();
        
        val map = applicationContext.getBeansOfType(FlowDefinitionRegistry.class);
        map.forEach((key, value) -> Arrays.stream(value.getFlowDefinitionIds())
            .filter(currentId -> StringUtils.isBlank(flowId) || flowId.equalsIgnoreCase(currentId))
            .forEach(id -> {
                val flowDefinition = (Flow) value.getFlowDefinition(id);

                val flowDetails = new LinkedHashMap<String, Object>();
                flowDetails.put("startState", flowDefinition.getStartState().getId());

                val startActions = StreamSupport.stream(flowDefinition.getStartActionList().spliterator(), false)
                    .map(SpringWebflowEndpoint::convertActionToString)
                    .collect(Collectors.toList());
                if (!startActions.isEmpty()) {
                    flowDetails.put("startActions", startActions);
                }

                val states = new LinkedHashMap<String, Map>();
                Arrays.stream(flowDefinition.getStateIds())
                    .filter(st -> StringUtils.isBlank(stateId) || RegexUtils.find(stateId, st))
                    .forEach(st -> {
                        val stateMap = getStateDetails(flowDefinition, st);
                        states.put(st, stateMap);
                    });

                flowDetails.put("states", states);
                flowDetails.put("possibleOutcomes", flowDefinition.getPossibleOutcomes());
                flowDetails.put("stateCount", flowDefinition.getStateCount());

                var acts = StreamSupport.stream(flowDefinition.getEndActionList().spliterator(), false)
                    .map(SpringWebflowEndpoint::convertActionToString)
                    .collect(Collectors.toList());
                if (!acts.isEmpty()) {
                    flowDetails.put("endActions", acts);
                }

                acts = StreamSupport.stream(flowDefinition.getGlobalTransitionSet().spliterator(), false)
                    .map(tr -> tr.getId() + " -> " + tr.getTargetStateId() + " @ " + tr.getExecutionCriteria().toString())
                    .collect(Collectors.toList());
                if (!acts.isEmpty()) {
                    flowDetails.put("globalTransitions", acts);
                }

                acts = Arrays.stream(flowDefinition.getExceptionHandlerSet().toArray())
                    .map(Object::toString)
                    .collect(Collectors.toList());
                if (!acts.isEmpty()) {
                    flowDetails.put("exceptionHandlers", acts);
                }

                val vars = Arrays.stream(flowDefinition.getVariables())
                    .map(FlowVariable::getName)
                    .collect(Collectors.joining(","));

                if (StringUtils.isNotBlank(vars)) {
                    flowDetails.put("variables", vars);
                }

                jsonMap.put(id, flowDetails);
            }));

        return jsonMap;
    }
Get SWF report.

@param flowId  the flow id
@param stateId the state id
@return JSON representing the current state of SWF.
support/cas-server-support-reports-core/src/main/java/org/apereo/cas/web/report/SpringWebflowEndpoint.java