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.tools.validator;
017
018import static java.util.function.Function.identity;
019import static java.util.stream.Collectors.groupingBy;
020import static java.util.stream.Collectors.joining;
021import static java.util.stream.Collectors.toList;
022import static java.util.stream.Collectors.toMap;
023
024import java.util.ArrayList;
025import java.util.HashSet;
026import java.util.List;
027import java.util.Map;
028import java.util.Objects;
029import java.util.Set;
030import java.util.stream.Collectors;
031import java.util.stream.Stream;
032
033import org.apache.xbean.finder.AnnotationFinder;
034import org.talend.sdk.component.api.configuration.action.Checkable;
035import org.talend.sdk.component.api.configuration.type.DataStore;
036import org.talend.sdk.component.api.service.Service;
037import org.talend.sdk.component.api.service.healthcheck.HealthCheck;
038import org.talend.sdk.component.tools.validator.Validators.ValidatorHelper;
039
040public class DataStoreValidator implements Validator {
041
042    private final Validators.ValidatorHelper helper;
043
044    public DataStoreValidator(final ValidatorHelper helper) {
045        this.helper = helper;
046    }
047
048    @Override
049    public Stream<String> validate(final AnnotationFinder finder, final List<Class<?>> components) {
050        List<String> errors = new ArrayList<>();
051        final List<Class<?>> datastoreClasses = finder.findAnnotatedClasses(DataStore.class);
052
053        final List<String> datastores =
054                datastoreClasses.stream().map(d -> d.getAnnotation(DataStore.class).value()).collect(toList());
055
056        Set<String> uniqueDatastores = new HashSet<>(datastores);
057        if (datastores.size() != uniqueDatastores.size()) {
058            errors
059                    .add("Duplicated DataStore found : " + datastores
060                            .stream()
061                            .collect(groupingBy(identity()))
062                            .entrySet()
063                            .stream()
064                            .filter(e -> e.getValue().size() > 1)
065                            .map(Map.Entry::getKey)
066                            .collect(joining(", ")));
067        }
068
069        final List<Class<?>> checkableClasses = finder.findAnnotatedClasses(Checkable.class);
070        errors
071                .addAll(checkableClasses
072                        .stream()
073                        .filter(d -> !d.isAnnotationPresent(DataStore.class))
074                        .map(c -> c.getName() + " has @Checkable but is not a @DataStore")
075                        .sorted()
076                        .collect(Collectors.toList()));
077
078        final Map<String, String> checkableDataStoresMap = checkableClasses
079                .stream()
080                .filter(d -> d.isAnnotationPresent(DataStore.class))
081                .collect(toMap(d -> d.getAnnotation(DataStore.class).value(),
082                        d -> d.getAnnotation(Checkable.class).value()));
083
084        final Set<String> healthchecks = finder
085                .findAnnotatedMethods(HealthCheck.class)
086                .stream()
087                .filter(h -> h.getDeclaringClass().isAnnotationPresent(Service.class))
088                .map(m -> m.getAnnotation(HealthCheck.class).value())
089                .collect(Collectors.toSet());
090        errors
091                .addAll(checkableDataStoresMap
092                        .entrySet()
093                        .stream()
094                        .filter(e -> !healthchecks.contains(e.getValue()))
095                        .map(e -> "No @HealthCheck for dataStore: '" + e.getKey() + "' with checkable: '" + e.getValue()
096                                + "'")
097                        .sorted()
098                        .collect(Collectors.toList()));
099
100        errors
101                .addAll(datastoreClasses
102                        .stream()
103                        .map(clazz -> this.helper
104                                .validateFamilyI18nKey(clazz,
105                                        "${family}.datastore." + clazz.getAnnotation(DataStore.class).value()
106                                                + "._displayName"))
107                        .filter(Objects::nonNull)
108                        .collect(toList()));
109
110        return errors.stream();
111
112    }
113}