private static void notifyListeners()

in modules/configuration/src/main/java/org/apache/ignite/internal/configuration/notifications/ConfigurationNotifier.java [100:343]


    private static void notifyListeners(
            @Nullable InnerNode oldInnerNode,
            InnerNode newInnerNode,
            DynamicConfiguration<InnerNode, ?> config,
            Iterable<DynamicConfiguration<InnerNode, ?>> anyConfigs,
            ConfigurationNotificationContext ctx
    ) {
        assert !(config instanceof NamedListConfiguration);

        if (oldInnerNode == null || newInnerNode == oldInnerNode) {
            return;
        }

        notifyPublicListeners(
                listeners(config, ctx.notificationNum),
                concat(mapIterable(anyConfigs, anyCfg -> listeners(anyCfg, ctx.notificationNum))),
                oldInnerNode.specificNode(),
                newInnerNode.specificNode(),
                ctx,
                ConfigurationListener::onUpdate
        );

        // Polymorphic configuration type has changed.
        // At the moment, we do not separate common fields from fields of a specific polymorphic configuration,
        // so this may cause errors in the logic below, perhaps we will fix it later.
        // TODO: https://issues.apache.org/jira/browse/IGNITE-15916
        if (oldInnerNode.schemaType() != newInnerNode.schemaType()) {
            return;
        }

        oldInnerNode.traverseChildren(new ConfigurationVisitor<Void>() {
            /** {@inheritDoc} */
            @Override
            public Void visitLeafNode(Field field, String key, Serializable oldLeaf) {
                Serializable newLeaf = newInnerNode.traverseChild(key, leafNodeVisitor(), true);

                if (newLeaf != oldLeaf) {
                    // TODO: Remove null check after https://issues.apache.org/jira/browse/IGNITE-21101
                    DynamicProperty<Serializable> node = config != null ? dynamicProperty(config, key) : null;
                    notifyPublicListeners(
                            listeners(node, ctx.notificationNum),
                            concat(mapIterable(anyConfigs, anyCfg -> listeners(dynamicProperty(anyCfg, key), ctx.notificationNum))),
                            oldLeaf,
                            newLeaf,
                            ctx,
                            ConfigurationListener::onUpdate
                    );
                }

                return null;
            }

            /** {@inheritDoc} */
            @Override
            public Void visitInnerNode(Field field, String key, InnerNode oldNode) {
                InnerNode newNode = newInnerNode.traverseChild(key, innerNodeVisitor(), true);

                DynamicConfiguration<InnerNode, ?> newConfig = dynamicConfig(config, key);

                ctx.addContainer(oldNode, newNode, null, null);

                notifyListeners(
                        oldNode,
                        newNode,
                        newConfig,
                        mapIterable(anyConfigs, anyCfg -> dynamicConfig(anyCfg, key)),
                        ctx
                );

                ctx.removeContainer();

                return null;
            }

            /** {@inheritDoc} */
            @Override
            public Void visitNamedListNode(Field field, String key, NamedListNode<?> oldNamedList) {
                NamedListNode<InnerNode> newNamedList =
                        (NamedListNode<InnerNode>) newInnerNode.traverseChild(key, namedListNodeVisitor(), true);

                if (newNamedList != oldNamedList) {
                    notifyPublicListeners(
                            listeners(namedDynamicConfig(config, key), ctx.notificationNum),
                            concat(mapIterable(anyConfigs, anyCfg -> listeners(namedDynamicConfig(anyCfg, key), ctx.notificationNum))),
                            oldNamedList,
                            newNamedList,
                            ctx,
                            ConfigurationListener::onUpdate
                    );

                    NamedListChanges namedListChanges = NamedListChanges.of(oldNamedList, newNamedList);

                    NamedListConfiguration<?, InnerNode, ?> namedListCfg = namedDynamicConfig(config, key);

                    Map<String, ConfigurationProperty<?>> namedListCfgMembers = namedListCfg.touchMembers();

                    // Lazy initialization.
                    Iterable<DynamicConfiguration<InnerNode, ?>> newAnyConfigs = null;

                    for (String name : namedListChanges.created) {
                        DynamicConfiguration<InnerNode, ?> newNodeCfg =
                                (DynamicConfiguration<InnerNode, ?>) namedListCfg.members().get(name);

                        touch(newNodeCfg);

                        InnerNode newVal = newNamedList.getInnerNode(name);

                        ctx.addContainer(null, newVal, null, name);

                        notifyPublicListeners(
                                extendedListeners(namedDynamicConfig(config, key), ctx.notificationNum),
                                concat(mapIterable(
                                        anyConfigs,
                                        anyCfg -> extendedListeners(namedDynamicConfig(anyCfg, key), ctx.notificationNum)
                                )),
                                null,
                                newVal.specificNode(),
                                ctx,
                                ConfigurationNamedListListener::onCreate
                        );

                        if (newAnyConfigs == null) {
                            newAnyConfigs = mergeAnyConfigs(
                                    mapIterable(anyConfigs, anyCfg -> any(namedDynamicConfig(anyCfg, key))),
                                    any(namedListCfg)
                            );
                        }

                        notifyListeners(
                                newVal,
                                newNodeCfg,
                                newAnyConfigs,
                                ctx
                        );

                        ctx.removeContainer();
                    }

                    for (String name : namedListChanges.deleted) {
                        DynamicConfiguration<InnerNode, ?> delNodeCfg =
                                (DynamicConfiguration<InnerNode, ?>) namedListCfgMembers.get(name);

                        InnerNode oldVal = oldNamedList.getInnerNode(name);

                        ctx.addContainer(oldVal, null, name, null);

                        notifyPublicListeners(
                                extendedListeners(namedDynamicConfig(config, key), ctx.notificationNum),
                                concat(mapIterable(
                                        anyConfigs,
                                        anyCfg -> extendedListeners(namedDynamicConfig(anyCfg, key), ctx.notificationNum)
                                )),
                                oldVal.specificNode(),
                                null,
                                ctx,
                                ConfigurationNamedListListener::onDelete
                        );

                        // Notification for deleted configuration.

                        notifyPublicListeners(
                                listeners(delNodeCfg, ctx.notificationNum),
                                concat(mapIterable(
                                        anyConfigs,
                                        anyCfg -> listeners(any(namedDynamicConfig(anyCfg, key)), ctx.notificationNum)
                                )),
                                oldVal.specificNode(),
                                null,
                                ctx,
                                ConfigurationListener::onUpdate
                        );

                        ctx.removeContainer();
                    }

                    for (Map.Entry<String, String> entry : namedListChanges.renamed.entrySet()) {
                        InnerNode oldVal = oldNamedList.getInnerNode(entry.getKey());
                        InnerNode newVal = newNamedList.getInnerNode(entry.getValue());

                        ctx.addContainer(oldVal, newVal, entry.getKey(), entry.getValue());

                        notifyPublicListeners(
                                extendedListeners(namedDynamicConfig(config, key), ctx.notificationNum),
                                concat(mapIterable(
                                        anyConfigs,
                                        anyCfg -> extendedListeners(namedDynamicConfig(anyCfg, key), ctx.notificationNum)
                                )),
                                oldVal.specificNode(),
                                newVal.specificNode(),
                                ctx,
                                (listener, event) -> listener.onRename(event)
                        );

                        ctx.removeContainer();
                    }

                    for (String name : namedListChanges.updated) {
                        InnerNode oldVal = oldNamedList.getInnerNode(name);
                        InnerNode newVal = newNamedList.getInnerNode(name);

                        if (oldVal == newVal) {
                            continue;
                        }

                        DynamicConfiguration<InnerNode, ?> updNodeCfg =
                                (DynamicConfiguration<InnerNode, ?>) namedListCfgMembers.get(name);

                        ctx.addContainer(oldVal, newVal, name, name);

                        notifyPublicListeners(
                                extendedListeners(namedDynamicConfig(config, key), ctx.notificationNum),
                                concat(mapIterable(
                                        anyConfigs,
                                        anyCfg -> extendedListeners(namedDynamicConfig(anyCfg, key), ctx.notificationNum)
                                )),
                                oldVal.specificNode(),
                                newVal.specificNode(),
                                ctx,
                                ConfigurationNamedListListener::onUpdate
                        );

                        if (newAnyConfigs == null) {
                            newAnyConfigs = mergeAnyConfigs(
                                    mapIterable(anyConfigs, anyCfg -> any(namedDynamicConfig(anyCfg, key))),
                                    any(namedListCfg)
                            );
                        }

                        notifyListeners(
                                oldVal,
                                newVal,
                                updNodeCfg,
                                newAnyConfigs,
                                ctx
                        );

                        ctx.removeContainer();
                    }
                }

                return null;
            }
        }, true);
    }