Skip to content

Commit

Permalink
Merge branch 'master' into ypiel/TCOMP-2408_ComponentException_only_E…
Browse files Browse the repository at this point in the history
…xceptionCause
  • Loading branch information
undx authored Jun 26, 2024
2 parents 661d858 + 6e58767 commit 7b182dd
Show file tree
Hide file tree
Showing 16 changed files with 447 additions and 153 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<description>JUnit integration to simplify the HTTP API testing/mocking.</description>

<properties>
<netty.version>4.1.104.Final</netty.version>
<netty.version>4.1.111.Final</netty.version>
<talend.build.name>${talend.build.name.base}.junit.http</talend.build.name>
</properties>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ void getIconIndex() {
.accept(APPLICATION_SVG_XML_TYPE)
.get();
assertNotNull(icons);
assertEquals(406, icons.getStatus());
assertEquals(406, icons.getStatus());
// inexistant theme (no fallback)
icons = base.path("component/icon/index")
.queryParam("theme", "dak")
Expand Down Expand Up @@ -357,7 +357,8 @@ void getIconIndex() {
assertTrue(content.contains(
"data-connector=\"standalone\" data-family=\"chain\" data-theme=\"light\" data-type=\"connector\" id=\"myicon-light\""));
assertTrue(
content.contains("data-family=\"file\" data-theme=\"light\" data-type=\"family\" id=\"file-family-light\""));
content.contains(
"data-family=\"file\" data-theme=\"light\" data-type=\"family\" id=\"file-family-light\""));
// light theme
content = base.path("component/icon/index")
.queryParam("theme", "light")
Expand All @@ -371,7 +372,8 @@ void getIconIndex() {
assertTrue(content.contains(
"data-connector=\"standalone\" data-family=\"chain\" data-theme=\"light\" data-type=\"connector\" id=\"myicon-light\""));
assertTrue(
content.contains("data-family=\"file\" data-theme=\"light\" data-type=\"family\" id=\"file-family-light\""));
content.contains(
"data-family=\"file\" data-theme=\"light\" data-type=\"family\" id=\"file-family-light\""));

// dark theme
content = base.path("component/icon/index")
Expand All @@ -384,9 +386,11 @@ void getIconIndex() {
content.startsWith(
"<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"sr-only\" data-theme=\"dark\" focusable=\"false\">"));
assertTrue(content
.contains("data-connector=\"input\" data-family=\"jdbc\" data-theme=\"dark\" data-type=\"connector\" id=\"db-input-dark\""));
.contains(
"data-connector=\"input\" data-family=\"jdbc\" data-theme=\"dark\" data-type=\"connector\" id=\"db-input-dark\""));
assertTrue(content
.contains("data-connector=\"output\" data-family=\"jdbc\" data-theme=\"dark\" data-type=\"connector\" id=\"db-input-dark\""));
.contains(
"data-connector=\"output\" data-family=\"jdbc\" data-theme=\"dark\" data-type=\"connector\" id=\"db-input-dark\""));
// theme = all
content = base.path("component/icon/index")
.queryParam("theme", "all")
Expand All @@ -399,13 +403,16 @@ void getIconIndex() {
content.startsWith(
"<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"sr-only\" data-theme=\"all\" focusable=\"false\">"));
assertTrue(content
.contains("data-connector=\"input\" data-family=\"jdbc\" data-theme=\"dark\" data-type=\"connector\" id=\"db-input-dark\""));
.contains(
"data-connector=\"input\" data-family=\"jdbc\" data-theme=\"dark\" data-type=\"connector\" id=\"db-input-dark\""));
assertTrue(content
.contains("data-connector=\"output\" data-family=\"jdbc\" data-theme=\"dark\" data-type=\"connector\" id=\"db-input-dark\""));
.contains(
"data-connector=\"output\" data-family=\"jdbc\" data-theme=\"dark\" data-type=\"connector\" id=\"db-input-dark\""));
assertTrue(content.contains(
"data-connector=\"standalone\" data-family=\"chain\" data-theme=\"light\" data-type=\"connector\" id=\"myicon-light\""));
assertTrue(
content.contains("data-family=\"file\" data-theme=\"dark\" data-type=\"family\" id=\"file-family-dark\""));
content.contains(
"data-family=\"file\" data-theme=\"dark\" data-type=\"family\" id=\"file-family-dark\""));
}

