Skip to content

Commit

Permalink
feat(QTDI-723): fixed schema
Browse files Browse the repository at this point in the history
Co-authored-by: undx <[email protected]>
  • Loading branch information
undx and undx authored Dec 5, 2024
1 parent c30452a commit 64be644
Show file tree
Hide file tree
Showing 9 changed files with 386 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* Copyright (C) 2006-2024 Talend Inc. - www.talend.com
*
* Licensed 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 org.talend.sdk.component.api.service.schema;

import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import org.talend.sdk.component.api.meta.Documentation;

@Target(TYPE)
@Retention(RUNTIME)
@Documentation("Mark a connector as having a fixed schema. " +
"Annotation's value must match the name of a DiscoverSchema or a DiscoverSchemaExtended annotation. " +
"The related action will return the fixed schema.")
public @interface FixedSchema {

String value() default "";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Copyright (C) 2006-2024 Talend Inc. - www.talend.com
*
* Licensed 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 org.talend.sdk.component.runtime.manager.reflect.parameterenricher;

import static java.util.Collections.emptyMap;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

import org.talend.sdk.component.api.service.schema.FixedSchema;

public class SchemaParameterEnricher extends BaseParameterEnricher {

public static final String META_PREFIX = "tcomp::ui::schema::fixed";

@Override
public Map<String, String> onParameterAnnotation(final String parameterName, final Type parameterType,
final Annotation annotation) {
if (FixedSchema.class.equals(annotation.annotationType())) {
FixedSchema fixed = FixedSchema.class.cast(annotation);
return new HashMap<String, String>() {

{
put(META_PREFIX, fixed.value());
}
};
}
return emptyMap();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* Copyright (C) 2006-2024 Talend Inc. - www.talend.com
*
* Licensed 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 org.talend.sdk.component.runtime.manager.reflect.parameterenricher;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.lang.annotation.Annotation;
import java.util.HashMap;

import org.junit.jupiter.api.Test;
import org.talend.sdk.component.api.service.schema.FixedSchema;

public class SchemaParameterEnricherTest {

private final SchemaParameterEnricher enricher = new SchemaParameterEnricher();

@Test
void validateConnectorReference() throws ReflectiveOperationException {
assertEquals(new HashMap<String, String>() {

{
put("tcomp::ui::schema::fixed", "discover");
}
}, enricher.onParameterAnnotation("testParam", null, new FixedSchema() {

@Override
public Class<? extends Annotation> annotationType() {
return FixedSchema.class;
}

@Override
public String value() {
return "discover";
}
}));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -310,5 +310,7 @@ public static class Configuration {

private boolean validateSchema;

private boolean validateFixedSchema;

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* Copyright (C) 2006-2024 Talend Inc. - www.talend.com
*
* Licensed 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 org.talend.sdk.component.tools.validator;

import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.xbean.finder.AnnotationFinder;
import org.talend.sdk.component.api.service.schema.DiscoverSchema;
import org.talend.sdk.component.api.service.schema.DiscoverSchemaExtended;
import org.talend.sdk.component.api.service.schema.FixedSchema;

public class FixedSchemaValidator implements Validator {

@Override
public Stream<String> validate(final AnnotationFinder finder, final List<Class<?>> components) {
final List<String> errors = new ArrayList<>();
final Map<Class<?>, String> classes = finder.findAnnotatedClasses(FixedSchema.class)
.stream()
.collect(toMap(identity(), d -> d.getAnnotation(FixedSchema.class).value()));
// search for empty annotations
errors.addAll(classes.entrySet()
.stream()
.filter(e -> e.getValue().isEmpty())
.map(e -> String.format("Empty @FixedSchema annotation's value in class %s.",
e.getKey().getSimpleName()))
.collect(Collectors.toList()));
// search for missing methods
final List<String> methods = Stream
.concat(finder.findAnnotatedMethods(DiscoverSchema.class)
.stream()
.map(m -> m.getDeclaredAnnotation(DiscoverSchema.class).value()),
finder.findAnnotatedMethods(DiscoverSchemaExtended.class)
.stream()
.map(m -> m.getDeclaredAnnotation(DiscoverSchemaExtended.class).value()))
.collect(Collectors.toList());
errors.addAll(classes.entrySet()
.stream()
.filter(e -> !e.getValue().isEmpty())
.filter(e -> !methods.contains(e.getValue()))
.map(e -> String.format("@FixedSchema '%s' in class %s is not declared anywhere as DiscoverSchema*.",
e.getValue(), e.getKey().getSimpleName()))
.collect(Collectors.toList()));

return errors.stream();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ public static Validators build(final Configuration configuration, final Validato
if (configuration.isValidateSchema()) {
activeValidators.add(new SchemaValidator());
}
if (configuration.isValidateFixedSchema()) {
activeValidators.add(new FixedSchemaValidator());
}

return new Validators(activeValidators);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/**
* Copyright (C) 2006-2024 Talend Inc. - www.talend.com
*
* Licensed 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 org.talend.sdk.component.tools.validator;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.io.Serializable;
import java.util.Arrays;
import java.util.stream.Stream;

import org.apache.xbean.finder.AnnotationFinder;
import org.apache.xbean.finder.archive.ClassesArchive;
import org.junit.jupiter.api.Test;
import org.talend.sdk.component.api.configuration.Option;
import org.talend.sdk.component.api.configuration.type.DataSet;
import org.talend.sdk.component.api.input.Emitter;
import org.talend.sdk.component.api.input.Producer;
import org.talend.sdk.component.api.record.Record;
import org.talend.sdk.component.api.record.Schema;
import org.talend.sdk.component.api.service.Service;
import org.talend.sdk.component.api.service.schema.DiscoverSchema;
import org.talend.sdk.component.api.service.schema.DiscoverSchemaExtended;
import org.talend.sdk.component.api.service.schema.FixedSchema;

public class FixedSchemaValidatorTest {

@Test
void validateFixedSchema() {
final FixedSchemaValidator validator = new FixedSchemaValidator();
AnnotationFinder finder =
new AnnotationFinder(new ClassesArchive(MySourceOk.class, MySourceOkExt.class, FixedService.class));
final Stream<String> noerrors =
validator.validate(finder, Arrays.asList(MySourceOk.class, MySourceOkExt.class, FixedService.class));
assertEquals(0, noerrors.count());

finder = new AnnotationFinder(
new ClassesArchive(MySourceKoEmpty.class, MySourceKoMissing.class, FixedService.class));
final Stream<String> errors = validator.validate(finder,
Arrays.asList(MySourceKoEmpty.class, MySourceKoMissing.class, FixedService.class));
assertEquals(2, errors.count());
}

@Emitter(family = "test", name = "mysource0")
@FixedSchema("discover")
static class MySourceOk implements Serializable {

@Producer
public Record next() {
return null;
}
}

@Emitter(family = "test", name = "mysource1")
@FixedSchema("discoverext")
static class MySourceOkExt implements Serializable {

@Producer
public Record next() {
return null;
}
}

@Emitter(family = "test", name = "mysource2")
@FixedSchema
static class MySourceKoEmpty implements Serializable {

@Producer
public Record next() {
return null;
}
}

@Emitter(family = "test", name = "mysource3")
@FixedSchema("missing")
static class MySourceKoMissing implements Serializable {

@Producer
public Record next() {
return null;
}
}

@DataSet("ds")
public static class DS {

@Option
private String dto;
}

@Service
static class FixedService {

@DiscoverSchema("discover")
public Schema discover(DS ds) {
return null;
}

@DiscoverSchemaExtended("discoverext")
public Schema discover(DS ds, String branch) {
return null;
}
}
}
Loading

0 comments on commit 64be644

Please sign in to comment.