All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.yahoo.vespa.model.builder.xml.dom.chains.ComponentsBuilder Maven / Gradle / Ivy

There is a newer version: 8.409.18
Show newest version
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.builder.xml.dom.chains;

import com.yahoo.component.ComponentId;
import com.yahoo.component.ComponentSpecification;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.text.XML;
import com.yahoo.config.model.producer.AnyConfigProducer;
import com.yahoo.config.model.producer.TreeConfigProducer;
import com.yahoo.config.model.builder.xml.XmlHelper;
import com.yahoo.vespa.model.builder.xml.dom.VespaDomBuilder;
import com.yahoo.vespa.model.builder.xml.dom.chains.docproc.DomDocumentProcessorBuilder;
import com.yahoo.vespa.model.container.http.xml.FilterBuilder;
import com.yahoo.vespa.model.builder.xml.dom.chains.processing.DomProcessorBuilder;
import com.yahoo.vespa.model.builder.xml.dom.chains.search.DomFederationSearcherBuilder;
import com.yahoo.vespa.model.builder.xml.dom.chains.search.DomSearcherBuilder;
import com.yahoo.vespa.model.container.component.chain.ChainedComponent;
import com.yahoo.vespa.model.container.http.Filter;
import com.yahoo.vespa.model.container.processing.Processor;
import com.yahoo.vespa.model.container.docproc.DocumentProcessor;
import com.yahoo.vespa.model.container.search.searchchain.Searcher;
import org.w3c.dom.Element;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
 * Creates component models and component references from xml for a given scope.
 * @author Tony Vaagenes
 */
public class ComponentsBuilder> {

    // NOTE: the 'name' string must match the xml tag name for the component in services.
    public static class ComponentType> {
        static List> values = new ArrayList<>();
        public static final ComponentType documentprocessor = new ComponentType<>("documentprocessor", DomDocumentProcessorBuilder.class);
        public static final ComponentType> searcher = new ComponentType<>("searcher", DomSearcherBuilder.class);
        public static final ComponentType processor = new ComponentType<>("processor", DomProcessorBuilder.class);
        public static final ComponentType> federation = new ComponentType<>("federation", DomFederationSearcherBuilder.class);
        public static final ComponentType filter = new ComponentType<>("filter", FilterBuilder.class);


        final String name;

        private final Class > builderClass;

        private ComponentType(String name, Class > builderClass) {
            this.name = name;
            this.builderClass = builderClass;
            values.add(this);
        }

        public VespaDomBuilder.DomConfigProducerBuilderBase createBuilder() {
            return DomBuilderCreator.create(builderClass);
        }
    }

    private final Set outerComponentReferences = new LinkedHashSet<>();
    private final List componentDefinitions = new ArrayList<>();
    private final Map> componentTypesByComponentName = new LinkedHashMap<>();

    /**
     * @param ancestor The parent config producer
     * @param componentTypes The allowed component types for 'elementContainingComponentElements' - MUST match <T>
     * @param elementsContainingComponentElems All elements containing elements with name matching ComponentType.name
     * @param outerComponentTypeByComponentName Use null if this is the outermost scope, i.e.
     *                                          every component is a definition, not a reference.
     */
    ComponentsBuilder(DeployState deployState,
                      TreeConfigProducer ancestor,
                      Collection> componentTypes,
                      List elementsContainingComponentElems,
                      Map> outerComponentTypeByComponentName) {

        readComponents(deployState, ancestor, componentTypes, elementsContainingComponentElems, unmodifiable(outerComponentTypeByComponentName));
    }

    private void readComponents(DeployState deployState,
                                TreeConfigProducer ancestor,
                                Collection> componentTypes,
                                List elementsContainingComponentElems,
                                Map> outerComponentTypeByComponentName) {

        for (ComponentType componentType : componentTypes) {
            for (Element elemContainingComponentElems : elementsContainingComponentElems) {
                for (Element componentElement : XML.getChildren(elemContainingComponentElems, componentType.name)) {
                    readComponent(deployState, ancestor, componentElement, componentType, outerComponentTypeByComponentName);
                }
            }
        }
    }

    private void readComponent(DeployState deployState, TreeConfigProducer ancestor,
                               Element componentElement,
                               ComponentType componentType,
                               Map> outerComponentTypeByComponentName) {

        ComponentSpecification componentSpecification = XmlHelper.getIdRef(componentElement);

        if (outerComponentTypeByComponentName.containsKey(componentSpecification.getName())) {
            readComponentReference(componentElement, componentType, componentSpecification, outerComponentTypeByComponentName);
        } else {
            readComponentDefinition(deployState, ancestor, componentElement, componentType);
        }
    }

    private void readComponentReference(Element componentElement, ComponentType componentType,
                                        ComponentSpecification componentSpecification,
                                        Map> outerComponentTypeByComponentName) {

        String componentName = componentSpecification.getName();
        ensureTypesMatch(componentType, outerComponentTypeByComponentName.get(componentName), componentName);
        ensureNotDefinition(componentName, componentElement);
        outerComponentReferences.add(componentSpecification);
    }

    private void readComponentDefinition(DeployState deployState, TreeConfigProducer ancestor, Element componentElement, ComponentType componentType) {
        T component = componentType.createBuilder().build(deployState, ancestor, componentElement);
        componentDefinitions.add(component);
        updateComponentTypes(component.getComponentId(), componentType);
    }

    private void updateComponentTypes(ComponentId componentId, ComponentType componentType) {
        ComponentType oldType = componentTypesByComponentName.put(componentId.getName(), componentType);
        if (oldType != null) {
            ensureTypesMatch(componentType, oldType, componentId.getName());
        }
    }

    private void ensureNotDefinition(String componentName, Element componentSpec) {
        if (componentSpec.getAttributes().getLength() > 1 || !XML.getChildren(componentSpec).isEmpty())
            throw new IllegalArgumentException("Expecting " + componentName +
                                               " to be a reference to a global component with the same name," +
                                               " so no additional attributes or nested elements are allowed");
    }

    private void ensureTypesMatch(ComponentType type1, ComponentType type2, String componentName) {
        if (!type1.equals(type2)) {
            throw new IllegalArgumentException("Two different types declared for the component with name '" + componentName +
                                               "' (" + type1.name + " != " + type2.name + ").");
        }
    }

    private Map> unmodifiable(Map> outerComponentTypeByComponentName) {
        return (outerComponentTypeByComponentName != null)?
                Collections.unmodifiableMap(outerComponentTypeByComponentName):
                Map.of();
    }

    public Collection getComponentDefinitions() {
        return Collections.unmodifiableCollection(componentDefinitions);
    }

    public Map> getComponentTypeByComponentName() {
        return Collections.unmodifiableMap(componentTypesByComponentName);
    }

    public Set getOuterComponentReferences() {
        return Collections.unmodifiableSet(outerComponentReferences);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy