How to simplify ?

One Star

How to simplify ?

Hello,
I have an Oracle table input with this structure (called struct1):
- COD
- REF
- ENTITE
- TYPE_01
- TYPE_02
....
- TYPE_20
- AR_01
- AR_02
- ...
- AR_20
- NR_01 to 20
- ETBC_01 to 20
My job transforms this input in the following output (called Struct2):
- COD
- REF
- TYPE
- AR
- NR
- ETBC
So each line in Struct1 becomes 20 lines in Struct2.
I used a tMap to convert a struct1 line to 20 streams like struct2. But editing tMap component is very slow.
So I writed a tJavaRow to create 20 streams. This tJavaRow use the java reflect api, so it can use in an other context.
/*
* Configuration
*/
// Flux en entrée
Object inStream = Cases;
// Flux en sortie
Object [] outStreams = new Object[] {
case1,
case2,
case3,
case4,
case5,
case6,
case7,
case8,
case9,
case10,
case11,
case12,
case13,
case14,
case15,
case16,
case17,
case18,
case19,
case20};
// Séparateur du nom de la colonne et de l'indice de la colonne
char separator = '_';

/*
* Routine
*/
// Classe du flux d'entrée
Class clazz = inStream.getClass();
// Parcours des champs du flux d'entrée
for (java.lang.reflect.Field field : clazz.getDeclaredFields()) {
// Nom du champ
String fieldName = field.getName();
// Valeur du champ
field.setAccessible(true);
Object value = field.get(inStream);

int separatorIndex = fieldName.indexOf(separator);
if (separatorIndex > -1) {
// C'est un champ indexé
// Index du champ. (Les index des champs commencent à 1.
int index = Integer.parseInt(fieldName.substring(separatorIndex + 1)) - 1;
// Récupération du flux de sortie correspondant
Object outStream = outStreams;
// Nom de la colonne
String column = fieldName.substring(0, separatorIndex);

// Set de la valeur dans le flux de sortie
Object out = outStreams;
java.lang.reflect.Field outField = out.getClass().getDeclaredField(column);
outField.setAccessible(true);
outField.set(out, value);
} else {
// Ce n'est pas un champ indexé
// Set de la valeur dans tous les flux de sortie
for (Object out : outStreams) {
java.lang.reflect.Field outField = out.getClass().getDeclaredField(fieldName);
outField.setAccessible(true);
outField.set(out, value);
}
}
}

It works fine. But i want simplify my job.
Instead of creating 20 streams, how can i create only a output stream?
For each row of my input stream, how can i create 20 rows in the output stream?
Regards,
Arnaud BRUNET
Sorry for my poor English.
One Star

Re: How to simplify ?

Hello
First, I want to say your design with the java reflect api on tJavaRow is very good. It can assign the value to the 20 structs dynamically. Good idea.
But your case is a little special.
The key problem focus on how can we match your column "TYPE_01" with column "AR_01"?
( I mean, why column "TYPE_01" must match the column "AR_01"? why can't that match the column "TYPE_01" with the column "AR_02" ? )
So, as you know, we must write some code to add the rule between the columns "TYPE_01" and "AR_01".
The second problem is how can we generate 20 records from one record?
Here, I have a design to deal with your case, maybe it looks not very well, for your case is a little special, But it run well, and looks a little simple.
Welcome to use TOS.
Regards
One Star

Re: How to simplify ?

Hi,
Thanks for your answer.
I maked a job with tNormalize compoment but I need too tJavaRow compoments.
So I write a tJavaRow with for loop.
My final Job is join as picture.
Compoment descriptions :
CasesStrut :
private String CompteId;
private String TYPE_XX; // XX :01 ->20
private String AR_XX;
private String NR_XX;
private String NC_XX;
private String BC_XX;
private String ETBC_XX;

CaseStrut:
private String CompteId;
private String TYPE;
private String AR;
private String NR;
private String NC;
private String BC;
private String ETBC;

Début Dispatch Code :
/*
* Configuration
*/
// Flux en entrée
Object inStream = Cases;
// Flux en sortie
Object outStream = Case;
// Séparateur du nom de la colonne et de l'indice de la colonne
char separator = '_';
/*
* Routine
*/
// Classe du flux d'entrée
Class<?> clazz = inStream.getClass();
// Map contenant les différentes valeurs par colonnes
java.util.Map<String, List<String>> columns = new java.util.HashMap<String, List<String>>();
// Parcours des champs du flux d'entrée
for (java.lang.reflect.Field field : clazz.getDeclaredFields()) {
// Nom du champ
String fieldName = field.getName();
if ("this$0".equals(fieldName)) {
continue;
}
String columnName = fieldName;

// Valeur du champ
field.setAccessible(true);
String value = (String) field.get(inStream);

int separatorIndex = fieldName.indexOf(separator);
if (separatorIndex > -1) {
// C'est un champ indexé
// Index du champ. (Les index des champs commencent à 1.
int index = Integer.parseInt(fieldName.substring(separatorIndex + 1)) - 1;
// Nom de la colonne
columnName = fieldName.substring(0, separatorIndex);
// Enregistrement de la valeur dans la map
List<String> values = columns.get(columnName);
if (values == null) {
values = new java.util.ArrayList<String>();
columns.put(columnName, values);
}
values.add(index, value);
} else {
// Ce n'est pas un champ indexé
// Enregistrement de la valeur dans la map
columns.put(columnName, java.util.Arrays.asList(value));
}
}
int nbIndexedColumns = columns.values().iterator().next().size();
for (int i = 0; i < nbIndexedColumns; i++) {
// Remplissange du flux de sortie
for (java.util.Map.Entry<String, List<String>> column : columns.entrySet()) {
String outValue = "";
List<String> values = column.getValue();
if (values.size() == 1) {
// Cas d'une colonne non indexée
outValue = values.get(0);
} else {
// Cas d'une colonne indexée
outValue = values.get(i);
}
// Set de la valeur de sortie
java.lang.reflect.Field outField = outStream.getClass().getDeclaredField(column.getKey());
outField.setAccessible(true);
outField.set(outStream, outValue);
}
// Début du traitement

FinDispatch Code:
	// Fin du traitement
}

The "FinDispatch" tJavaRow close the for loop.
It's easier to maintain this job than before.
Regards,
Arnaud BRUNET
One Star

Re: How to simplify ?

Hello
Yes, my demo only have two columns "address" and "email", but your case have 7 columns need to do. So, if following my demo, there need 7 tNormalize. (a little complex)
Your new design is more simple now. I have checked it , it seems OK. Good.
Only one problem exist, this statement is not very good:
int nbIndexedColumns = columns.values().iterator().next().size();
maybe sometimes, it will return the value 1, sometimes it will return 20. (I know you run it normally, because the key of the map just suit it in your case.Smiley Happy )

Regards
xtan