<commit_before>/*
 * Copyright 2017 The Hekate Project
 *
 * The Hekate Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package io.hekate.spring.bean.internal;

import io.hekate.cluster.ClusterServiceFactory;
import io.hekate.cluster.health.DefaultFailureDetector;
import io.hekate.cluster.health.DefaultFailureDetectorConfig;
import io.hekate.cluster.seed.StaticSeedNodeProvider;
import io.hekate.cluster.seed.StaticSeedNodeProviderConfig;
import io.hekate.cluster.seed.fs.FsSeedNodeProvider;
import io.hekate.cluster.seed.fs.FsSeedNodeProviderConfig;
import io.hekate.cluster.seed.jclouds.BasicCredentialsSupplier;
import io.hekate.cluster.seed.jclouds.CloudSeedNodeProvider;
import io.hekate.cluster.seed.jclouds.CloudSeedNodeProviderConfig;
import io.hekate.cluster.seed.jclouds.CloudStoreSeedNodeProvider;
import io.hekate.cluster.seed.jclouds.CloudStoreSeedNodeProviderConfig;
import io.hekate.cluster.seed.jclouds.aws.AwsCredentialsSupplier;
import io.hekate.cluster.seed.jdbc.JdbcSeedNodeProvider;
import io.hekate.cluster.seed.jdbc.JdbcSeedNodeProviderConfig;
import io.hekate.cluster.seed.multicast.MulticastSeedNodeProvider;
import io.hekate.cluster.seed.multicast.MulticastSeedNodeProviderConfig;
import io.hekate.cluster.split.AddressReachabilityDetector;
import io.hekate.cluster.split.HostReachabilityDetector;
import io.hekate.cluster.split.SplitBrainDetectorGroup;
import io.hekate.coordinate.CoordinationProcessConfig;
import io.hekate.coordinate.CoordinationServiceFactory;
import io.hekate.election.CandidateConfig;
import io.hekate.election.ElectionServiceFactory;
import io.hekate.lock.LockRegionConfig;
import io.hekate.lock.LockServiceFactory;
import io.hekate.messaging.MessagingBackPressureConfig;
import io.hekate.messaging.MessagingChannelConfig;
import io.hekate.messaging.MessagingServiceFactory;
import io.hekate.metrics.cluster.ClusterMetricsServiceFactory;
import io.hekate.metrics.local.CounterConfig;
import io.hekate.metrics.local.LocalMetricsServiceFactory;
import io.hekate.metrics.local.ProbeConfig;
import io.hekate.network.NetworkConnectorConfig;
import io.hekate.network.NetworkServiceFactory;
import io.hekate.rpc.RpcClientConfig;
import io.hekate.rpc.RpcServerConfig;
import io.hekate.rpc.RpcServiceFactory;
import io.hekate.spring.bean.HekateSpringBootstrap;
import io.hekate.spring.bean.cluster.ClusterServiceBean;
import io.hekate.spring.bean.codec.CodecServiceBean;
import io.hekate.spring.bean.coordinate.CoordinationServiceBean;
import io.hekate.spring.bean.election.ElectionServiceBean;
import io.hekate.spring.bean.lock.LockBean;
import io.hekate.spring.bean.lock.LockRegionBean;
import io.hekate.spring.bean.lock.LockServiceBean;
import io.hekate.spring.bean.messaging.MessagingChannelBean;
import io.hekate.spring.bean.messaging.MessagingServiceBean;
import io.hekate.spring.bean.metrics.ClusterMetricsServiceBean;
import io.hekate.spring.bean.metrics.CounterMetricBean;
import io.hekate.spring.bean.metrics.LocalMetricsServiceBean;
import io.hekate.spring.bean.metrics.MetricBean;
import io.hekate.spring.bean.network.NetworkConnectorBean;
import io.hekate.spring.bean.network.NetworkServiceBean;
import io.hekate.spring.bean.rpc.RpcClientBean;
import io.hekate.spring.bean.rpc.RpcServiceBean;
import io.hekate.spring.bean.task.TaskServiceBean;
import io.hekate.task.TaskServiceFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.ManagedSet;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;

import static java.util.stream.Collectors.toSet;
import static org.springframework.util.xml.DomUtils.getChildElementByTagName;
import static org.springframework.util.xml.DomUtils.getChildElementsByTagName;
import static org.springframework.util.xml.DomUtils.getTextValue;

public class HekateBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
    private final Map<BeanDefinitionBuilder, String> deferredBaseBeans = new HashMap<>();

    @Override
    protected Class<?> getBeanClass(Element element) {
        return HekateSpringBootstrap.class;
    }

    @Override
    protected boolean shouldGenerateId() {
        return false;
    }

    @Override
    protected boolean shouldGenerateIdAsFallback() {
        return true;
    }

    @Override
    protected String resolveId(Element el, AbstractBeanDefinition def, ParserContext ctx) {
        String id = super.resolveId(el, def, ctx);

        deferredBaseBeans.forEach((baseBeanBuilder, baseBeanName) -> {
            baseBeanBuilder.addPropertyValue("source", new RuntimeBeanReference(id));

            AbstractBeanDefinition baseBean = baseBeanBuilder.getBeanDefinition();

            if (baseBeanName == null) {
                ctx.getRegistry().registerBeanDefinition(ctx.getReaderContext().generateBeanName(baseBean), baseBean);
            } else {
                ctx.getRegistry().registerBeanDefinition(baseBeanName, baseBean);
            }
        });

        return id;
    }

    @Override
    protected void doParse(Element rootEl, ParserContext ctx, BeanDefinitionBuilder boot) {
        setProperty(boot, rootEl, "name", "nodeName");
        setProperty(boot, rootEl, "cluster", "clusterName");

        parseNodeRoles(boot, rootEl);

        parseProperties(rootEl).ifPresent(props ->
            boot.addPropertyValue("properties", props)
        );

        parseNodePropertyProviders(boot, rootEl, ctx);

        parseDefaultCodec(boot, rootEl, ctx);

        ManagedList<RuntimeBeanReference> services = new ManagedList<>();

        parseClusterService(rootEl, ctx).ifPresent(services::add);
        parseNetworkService(rootEl, ctx).ifPresent(services::add);
        parseMessagingService(rootEl, ctx).ifPresent(services::add);
        parseRpcService(rootEl, ctx).ifPresent(services::add);
        parseTaskService(rootEl, ctx).ifPresent(services::add);
        parseLockService(rootEl, ctx).ifPresent(services::add);
        parseCoordinationService(rootEl, ctx).ifPresent(services::add);
        parseElectionService(rootEl, ctx).ifPresent(services::add);
        parseLocalMetricsService(rootEl, ctx).ifPresent(services::add);
        parseClusterMetricsService(rootEl, ctx).ifPresent(services::add);

        subElements(rootEl, "custom-services", "service").forEach(serviceEl ->
            parseRefOrBean(serviceEl, ctx).ifPresent(services::add)
        );

        if (!services.isEmpty()) {
            boot.addPropertyValue("services", services);<commit_msg>Fixed issue with cluster and node names not being set by Spring XSD parser.<commit_after>/*
 * Copyright 2017 The Hekate Project
 *
 * The Hekate Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package io.hekate.spring.bean.internal;

import io.hekate.cluster.ClusterServiceFactory;
import io.hekate.cluster.health.DefaultFailureDetector;
import io.hekate.cluster.health.DefaultFailureDetectorConfig;
import io.hekate.cluster.seed.StaticSeedNodeProvider;
import io.hekate.cluster.seed.StaticSeedNodeProviderConfig;
import io.hekate.cluster.seed.fs.FsSeedNodeProvider;
import io.hekate.cluster.seed.fs.FsSeedNodeProviderConfig;
import io.hekate.cluster.seed.jclouds.BasicCredentialsSupplier;
import io.hekate.cluster.seed.jclouds.CloudSeedNodeProvider;
import io.hekate.cluster.seed.jclouds.CloudSeedNodeProviderConfig;
import io.hekate.cluster.seed.jclouds.CloudStoreSeedNodeProvider;
import io.hekate.cluster.seed.jclouds.CloudStoreSeedNodeProviderConfig;
import io.hekate.cluster.seed.jclouds.aws.AwsCredentialsSupplier;
import io.hekate.cluster.seed.jdbc.JdbcSeedNodeProvider;
import io.hekate.cluster.seed.jdbc.JdbcSeedNodeProviderConfig;
import io.hekate.cluster.seed.multicast.MulticastSeedNodeProvider;
import io.hekate.cluster.seed.multicast.MulticastSeedNodeProviderConfig;
import io.hekate.cluster.split.AddressReachabilityDetector;
import io.hekate.cluster.split.HostReachabilityDetector;
import io.hekate.cluster.split.SplitBrainDetectorGroup;
import io.hekate.coordinate.CoordinationProcessConfig;
import io.hekate.coordinate.CoordinationServiceFactory;
import io.hekate.election.CandidateConfig;
import io.hekate.election.ElectionServiceFactory;
import io.hekate.lock.LockRegionConfig;
import io.hekate.lock.LockServiceFactory;
import io.hekate.messaging.MessagingBackPressureConfig;
import io.hekate.messaging.MessagingChannelConfig;
import io.hekate.messaging.MessagingServiceFactory;
import io.hekate.metrics.cluster.ClusterMetricsServiceFactory;
import io.hekate.metrics.local.CounterConfig;
import io.hekate.metrics.local.LocalMetricsServiceFactory;
import io.hekate.metrics.local.ProbeConfig;
import io.hekate.network.NetworkConnectorConfig;
import io.hekate.network.NetworkServiceFactory;
import io.hekate.rpc.RpcClientConfig;
import io.hekate.rpc.RpcServerConfig;
import io.hekate.rpc.RpcServiceFactory;
import io.hekate.spring.bean.HekateSpringBootstrap;
import io.hekate.spring.bean.cluster.ClusterServiceBean;
import io.hekate.spring.bean.codec.CodecServiceBean;
import io.hekate.spring.bean.coordinate.CoordinationServiceBean;
import io.hekate.spring.bean.election.ElectionServiceBean;
import io.hekate.spring.bean.lock.LockBean;
import io.hekate.spring.bean.lock.LockRegionBean;
import io.hekate.spring.bean.lock.LockServiceBean;
import io.hekate.spring.bean.messaging.MessagingChannelBean;
import io.hekate.spring.bean.messaging.MessagingServiceBean;
import io.hekate.spring.bean.metrics.ClusterMetricsServiceBean;
import io.hekate.spring.bean.metrics.CounterMetricBean;
import io.hekate.spring.bean.metrics.LocalMetricsServiceBean;
import io.hekate.spring.bean.metrics.MetricBean;
import io.hekate.spring.bean.network.NetworkConnectorBean;
import io.hekate.spring.bean.network.NetworkServiceBean;
import io.hekate.spring.bean.rpc.RpcClientBean;
import io.hekate.spring.bean.rpc.RpcServiceBean;
import io.hekate.spring.bean.task.TaskServiceBean;
import io.hekate.task.TaskServiceFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.ManagedSet;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;

import static java.util.stream.Collectors.toSet;
import static org.springframework.util.xml.DomUtils.getChildElementByTagName;
import static org.springframework.util.xml.DomUtils.getChildElementsByTagName;
import static org.springframework.util.xml.DomUtils.getTextValue;

public class HekateBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
    private final Map<BeanDefinitionBuilder, String> deferredBaseBeans = new HashMap<>();

    @Override
    protected Class<?> getBeanClass(Element element) {
        return HekateSpringBootstrap.class;
    }

    @Override
    protected boolean shouldGenerateId() {
        return false;
    }

    @Override
    protected boolean shouldGenerateIdAsFallback() {
        return true;
    }

    @Override
    protected String resolveId(Element el, AbstractBeanDefinition def, ParserContext ctx) {
        String id = super.resolveId(el, def, ctx);

        deferredBaseBeans.forEach((baseBeanBuilder, baseBeanName) -> {
            baseBeanBuilder.addPropertyValue("source", new RuntimeBeanReference(id));

            AbstractBeanDefinition baseBean = baseBeanBuilder.getBeanDefinition();

            if (baseBeanName == null) {
                ctx.getRegistry().registerBeanDefinition(ctx.getReaderContext().generateBeanName(baseBean), baseBean);
            } else {
                ctx.getRegistry().registerBeanDefinition(baseBeanName, baseBean);
            }
        });

        return id;
    }

    @Override
    protected void doParse(Element rootEl, ParserContext ctx, BeanDefinitionBuilder boot) {
        setProperty(boot, rootEl, "nodeName", "name");
        setProperty(boot, rootEl, "clusterName", "cluster");

        parseNodeRoles(boot, rootEl);

        parseProperties(rootEl).ifPresent(props ->
            boot.addPropertyValue("properties", props)
        );

        parseNodePropertyProviders(boot, rootEl, ctx);

        parseDefaultCodec(boot, rootEl, ctx);

        ManagedList<RuntimeBeanReference> services = new ManagedList<>();

        parseClusterService(rootEl, ctx).ifPresent(services::add);
        parseNetworkService(rootEl, ctx).ifPresent(services::add);
        parseMessagingService(rootEl, ctx).ifPresent(services::add);
        parseRpcService(rootEl, ctx).ifPresent(services::add);
        parseTaskService(rootEl, ctx).ifPresent(services::add);
        parseLockService(rootEl, ctx).ifPresent(services::add);
        parseCoordinationService(rootEl, ctx).ifPresent(services::add);
        parseElectionService(rootEl, ctx).ifPresent(services::add);
        parseLocalMetricsService(rootEl, ctx).ifPresent(services::add);
        parseClusterMetricsService(rootEl, ctx).ifPresent(services::add);

        subElements(rootEl, "custom-services", "service").forEach(serviceEl ->
            parseRefOrBean(serviceEl, ctx).ifPresent(services::add)
        );

        if (!services.isEmpty()) {
            boot.addPropertyValue("services", services);
{'fraction_non_alphanumeric': 0.09723820483314154, 'fraction_numerical': 0.0011507479861910242, 'mean_word_length': 5.185448793989719, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 12}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3755718', 'n_tokens_mistral': 4557, 'n_tokens_neox': 4482, 'n_words': 778}