@Test
Expand Down
6 changes: 5 additions & 1 deletion component-studio/component-runtime-di/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@
<scope>test</scope>
<!-- rarely needed + don't deliver it by default since it brings a lot of CVE -->
</dependency>

<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>${dom4j.version}</version>
</dependency>
<dependency>
<groupId>org.talend.sdk.component</groupId>
<artifactId>component-runtime-manager</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import static org.talend.sdk.component.api.record.SchemaProperty.STUDIO_TYPE;

import routines.system.Dynamic;
import routines.system.ParserUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
Expand All @@ -54,6 +55,7 @@
import javax.json.bind.spi.JsonbProvider;
import javax.json.spi.JsonProvider;

import org.dom4j.DocumentException;
import org.talend.sdk.component.api.record.Record;
import org.talend.sdk.component.api.record.Schema;
import org.talend.sdk.component.api.record.Schema.Entry;
Expand Down Expand Up @@ -307,46 +309,58 @@ private DynamicMetadataWrapper generateMetadata(final Entry entry) {
private void setField(final Entry entry, final Object value) {
final Field field = fields.get(entry.getName());
if (hasDynamic && (field == null || dynamicColumn.equals(entry.getName()))) {
final String name;
if (allowSpecialName) {
name = entry.getOriginalFieldName();
} else {
name = recordFieldsMap.computeIfAbsent(entry.getName(), key -> recordFields
.stream()
.filter(f -> f.endsWith("." + key))
.findFirst()
.orElse(key));
}
int index = dynamic.getDynamic().getIndex(name);
final DynamicMetadataWrapper metadata;
if (index < 0) {
metadata = generateMetadata(entry);
dynamic.getDynamic().metadatas.add(metadata.getDynamicMetadata());
index = dynamic.getDynamic().getIndex(name);
} else {
metadata = new DynamicMetadataWrapper(dynamic.getDynamic().getColumnMetadata(index));
}

final Class<?> clazz = StudioTypes.classFromType(metadata.getDynamicMetadata().getType());
if (clazz != null) {
dynamic.getDynamic().setColumnValue(index, MappingUtils.coerce(clazz, value, name));
} else {
dynamic.getDynamic().setColumnValue(index, MappingUtils.coerce(value.getClass(), value, name));
}
log.trace("[setField] Dynamic#{}\t{}\t({})\t ==> {}.", index, name, metadata.getDynamicMetadata().getType(),
value);
handleDynamic(entry, value);
return;
}
if (field == null) {
return;
}

try {
if (routines.system.Document.class == field.getType()) {
log.trace("[setField] Document#{}.", entry.getName());
field.set(instance, ParserUtils.parseTo_Document(value.toString()));
return;
}

field.set(instance, MappingUtils.coerce(field.getType(), value, entry.getName()));
} catch (final IllegalAccessException e) {
} catch (final IllegalAccessException | DocumentException e) {
log.error("[setField] exception message: {}", e.getMessage());
throw new IllegalStateException(e);
}
}

private void handleDynamic(final Entry entry, final Object value) {
final String name;
if (allowSpecialName) {
name = entry.getOriginalFieldName();
} else {
name = recordFieldsMap.computeIfAbsent(entry.getName(), key -> recordFields
.stream()
.filter(f -> f.endsWith("." + key))
.findFirst()
.orElse(key));
}
int index = dynamic.getDynamic().getIndex(name);
final DynamicMetadataWrapper metadata;
if (index < 0) {
metadata = generateMetadata(entry);
dynamic.getDynamic().metadatas.add(metadata.getDynamicMetadata());
index = dynamic.getDynamic().getIndex(name);
} else {
metadata = new DynamicMetadataWrapper(dynamic.getDynamic().getColumnMetadata(index));
}

final Class<?> clazz = StudioTypes.classFromType(metadata.getDynamicMetadata().getType());
if (clazz != null) {
dynamic.getDynamic().setColumnValue(index, MappingUtils.coerce(clazz, value, name));
} else {
dynamic.getDynamic().setColumnValue(index, MappingUtils.coerce(value.getClass(), value, name));
}
log.trace("[setField] Dynamic#{}\t{}\t({})\t ==> {}.", index, name, metadata.getDynamicMetadata().getType(),
value);
}

@Override
public void onInt(final Entry entry, final OptionalInt optionalInt) {
log.trace("[onInt] visiting {}.", entry.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
import static org.talend.sdk.component.api.record.SchemaProperty.SIZE;
import static org.talend.sdk.component.api.record.SchemaProperty.STUDIO_TYPE;

import routines.system.Document;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
Expand Down Expand Up @@ -140,76 +142,15 @@ private void visit(final Object data) {
}
onDatetime(name, Date.class.cast(raw).toInstant().atZone(UTC));
break;
case StudioTypes.DOCUMENT:
if (Document.class.cast(raw).getDocument() == null) {
log.trace("[visit] Skipping field {} with null value.", name);
return;
}
onDocument(name, raw);
break;
case StudioTypes.DYNAMIC:
final DynamicWrapper dynamic = new DynamicWrapper(raw);
dynamic.getDynamic().metadatas.forEach(meta -> {
final Object value = dynamic.getDynamic().getColumnValue(meta.getName());
final String metaName = sanitizeConnectionName(meta.getName());
final String metaOriginalName = meta.getDbName();
log.trace("[visit] Dynamic {}\t({})\t ==> {}.", meta.getName(), meta.getType(), value);
if (value == null) {
return;
}
switch (meta.getType()) {
case StudioTypes.OBJECT:
onObject(metaName, value);
break;
case StudioTypes.LIST:
onArray(toCollectionEntry(metaName, metaOriginalName, value), Collection.class.cast(value));
break;
case StudioTypes.STRING:
case StudioTypes.CHARACTER:
onString(metaName, value);
break;
case StudioTypes.BYTE_ARRAY:
final byte[] bytes;
if (byte[].class.isInstance(value)) {
bytes = byte[].class.cast(value);
} else if (ByteBuffer.class.isInstance(value)) {
bytes = ByteBuffer.class.cast(value).array();
} else {
log
.warn("[visit] '{}' of type `id_byte[]` and content is contained in `{}`:"
+ " This should not happen! "
+ " Wrapping `byte[]` from `String.valueOf()`: result may be inaccurate.",
metaName, value.getClass().getSimpleName());
bytes = ByteBuffer.wrap(String.valueOf(value).getBytes()).array();
}
onBytes(metaName, bytes);
break;
case StudioTypes.BYTE:
case StudioTypes.SHORT:
case StudioTypes.INTEGER:
onInt(metaName, value);
break;
case StudioTypes.LONG:
onLong(metaName, value);
break;
case StudioTypes.FLOAT:
onFloat(metaName, value);
break;
case StudioTypes.DOUBLE:
onDouble(metaName, value);
break;
case StudioTypes.BIGDECIMAL:
onDecimal(metaName, BigDecimal.class.cast(value));
break;
case StudioTypes.BOOLEAN:
onBoolean(metaName, value);
break;
case StudioTypes.DATE:
final ZonedDateTime dateTime;
if (Long.class.isInstance(value)) {
dateTime = ZonedDateTime.ofInstant(ofEpochMilli(Long.class.cast(value)), UTC);
} else {
dateTime = ZonedDateTime.ofInstant(Date.class.cast(value).toInstant(), UTC);
}
onDatetime(metaName, dateTime);
break;
default:
throw new IllegalStateException("Unexpected value: " + meta.getType());
}
});
handleDynamic(raw);
break;
default:
throw new IllegalAccessException(String.format("Invalid type: %s (%s) with value: %s. .",
Expand All @@ -221,6 +162,78 @@ private void visit(final Object data) {
});
}

private void handleDynamic(final Object raw) {
final DynamicWrapper dynamic = new DynamicWrapper(raw);
dynamic.getDynamic().metadatas.forEach(meta -> {
final Object value = dynamic.getDynamic().getColumnValue(meta.getName());
final String metaName = sanitizeConnectionName(meta.getName());
final String metaOriginalName = meta.getDbName();
log.trace("[visit] Dynamic {}\t({})\t ==> {}.", meta.getName(), meta.getType(), value);
if (value == null) {
return;
}
switch (meta.getType()) {
case StudioTypes.OBJECT:
onObject(metaName, value);
break;
case StudioTypes.LIST:
onArray(toCollectionEntry(metaName, metaOriginalName, value), Collection.class.cast(value));
break;
case StudioTypes.STRING:
case StudioTypes.CHARACTER:
onString(metaName, value);
break;
case StudioTypes.BYTE_ARRAY:
final byte[] bytes;
if (byte[].class.isInstance(value)) {
bytes = byte[].class.cast(value);
} else if (ByteBuffer.class.isInstance(value)) {
bytes = ByteBuffer.class.cast(value).array();
} else {
log
.warn("[visit] '{}' of type `id_byte[]` and content is contained in `{}`:"
+ " This should not happen! "
+ " Wrapping `byte[]` from `String.valueOf()`: result may be inaccurate.",
metaName, value.getClass().getSimpleName());
bytes = ByteBuffer.wrap(String.valueOf(value).getBytes()).array();
}
onBytes(metaName, bytes);
break;
case StudioTypes.BYTE:
case StudioTypes.SHORT:
case StudioTypes.INTEGER:
onInt(metaName, value);
break;
case StudioTypes.LONG:
onLong(metaName, value);
break;
case StudioTypes.FLOAT:
onFloat(metaName, value);
break;
case StudioTypes.DOUBLE:
onDouble(metaName, value);
break;
case StudioTypes.BIGDECIMAL:
onDecimal(metaName, BigDecimal.class.cast(value));
break;
case StudioTypes.BOOLEAN:
onBoolean(metaName, value);
break;
case StudioTypes.DATE:
final ZonedDateTime dateTime;
dateTime = ZonedDateTime.ofInstant(value instanceof Long ? ofEpochMilli(Long.class.cast(value))
: Date.class.cast(value).toInstant(), UTC);
onDatetime(metaName, dateTime);
break;
case StudioTypes.DOCUMENT:
onString(metaName, value);
break;
default:
throw new IllegalStateException("Unexpected value: " + meta.getType());
}
});
}

public Record get(final Object data, final RecordBuilderFactory factory) {
if (rowStructSchema == null) {
this.factory = factory;
Expand Down Expand Up @@ -323,6 +336,10 @@ private Schema inferSchema(final Object data, final RecordBuilderFactory factory
schema.withEntry(toEntry(name, BYTES, originalDbColumnName, isNullable, comment, isKey, null, null,
defaultValue, null, studioType));
break;
case StudioTypes.DOCUMENT:
schema.withEntry(toEntry(name, STRING, originalDbColumnName, isNullable, comment, isKey, null,
null, defaultValue, pattern, studioType));
break;
case StudioTypes.DYNAMIC:
final DynamicWrapper dynamic = new DynamicWrapper(raw);
dynamic.getDynamic().metadatas.forEach(meta -> {
Expand Down Expand Up @@ -421,6 +438,10 @@ private void onString(final String name, final Object value) {
recordBuilder.withString(name, String.class.cast(MappingUtils.coerce(String.class, value, name)));
}

private void onDocument(final String name, final Object raw) {
recordBuilder.withString(name, Document.class.cast(raw).getDocument().toString());
}

private void onDecimal(final String name, final BigDecimal value) {
recordBuilder.withDecimal(name, value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public class StudioTypes {
put("long", LONG);
put("routines.system.Dynamic", DYNAMIC);
put("short", SHORT);
put("routines.system.Document", DOCUMENT);
}
};

Expand Down
Loading

0 comments on commit 7b182dd

Please sign in to comment.