001/** 002 * Copyright (C) 2006-2024 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.Collections.emptyList; 019import static java.util.Optional.ofNullable; 020import static java.util.function.Function.identity; 021import static java.util.stream.Collectors.toMap; 022 023import java.util.List; 024import java.util.Map; 025import java.util.Objects; 026import java.util.stream.Stream; 027 028import org.apache.xbean.finder.AnnotationFinder; 029import org.talend.sdk.component.api.configuration.type.DatasetDiscovery; 030import org.talend.sdk.component.api.configuration.type.DatasetDiscoveryConfiguration; 031import org.talend.sdk.component.runtime.manager.ParameterMeta; 032import org.talend.sdk.component.runtime.manager.reflect.ParameterModelService; 033import org.talend.sdk.component.runtime.manager.reflect.parameterenricher.BaseParameterEnricher; 034import org.talend.sdk.component.runtime.manager.service.LocalConfigurationService; 035 036public class DatasetDiscoveryValidator implements Validator { 037 038 private final Validators.ValidatorHelper helper; 039 040 public DatasetDiscoveryValidator(final Validators.ValidatorHelper helper) { 041 this.helper = helper; 042 } 043 044 @Override 045 public Stream<String> validate(final AnnotationFinder finder, final List<Class<?>> components) { 046 final List<Class<?>> datasetDiscoveryClasses = finder.findAnnotatedClasses(DatasetDiscovery.class); 047 final Map<Class<?>, String> datasetDiscoveries = datasetDiscoveryClasses 048 .stream() 049 .collect(toMap(identity(), d -> d.getAnnotation(DatasetDiscovery.class).value())); 050 051 final Stream<String> duplicated = DatasetValidator.duplicatedDataset(datasetDiscoveries.values()); 052 053 final Stream<String> i18nError = datasetDiscoveries 054 .entrySet() 055 .stream() 056 .map(entry -> this.helper 057 .validateFamilyI18nKey(entry.getKey(), 058 "${family}.datasetdiscovery." + entry.getValue() + "._displayName")) 059 .filter(Objects::nonNull); 060 061 // "cloud" rule - ensure all datasetDiscoveries have a datastore 062 final BaseParameterEnricher.Context context = 063 new BaseParameterEnricher.Context(new LocalConfigurationService(emptyList(), "tools")); 064 final Stream<String> withoutStore = datasetDiscoveryClasses 065 .stream() 066 .map((Class<?> ds) -> this.findDatasetDiscoveryWithoutDataStore(ds, context)) 067 .filter(Objects::nonNull) 068 .sorted(); 069 070 // A datasetDiscovery must implement interface DatasetDiscoveryConfiguration 071 final Stream<String> implementationError = datasetDiscoveryClasses 072 .stream() 073 .filter((Class<?> ds) -> !(DatasetDiscoveryConfiguration.class.isAssignableFrom(ds))) 074 .map((Class<?> ds) -> "Class " + ds.getName() + " must implement " 075 + DatasetDiscoveryConfiguration.class) 076 .sorted(); 077 078 return Stream 079 .of(duplicated, i18nError, withoutStore, implementationError) 080 .reduce(Stream::concat) 081 .orElseGet(Stream::empty); 082 } 083 084 private String findDatasetDiscoveryWithoutDataStore(final Class<?> ds, 085 final BaseParameterEnricher.Context context) { 086 final List<ParameterMeta> dataset = helper 087 .getParameterModelService() 088 .buildParameterMetas( 089 Stream.of(new ParameterModelService.Param(ds, ds.getAnnotations(), "datasetDiscovery")), ds, 090 ofNullable(ds.getPackage()).map(Package::getName).orElse(""), true, context); 091 if (DatasetValidator 092 .flatten(dataset) 093 .noneMatch(prop -> "datastore".equals(prop.getMetadata().get("tcomp::configurationtype::type")))) { 094 return "The datasetDiscovery " + ds.getName() 095 + " is missing a datastore reference in its configuration (see @DataStore)"; 096 } 097 return null; 098 } 099}