001/**
002 * Copyright (C) 2006-2025 Talend Inc. - www.talend.com
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.talend.sdk.component.runtime.manager.service.api;
017
018import java.util.Map;
019import java.util.Objects;
020import java.util.Optional;
021import java.util.function.Supplier;
022import java.util.stream.Stream;
023
024import org.talend.sdk.component.runtime.base.Lifecycle;
025import org.talend.sdk.component.runtime.manager.ComponentFamilyMeta;
026import org.talend.sdk.component.runtime.manager.ComponentManager.ComponentType;
027import org.talend.sdk.component.runtime.manager.ContainerComponentRegistry;
028
029import lombok.RequiredArgsConstructor;
030import lombok.extern.slf4j.Slf4j;
031
032@FunctionalInterface
033public interface ComponentInstantiator {
034
035    Lifecycle instantiate(final Map<String, String> configuration, final int configVersion);
036
037    interface MetaFinder {
038
039        Optional<? extends ComponentFamilyMeta.BaseMeta>
040                filter(final Map<String, ? extends ComponentFamilyMeta.BaseMeta> source);
041
042        static MetaFinder ofComponent(final String name) {
043            return new ComponentNameFinder(name);
044        }
045    }
046
047    @FunctionalInterface
048    interface Builder {
049
050        ComponentInstantiator build(final String familyName, final MetaFinder finder,
051                final ComponentType componentType);
052    }
053
054    @Slf4j
055    @RequiredArgsConstructor
056    class BuilderDefault implements Builder {
057
058        private final Supplier<Stream<ContainerComponentRegistry>> registrySupplier;
059
060        @Override
061        public ComponentInstantiator build(final String familyName, final MetaFinder finder,
062                final ComponentType componentType) {
063            final Stream<ContainerComponentRegistry> registries = this.registrySupplier.get();
064            if (registries == null) {
065                return null;
066            }
067            final String sanitizedFamilyName = Optional.ofNullable(familyName).map(String::trim).orElse("");
068            return registries
069                    .map((ContainerComponentRegistry registry) -> registry.findComponentFamily(sanitizedFamilyName))
070                    .filter(Objects::nonNull)
071                    .peek((ComponentFamilyMeta cm) -> log.debug("Family found {} plugin {}", sanitizedFamilyName,
072                            cm.getPlugin()))
073                    .map(componentType::findMeta)
074                    .map((Map<String, ? extends ComponentFamilyMeta.BaseMeta> map) -> finder.filter(map))
075                    .filter(Optional::isPresent)
076                    .map(Optional::get)
077                    .findFirst()
078                    .map((ComponentFamilyMeta.BaseMeta c) -> (ComponentInstantiator) c::instantiate)
079                    .orElse(null);
080        }
081    }
082
083    @Slf4j
084    class ComponentNameFinder implements MetaFinder {
085
086        private final String componentName;
087
088        public ComponentNameFinder(final String componentName) {
089            this.componentName = Optional.ofNullable(componentName).map(String::trim).orElse("");
090        }
091
092        @Override
093        public Optional<? extends ComponentFamilyMeta.BaseMeta>
094                filter(final Map<String, ? extends ComponentFamilyMeta.BaseMeta> source) {
095            if (!source.containsKey(this.componentName)) {
096                log.debug("Can't find component name {}", this.componentName);
097            }
098            return Optional.ofNullable(source.get(this.componentName));
099        }
100    }
101}