From 7787560c2bd9851043b7aa054c8131bca8efeb11 Mon Sep 17 00:00:00 2001 From: "Juan A. Fernandez" Date: Tue, 27 May 2014 09:47:14 +0200 Subject: [PATCH] Version 1.1 * Solved Bugs: - Output doesn't assign values if aliases are different https://github.com/amnesty/civicrm-data-integration/issues/2 * New improvements: - Manage result from output component https://github.com/amnesty/civicrm-data-integration/issues/9 - Beign able to define an http proxy https://github.com/amnesty/civicrm-data-integration/issues/12 - Create a response field https://github.com/amnesty/civicrm-data-integration/issues/6 - CiviCRM Input must be able to filter using data from previous steps https://github.com/amnesty/civicrm-data-integration/issues/1 - list of available fields not available in the filter https://github.com/amnesty/civicrm-data-integration/issues/7 --- bin/CIVICRMInput/CiviCrmInput.jar | Bin 54149 -> 61233 bytes bin/CIVICRMOutput/CiviCrmOutput.jar | Bin 48389 -> 50033 bytes src/main/CiviCRMInput/.classpath | 19 +- src/main/CiviCRMInput/.project | 2 +- .../es/stratebi/civi/input/CiviInputData.java | 1 - .../stratebi/civi/input/CiviInputDialog.java | 455 ++++++--- .../es/stratebi/civi/input/CiviInputMeta.java | 188 +++- .../es/stratebi/civi/input/CiviInputStep.java | 371 ++++++-- src/main/CiviCRMInput/swing2swt.jar | Bin 0 -> 33196 bytes .../civi/output/CiviOutputDialog.java | 215 +++-- .../stratebi/civi/output/CiviOutputMeta.java | 14 +- .../stratebi/civi/output/CiviOutputStep.java | 166 ++-- src/main/CiviCRMUtil/.classpath | 18 +- .../src/es/stratebi/civi/CiviData.java | 2 +- .../src/es/stratebi/civi/CiviDialog.java | 83 +- .../src/es/stratebi/civi/CiviMeta.java | 107 ++- .../src/es/stratebi/civi/CiviStep.java | 7 +- .../civi/messages/messages_en_US.properties | 26 +- .../src/es/stratebi/civi/util/FieldAttrs.java | 1 - .../src/es/stratebi/civi/util/JSONString.java | 6 +- .../src/es/stratebi/civi/util/RestUtil.java | 882 +++++++++--------- 21 files changed, 1635 insertions(+), 928 deletions(-) create mode 100644 src/main/CiviCRMInput/swing2swt.jar diff --git a/bin/CIVICRMInput/CiviCrmInput.jar b/bin/CIVICRMInput/CiviCrmInput.jar index 2074e5bd12f183a824a242c240ec98d54d4c6c0d..83aa5362caa6820162921560830b903b3afe3c18 100644 GIT binary patch delta 53651 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 R(nlnKS17Om!{Rc6zbC>`C delta 46501 zcmZU)Q*b3*)UF#F9VaX5*tTukwr#AWW81cE+jcre$F`I6{rlYfyY|(*7&UL^81>eu z=c(DS10GTaj-)694uK8=0|Nu1Wo;^wfTRcUKWEYvAz9J{C<5@qL}dm42QSlk$&p6! z49{9m5K78w!tgYpo_j-?vN-@r5w%eeEBWiq3wK!A;(1rL#irg zQs3Ss%cqayC(-WOMP8Ut3jB2_GuOv{_AU43<-sr4Vdwp(st#N;%mZN>O_Ta7n9x)G z_s5m!Bta`0zAx|*lG)-nY5mp{6dKnV#A+tA@Lu`^D94c*=2az z%Le=on!KyD9sVi-5)4TWGczR3+?w7r%o7KCCSTT77yp?Q@(K8PN*h@%%D;RZPyA23 z$Q(U+(S+goP#T$){9pt?Q&n7pyZ2*U|xx& zb*iA>BxSR=-4r#C_7c|hF%7T#9n5=)LOAGsc=gO)nVurHP+A6ie`gIFoyqhkXrkS~ z5bmDZSNqw(q9&0uUSZf7vyW!HXbx#4Q)CaqRQ~{NnU%uo17}vGLmO=&q?$9@kqAwU zm80l&%oj85V0HQHSt71d1(t1&5>c9qmIR>>D~*?i)m@pu#zhT}bjzvJ5Ns_p)dH4m z*%Il5_TErzhmg>C7KSDTpTR%Goh#jk4^qh0-Y=OOaD5~NH?$U1c-J_?91gZoE=Tym z{ak^^kM?m@2)%^Wf^J+>4<*{=gGONojztkchRZlZ)JX2gFuH(ECbUxHc-3n@df>NdG2& zFIZT(;7klB=+&mR{9%k`I+u7|+t}R9l$QW9hDTS*|D|R|ri5D)MdE;8wvMJ%a8a5K zrzDG0#I}-oB!)yL+qfE#&uDB?CkI3JMK~-DL^~;zd$9J{j&8<7BWV}wUp|nwQM<)g z_O(}I=Ni!=akng$lctFH=N{;Wr2=sMqp$)Eo`>3At!wVHGh1AOWrRwg)Z42A`|}74 zX)>k`y%8jj{(xW?=Md{EvRc!^5RK!xjyU}#u_vxl%R<}pd&7Yzl>>EU;J6AgtAL-9 z4;XXc)E5DL``acYrAXaswf9`ULbT54*S8(q6baax9!L~}*RJ`c&axX1Rv{ySiDlA+ zzXZNVA!rj*WiW4nBmaaA$*LZ{9CjYi1WNP^58Sjr)ykSP(gJ~Z20e?P

+ipx>As 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 Ee_zW_YXATM delta 41007 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 - - - - - - - - - + + + + + + + + + + diff --git a/src/main/CiviCRMInput/.project b/src/main/CiviCRMInput/.project index e06b22c..5062e32 100644 --- a/src/main/CiviCRMInput/.project +++ b/src/main/CiviCRMInput/.project @@ -1,6 +1,6 @@ - CiviCRMInput + CiviCrmInput diff --git a/src/main/CiviCRMInput/src/es/stratebi/civi/input/CiviInputData.java b/src/main/CiviCRMInput/src/es/stratebi/civi/input/CiviInputData.java index 44d5061..83480ac 100644 --- a/src/main/CiviCRMInput/src/es/stratebi/civi/input/CiviInputData.java +++ b/src/main/CiviCRMInput/src/es/stratebi/civi/input/CiviInputData.java @@ -5,7 +5,6 @@ import es.stratebi.civi.CiviData; /* - * * * Esta clase es la que mantiene los datos que se van a enviar hacia el paso que sigue. El truco que * hemos usado es crear una lista con todos aquellos valores que devueltos por el API de CIVICRM diff --git a/src/main/CiviCRMInput/src/es/stratebi/civi/input/CiviInputDialog.java b/src/main/CiviCRMInput/src/es/stratebi/civi/input/CiviInputDialog.java index 48c89c2..8d19f24 100644 --- a/src/main/CiviCRMInput/src/es/stratebi/civi/input/CiviInputDialog.java +++ b/src/main/CiviCRMInput/src/es/stratebi/civi/input/CiviInputDialog.java @@ -1,6 +1,9 @@ package es.stratebi.civi.input; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import org.eclipse.swt.SWT; @@ -28,6 +31,8 @@ import org.eclipse.swt.widgets.Text; import org.pentaho.di.core.Const; import org.pentaho.di.core.Props; +import org.pentaho.di.core.exception.KettleStepException; +import org.pentaho.di.core.row.RowMetaInterface; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.trans.Trans; import org.pentaho.di.trans.TransMeta; @@ -46,12 +51,9 @@ import org.pentaho.di.ui.trans.step.BaseStepDialog; import es.stratebi.civi.CiviDialog; -import es.stratebi.civi.CiviMeta; import es.stratebi.civi.util.FieldAttrs; -import es.stratebi.civi.util.RestUtil; /* - * * * Este es el dialogo de conexion a la API REST de CiviCRM */ @@ -73,6 +75,13 @@ public class CiviInputDialog extends CiviDialog implements StepDialogInterface { private ColumnInfo filterFieldsColumn = null; + // all fields from the previous steps, used for drop down selection + private RowMetaInterface prevMetaFields = null; + private String[] prevFields = new String[0]; + + // the drop down column which should contain previous fields from stream + private ColumnInfo prevFieldColumn = null; + private Group gEntity; private Composite gEntityFilter; private Composite gOutputFields; @@ -87,6 +96,11 @@ public class CiviInputDialog extends CiviDialog implements StepDialogInterface { private Listener lsGetEntities; private Listener lsTestConnection; + private Button wFilterWithPrevious; + private Label wlCiviCrmDebugMode; + private Label wlCiviCrmResultField; + private String[] comboFilterFields; + private ColumnInfo operatorFieldColumn; // Constructor public CiviInputDialog(Shell parent, Object in, TransMeta transMeta, String sname) { @@ -238,7 +252,7 @@ public void modifyText(ModifyEvent e) { fdlCiviPageSize.left = new FormAttachment(0, 0); fdlCiviPageSize.right = new FormAttachment(middle, -margin); wlCiviCrmPageSize.setLayoutData(fdlCiviPageSize); - + // CiviCrm pageSize text wCiviCrmPageSize = new TextVar(transMeta, gConnectionGroup, SWT.SINGLE | SWT.LEFT | SWT.BORDER); wCiviCrmPageSize.addModifyListener(lsMod); @@ -250,7 +264,52 @@ public void modifyText(ModifyEvent e) { fdCiviPageSize.left = new FormAttachment(middle, 0); fdCiviPageSize.right = new FormAttachment(100, 0); wCiviCrmPageSize.setLayoutData(fdCiviPageSize); - + + // CiviCrm JSON ResultField + wlCiviCrmResultField = new Label(gConnectionGroup, SWT.RIGHT); + wlCiviCrmResultField.setText(BaseMessages.getString(PKG, "CiviCrmDialog.ResultFieldName.Label")); + props.setLook(wlCiviCrmResultField); + + FormData fdlCiviCrmApiResultField = new FormData(); + fdlCiviCrmApiResultField.top = new FormAttachment(wCiviCrmPageSize, margin); + fdlCiviCrmApiResultField.left = new FormAttachment(0, 0); + fdlCiviCrmApiResultField.right = new FormAttachment(middle, -margin); + wlCiviCrmResultField.setLayoutData(fdlCiviCrmApiResultField); + + wCiviCrmResultField = new TextVar(transMeta, gConnectionGroup, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + wCiviCrmResultField.addModifyListener(lsMod); + wCiviCrmResultField.setToolTipText(BaseMessages.getString(PKG, "CiviCrmDialog.ResultFieldName.Tooltip")); + props.setLook(wCiviCrmResultField); + + FormData fdCiviCrmApiResultField = new FormData(); + fdCiviCrmApiResultField.top = new FormAttachment(wCiviCrmPageSize, margin); + fdCiviCrmApiResultField.left = new FormAttachment(middle, 0); + fdCiviCrmApiResultField.right = new FormAttachment(100, 0); + wCiviCrmResultField.setLayoutData(fdCiviCrmApiResultField); + + // CiviCrm debug mode label + wlCiviCrmDebugMode = new Label(gConnectionGroup, SWT.RIGHT); + wlCiviCrmDebugMode.setText(BaseMessages.getString(PKG, "CiviCrmDialog.DebugMode.Label")); + props.setLook(wlCiviCrmDebugMode); + + FormData fdlDebugMode = new FormData(); + fdlDebugMode.top = new FormAttachment(wCiviCrmResultField, margin); + fdlDebugMode.left = new FormAttachment(0, 0); + fdlDebugMode.right = new FormAttachment(middle, -margin); + wlCiviCrmDebugMode.setLayoutData(fdlDebugMode); + + // CiviCrm debug mode checkbox + wCiviCrmDebugMode = new Button(gConnectionGroup, SWT.CHECK); + wCiviCrmDebugMode.setToolTipText(BaseMessages.getString(PKG, "CiviCrmDialog.DebugMode.Tooltip")); + props.setLook(wCiviCrmDebugMode); + + FormData fdCiviCrmdDebugMode = new FormData(); + fdCiviCrmdDebugMode.right = new FormAttachment(wlCiviCrmDebugMode, 25, SWT.RIGHT); + fdCiviCrmdDebugMode.top = new FormAttachment(wCiviCrmResultField, margin); + fdCiviCrmdDebugMode.left = new FormAttachment(wlCiviCrmDebugMode, 5); + + wCiviCrmDebugMode.setLayoutData(fdCiviCrmdDebugMode); + // Test connection button wTestConnection = new Button(gConnectionGroup, SWT.PUSH); wTestConnection.setText(BaseMessages.getString(PKG, "CiviCrmDialog.TestConnection.Button")); //$NON-NLS-1$ @@ -260,12 +319,12 @@ public void modifyText(ModifyEvent e) { wGetEntities.setText(BaseMessages.getString(PKG, "CiviCrmDialog.GetEntityList.Button")); //$NON-NLS-1$ FormData fdGetEntities = new FormData(); - fdGetEntities.top = new FormAttachment(wCiviCrmPageSize, margin); + fdGetEntities.top = new FormAttachment(wlCiviCrmDebugMode, margin); fdGetEntities.right = new FormAttachment(100, 0); wGetEntities.setLayoutData(fdGetEntities); FormData fdTestConnection = new FormData(); - fdTestConnection.top = new FormAttachment(wCiviCrmPageSize, margin); + fdTestConnection.top = new FormAttachment(wlCiviCrmDebugMode, margin); fdTestConnection.right = new FormAttachment(wGetEntities, -margin); wTestConnection.setLayoutData(fdTestConnection); @@ -376,16 +435,17 @@ public void handleEvent(Event e) { *************************************************/ int outputKeyWidgetCols = 2; - int outputKeyWidgetRows = (((CiviInputMeta) input).getFields() != null ? ((CiviInputMeta) input).getFields().values().size() : 3); + int outputKeyWidgetRows = (((CiviInputMeta) input).getCiviCrmFields() != null ? ((CiviInputMeta) input).getCiviCrmFields().values() + .size() : 3); ColumnInfo[] ciOutputKeys = new ColumnInfo[outputKeyWidgetCols]; - ciOutputKeys[0] = new ColumnInfo(BaseMessages.getString(PKG, "CiviCrmDialog.ColumnInfo.FieldName"), ColumnInfo.COLUMN_TYPE_CCOMBO, + ciOutputKeys[0] = new ColumnInfo(BaseMessages.getString(PKG, "CiviCrmDialog.ColumnInfo.NameField"), ColumnInfo.COLUMN_TYPE_CCOMBO, new String[] {}, false); - ciOutputKeys[1] = new ColumnInfo(BaseMessages.getString(PKG, "CiviCrmDialog.ColumnInfo.FieldRename"), ColumnInfo.COLUMN_TYPE_TEXT, + ciOutputKeys[1] = new ColumnInfo(BaseMessages.getString(PKG, "CiviCrmDialog.ColumnInfo.RenameField"), ColumnInfo.COLUMN_TYPE_TEXT, false); - + outputFieldsColumn = ciOutputKeys[0]; - + tOutputFields = new TableView(transMeta, gOutputFields, SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL, ciOutputKeys, outputKeyWidgetRows, lsMod, props); @@ -415,23 +475,47 @@ public void handleEvent(Event e) { gEntityFilter = new Composite(wTabFolder, SWT.NONE); props.setLook(gEntityFilter); - FormLayout fieldsCompLayout = new FormLayout(); - fieldsCompLayout.marginWidth = Const.FORM_MARGIN; - fieldsCompLayout.marginHeight = Const.FORM_MARGIN; - gEntityFilter.setLayout(fieldsCompLayout); - + FormLayout entityFormLayout = new FormLayout(); + entityFormLayout.marginWidth = Const.FORM_MARGIN; + entityFormLayout.marginHeight = Const.FORM_MARGIN; + gEntityFilter.setLayout(entityFormLayout); + + // Update fields from previous steps? + /* + wFilterWithPrevious = new Button(gEntityFilter, SWT.PUSH); + wFilterWithPrevious.setText(BaseMessages.getString(PKG, "CiviCrmDialog.UpdatePreviousFields.Title")); + wFilterWithPrevious.setToolTipText(BaseMessages.getString(PKG, "CiviCrmDialog.UpdatePreviousFields.Tooltip")); + props.setLook(wFilterWithPrevious); + + FormData fdFilterWithPrevious = new FormData(); + fdFilterWithPrevious.right = new FormAttachment(100, 0); + fdFilterWithPrevious.top = new FormAttachment(0, margin); + wFilterWithPrevious.setLayoutData(fdFilterWithPrevious); + + wFilterWithPrevious.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent arg0) { + updatePreviousFields(); + } + }); + */ + /************************************************* * // KEY / FILTER TABLE *************************************************/ - int keyWidgetCols = 2; - int keyWidgetRows = (((CiviInputMeta) input).getFields() != null ? ((CiviInputMeta) input).getFields().values().size() : 1); + int keyWidgetCols = 3; + int keyWidgetRows = 3; + // (((CiviInputMeta) input).getCiviCrmFields() != null ? ((CiviInputMeta) + // input).getCiviCrmFields().values().size() : 1); ColumnInfo[] ciKeys = new ColumnInfo[keyWidgetCols]; - ciKeys[0] = new ColumnInfo(BaseMessages.getString(PKG, "CiviCrmDialog.ColumnInfo.FieldName"), ColumnInfo.COLUMN_TYPE_CCOMBO, + ciKeys[0] = new ColumnInfo(BaseMessages.getString(PKG, "CiviCrmDialog.ColumnInfo.NameField"), ColumnInfo.COLUMN_TYPE_CCOMBO, new String[] {}, false); - ciKeys[1] = new ColumnInfo(BaseMessages.getString(PKG, "CiviCrmDialog.ColumnInfo.FieldValue"), ColumnInfo.COLUMN_TYPE_TEXT, false); + ciKeys[1] = new ColumnInfo(BaseMessages.getString(PKG, "CiviCrmDialog.ColumnInfo.FilterOperator"), ColumnInfo.COLUMN_TYPE_CCOMBO); + ciKeys[2] = new ColumnInfo(BaseMessages.getString(PKG, "CiviCrmDialog.ColumnInfo.InputValueName"), ColumnInfo.COLUMN_TYPE_CCOMBO); filterFieldsColumn = ciKeys[0]; + operatorFieldColumn = ciKeys[1]; + prevFieldColumn = ciKeys[2]; tFilterFields = new TableView(transMeta, gEntityFilter, SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL, ciKeys, keyWidgetRows, lsMod, props); @@ -439,13 +523,14 @@ public void handleEvent(Event e) { FormData fdFields = new FormData(); fdFields.left = new FormAttachment(0, 0); fdFields.top = new FormAttachment(0, margin); + //fdFields.top = new FormAttachment(wFilterWithPrevious, margin); fdFields.right = new FormAttachment(100, -margin); fdFields.bottom = new FormAttachment(100, -margin); tFilterFields.setLayoutData(fdFields); FormData fdFilterFieldsComp = new FormData(); fdFilterFieldsComp.left = new FormAttachment(0, 0); - fdFilterFieldsComp.top = new FormAttachment(0, 0); + fdFilterFieldsComp.top = new FormAttachment(gEntityFilter, 0); fdFilterFieldsComp.right = new FormAttachment(100, 0); fdFilterFieldsComp.bottom = new FormAttachment(100, 0); gEntityFilter.setLayoutData(fdFilterFieldsComp); @@ -538,11 +623,93 @@ public void shellClosed(ShellEvent e) { return stepname; } - protected void getEntityFields() { - super.getEntityFields(); - tFilterFields.removeAll(); - tFilterFields.setRowNums(); - tFilterFields.optWidth(true); + protected void updatePreviousFields() { + try { + prevMetaFields = transMeta.getPrevStepFields(stepname); + + if (prevMetaFields != null && !prevMetaFields.isEmpty()) { + prevFields = prevMetaFields.getFieldNames(); + } else { + prevFields = new String[0]; + } + /* + int nrKeys = tFilterFields.nrNonEmpty(); + for (int i = 0; i < nrKeys; i++) { + TableItem item = tFilterFields.getNonEmpty(i); + String field = item.getText(1); + item.setText(3, ""); + if (prevFields.length >0 && field != null && !field.equals("")) { + for (int t = 0; t < prevFields.length; t++) { + if (field.equalsIgnoreCase(prevFields[t])) { + item.setText(3, field); + break; + } + } + } + } + */ + } catch (KettleStepException e) { + e.printStackTrace(); + } + prevFieldColumn.setComboValues(prevFields); + } + + protected boolean getEntityFields() { + try { + if (!super.getEntityFields()) { + return false; + } + + tFilterFields.clearAll(); + + int nrKeys = comboFieldList.length; + for (int i = 0; i < nrKeys; i++) { + TableItem filterItem = new TableItem(tFilterFields.table, SWT.NONE); + filterItem.setText(1, comboFieldList[i]); + } + tFilterFields.removeEmptyRows(); + + this.comboFilterFields = this.comboFieldList; + + filterFieldsColumn.setComboValues(this.comboFilterFields); + + prevMetaFields = transMeta.getPrevStepFields(stepname); + + if (prevMetaFields != null && !prevMetaFields.isEmpty()) { + prevFields = prevMetaFields.getFieldNames(); + prevFieldColumn.setComboValues(prevFields); + + nrKeys = tFilterFields.nrNonEmpty(); + for (int i = 0; i < nrKeys; i++) { + TableItem item = tFilterFields.getNonEmpty(i); + String field = item.getText(1); + item.setText(2, "="); + item.setText(3, ""); + if (field != null && !field.equals("")) { + for (int t = 0; t < prevFields.length; t++) { + if (field.equalsIgnoreCase(prevFields[t])) { + item.setText(3, field); + break; + } + } + } + } + } else { + prevFields = new String[0]; + nrKeys = tFilterFields.nrNonEmpty(); + for (int i = 0; i < nrKeys; i++) { + TableItem item = tFilterFields.getNonEmpty(i); + item.setText(2, ""); + } + } + + tFilterFields.setRowNums(); + tFilterFields.optWidth(true); + } catch (Exception e) { + new ErrorDialog(shell, BaseMessages.getString(PKG, "CiviCrmStep.Error.EntityListError"), e.toString().split(":")[0], e); //$NON-NLS-1$ //$NON-NLS-2$ + logBasic(BaseMessages.getString(PKG, "CiviCrmStep.Error.APIExecError", e.toString())); + } + return true; } /* @@ -562,22 +729,33 @@ public void getData() { wCiviCrmPageSize.setText(((CiviInputMeta) input).getCiviCrmPageSize().toString()); } - if (((CiviInputMeta) input).getFields() != null) { - - if (((CiviInputMeta) input).getFilterMap() != null) { + if (((CiviInputMeta) input).getCiviCrmFields() != null && ((CiviInputMeta) input).getCiviCrmFields().size() > 0) { + ArrayList opList = ((CiviInputMeta) input).getCiviCrmFilterOperator(); + if (((CiviInputMeta) input).getCiviCrmFilterMap() != null) { // Si hay elementos para filtrar entonces mostrarlos en la tabla int i = 0; - for (String cFilter : ((CiviInputMeta) input).getFilterList()) { - TableItem item = tFilterFields.table.getItem(i); - item.setText(1, cFilter); - item.setText(2, ((CiviInputMeta) input).getFilterMap().get(cFilter)); - i++; + if (((CiviInputMeta) input).getCiviCrmFilterList().size() > 0) { + for (String cFilter : ((CiviInputMeta) input).getCiviCrmFilterList()) { + TableItem item = new TableItem(tFilterFields.table, SWT.NONE); + item.setText(1, cFilter); + String op = (i >= opList.size()) ? "=" : opList.get(i); + item.setText(2, op); + String filterValue = ((CiviInputMeta) input).getCiviCrmFilterMap().get(cFilter); + item.setText(3, (filterValue != null) ? filterValue : ""); + i++; + } } } } - this.filterFieldsColumn.setComboValues(this.comboFieldList); +// this.prevFields = ((CiviInputMeta) input).getCiviCrmPrevFields().toArray(this.prevFields); +// this.prevFieldColumn.setComboValues(this.prevFields); + this.operatorFieldColumn.setComboValues(new String[] { "=", "<", ">", "LIKE", "NOT LIKE" }); + this.filterFieldsColumn.setComboValues(this.comboFieldList); + + updatePreviousFields(); + tFilterFields.removeEmptyRows(); tFilterFields.setRowNums(); tFilterFields.optWidth(true); @@ -594,9 +772,7 @@ public void getData() { protected boolean ok() { int nrKeys = tOutputFields.nrNonEmpty(); - boolean matchFields = true; - HashMap fields = ((CiviMeta) input).getFields(); ArrayList keyList = new ArrayList(); ArrayList filterList = new ArrayList(); @@ -607,132 +783,148 @@ protected boolean ok() { // Verificamos que los elementos de salida siempre tengan un campo // seleccionado y luego si no hay un alias le ponemos el mismo nombre del // campo - - if (item.getText(1) != null && !item.getText(1).equals("")) { - String fieldKey = item.getText(1); - matchFields = (fields.get(fieldKey) != null); - if (!matchFields) { - String msg = ""; - msg = BaseMessages.getString(PKG, "CiviCrmStep.Error.FieldNotMatch") - .replace("$1", fieldKey) - .replace("$2", activeEntity); - Exception e = new Exception(); - new ErrorDialog(shell, BaseMessages.getString(PKG, "CiviCrmStep.Error.UnableFindField"), msg, e); - break; - } + if (item.getText(1) != null && !item.getText(1).equals("")) { keyList.add(item.getText(1)); hOutput.put(item.getText(1), (item.getText(2) != null && !item.getText(2).equals("")) ? item.getText(2) : item.getText(1)); } } - HashMap hFilter = new HashMap (); - if (matchFields) { - nrKeys = tFilterFields.nrNonEmpty(); - for (int i = 0; i < nrKeys; i++) { - TableItem item = tFilterFields.getNonEmpty(i); + tFilterFields.removeEmptyRows(); + HashMap hFilter = new HashMap(); + ArrayList fOperatorList = new ArrayList(); + nrKeys = tFilterFields.nrNonEmpty(); + for (int i = 0; i < nrKeys; i++) { + TableItem item = tFilterFields.getNonEmpty(i); - String fieldKey = item.getText(1); - matchFields = (fields.get(fieldKey) != null); - - if (!matchFields) { - String msg = ""; - msg = BaseMessages.getString(PKG, "CiviCrmStep.Error.FieldNotMatch") - .replace("$1", fieldKey) - .replace("$2", activeEntity); - Exception e = new Exception(); - new ErrorDialog(shell, BaseMessages.getString(PKG, "CiviCrmStep.Error.UnableFindField"), msg, e); - break; - } + String fieldKey = item.getText(1); + filterList.add(fieldKey); + fOperatorList.add(item.getText(2).equals("") || ("<>=NOT LIKE".indexOf(item.getText(2)) == -1) ? "=" : item.getText(2)); + hFilter.put(item.getText(1), item.getText(3)); + } + stepname = wStepname.getText(); - filterList.add(fieldKey); - hFilter.put(item.getText(1), item.getText(2)); - } + // Datos de la conexion + try { + ((CiviInputMeta) input).setCiviCrmPageSize(Integer.parseInt(wCiviCrmPageSize.getText())); + } catch (NumberFormatException e) { + ((CiviInputMeta) input).setCiviCrmPageSize(25); } - if (matchFields) { - stepname = wStepname.getText(); - ((CiviInputMeta) input).setCiviCrmRestUrl(wCiviCrmRestUrl.getText()); - ((CiviInputMeta) input).setCiviCrmApiKey(wCiviCrmApiKey.getText()); - ((CiviInputMeta) input).setCiviCrmSiteKey(wCiviCrmSiteKey.getText()); - ((CiviInputMeta) input).setCiviCrmEntity(wCiviCrmEntity.getText()); + ((CiviInputMeta) input).setCiviCrmRestUrl(wCiviCrmRestUrl.getText()); + ((CiviInputMeta) input).setCiviCrmApiKey(wCiviCrmApiKey.getText()); + ((CiviInputMeta) input).setCiviCrmSiteKey(wCiviCrmSiteKey.getText()); + ((CiviInputMeta) input).setCiviCrmEntity(wCiviCrmEntity.getText()); - try { - ((CiviInputMeta)input).setCiviCrmPageSize(Integer.parseInt(wCiviCrmPageSize.getText())); - } catch (NumberFormatException e) { - ((CiviInputMeta)input).setCiviCrmPageSize(25); - } + // Datos para depuracion + ((CiviInputMeta) input).setCiviCrmResultField(wCiviCrmResultField.getText()); + ((CiviInputMeta) input).setCiviCrmDebugMode(wCiviCrmDebugMode.getSelection()); - ((CiviInputMeta) input).setFilterList(filterList); - ((CiviInputMeta) input).setKeyList(keyList); - ((CiviInputMeta) input).setOutputMap(hOutput); - ((CiviInputMeta)input).setFilterMap(hFilter); - dispose(); - return true; - } + // Datos para los filtros a usar en las llamadas al API de CIVICRM + ((CiviInputMeta) input).setCiviCrmFilterMap(hFilter); - return false; - } - - protected void preview() { - // Create the table input reader step... - CiviInputMeta inputMeta = new CiviInputMeta(); - inputMeta.setCiviCrmRestUrl(wCiviCrmRestUrl.getText()); - inputMeta.setCiviCrmApiKey(wCiviCrmApiKey.getText()); - inputMeta.setCiviCrmSiteKey(wCiviCrmSiteKey.getText()); - inputMeta.setCiviCrmEntity(wCiviCrmEntity.getText()); + // Chequeamos si se ha desvinculado el paso del anterior, de ser así pasamos un arr try { - inputMeta.setCiviCrmPageSize(Integer.parseInt(wCiviCrmPageSize.getText())); - } catch (NumberFormatException e) { - // Valor por defecto - inputMeta.setCiviCrmPageSize(25); + if (transMeta.getPrevStepFields(stepname) != null && !transMeta.getPrevStepFields(stepname).isEmpty()) { + ((CiviInputMeta) input).setCiviCrmPrevFields(new ArrayList(Arrays.asList(prevFields))); + ((CiviInputMeta) input).setHasPreviousStep(true); + } else { + ((CiviInputMeta) input).setCiviCrmPrevFields(new ArrayList()); + ((CiviInputMeta) input).setHasPreviousStep(false); + } + } catch (KettleStepException e) { + e.printStackTrace(); } + + ((CiviInputMeta) input).setCiviCrmFilterOperator(fOperatorList); + ((CiviInputMeta) input).setCiviCrmFilterList(filterList); - try { - String restUrl = variables.environmentSubstitute(wCiviCrmRestUrl.getText()); - String apiKey = variables.environmentSubstitute(wCiviCrmApiKey.getText()); - String siteKey = variables.environmentSubstitute(wCiviCrmSiteKey.getText()); - // String entity = wCiviCrmEntity.getText()); - - RestUtil crUtil = new RestUtil(restUrl, apiKey, siteKey, wCiviCrmEntity.getText()); - - HashMap lFields = crUtil.getFieldLists(true); - inputMeta.setFields(lFields); + // Datos con los campos de salida del paso + ((CiviInputMeta) input).setCiviCrmKeyList(keyList); + ((CiviInputMeta) input).setCiviCrmOutputMap(hOutput); + ((CiviInputMeta) input).setCiviCrmFields(civiCrmFields); - int nrKeys = tOutputFields.nrNonEmpty(); + dispose(); - if (nrKeys == 0) { - throw new Exception(BaseMessages.getString(PKG, "CiviCrmStep.Exception.NoFieldsSelected")); - } + return true; + } - HashMap hOutput = new HashMap(); + protected void preview() { + // Create the table input reader step... + HashMap hFilter = new HashMap(); + ArrayList fOperatorList = new ArrayList(); + ArrayList keyList = new ArrayList(); + ArrayList filterList = new ArrayList(); + HashMap hOutput = new HashMap(); + + HashMap cloneFields = (HashMap)civiCrmFields.clone(); + + + int nrKeys = tOutputFields.nrNonEmpty(); + for (int i = 0; i < nrKeys; i++) { + TableItem item = tOutputFields.getNonEmpty(i); + // Verificamos que los elementos de salida siempre tengan un campo + // seleccionado y luego si no hay un alias le ponemos el mismo nombre del + // campo - for (int i = 0; i < nrKeys; i++) { - TableItem item = tOutputFields.getNonEmpty(i); - if (item.getText(1) != null && !item.getText(1).equals("")) { - inputMeta.getKeyList().add(item.getText(1)); - hOutput.put(item.getText(1), (item.getText(2) != null && !item.getText(2).equals("")) ? item.getText(2) : item.getText(1)); + if (item.getText(1) != null && !item.getText(1).equals("")) { + String fieldKey = item.getText(1); + // Actualizando la lista de campos, cuando un campo no exista en la lista + // entonces se crea y su tipo predeterminado es String (2) + if (!cloneFields.containsKey(fieldKey)) { + FieldAttrs field = new FieldAttrs(); + field.setfFieldKey(fieldKey); + field.setfType("2"); + cloneFields.put(fieldKey, field); } + + keyList.add(item.getText(1)); + hOutput.put(item.getText(1), (item.getText(2) != null && !item.getText(2).equals("")) ? item.getText(2) : item.getText(1)); } + } - inputMeta.setOutputMap(hOutput); + nrKeys = tFilterFields.nrNonEmpty(); + for (int i = 0; i < nrKeys; i++) { + TableItem item = tFilterFields.getNonEmpty(i); - nrKeys = tFilterFields.nrNonEmpty(); + String fieldKey = item.getText(1); - HashMap hFilter = new HashMap(); - for (int i = 0; i < nrKeys; i++) { - TableItem item = tFilterFields.getNonEmpty(i); - hFilter.put(item.getText(1), item.getText(2)); + filterList.add(fieldKey); +// try { +// fOperatorList.add(item.getText(2).equals("") || ("<>=NOT LIKE".indexOf(item.getText(2)) == -1) ? "=" : (item.getText(2).toLowerCase().contains("like") ? URLEncoder.encode((String) item.getText(2), "UTF-8") : item.getText(2))); + fOperatorList.add(item.getText(2).equals("") || ("<>=NOT LIKE".indexOf(item.getText(2)) == -1) ? "=" : item.getText(2)); +// } catch (UnsupportedEncodingException e1) { +// e1.printStackTrace(); +// } + try { + hFilter.put(item.getText(1), item.getText(3).toLowerCase().contains("like") ? URLEncoder.encode((String) item.getText(3), "UTF-8") : item.getText(3)); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); } + } - inputMeta.setFilterMap(hFilter); + CiviInputMeta inputMeta = new CiviInputMeta(); + inputMeta.setCiviCrmRestUrl(wCiviCrmRestUrl.getText()); + inputMeta.setCiviCrmApiKey(wCiviCrmApiKey.getText()); + inputMeta.setCiviCrmSiteKey(wCiviCrmSiteKey.getText()); + inputMeta.setCiviCrmEntity(wCiviCrmEntity.getText()); + inputMeta.setCiviCrmResultField(wCiviCrmResultField.getText()); + inputMeta.setCiviCrmDebugMode(wCiviCrmDebugMode.getSelection()); + inputMeta.setCiviCrmFields(cloneFields); + inputMeta.setCiviCrmKeyList(keyList); + inputMeta.setCiviCrmFilterList(filterList); + inputMeta.setCiviCrmFilterOperator(fOperatorList); + inputMeta.setCiviCrmOutputMap(hOutput); + inputMeta.setCiviCrmFilterMap(hFilter); + try { TransMeta previewMeta = TransPreviewFactory.generatePreviewTransformation(transMeta, inputMeta, wStepname.getText()); - EnterNumberDialog numberDialog = new EnterNumberDialog(shell, props.getDefaultPreviewSize(), BaseMessages.getString(PKG, + EnterNumberDialog numberDialog = new EnterNumberDialog(shell, Integer.parseInt(wCiviCrmPageSize.getText()), BaseMessages.getString(PKG, "CiviCrmDialog.Preview.Title"), BaseMessages.getString(PKG, "CiviCrmDialog.Preview.NumberOfRowsToPreview")); //$NON-NLS-1$ //$NON-NLS-2$ int previewSize = numberDialog.open(); if (previewSize > 0) { + inputMeta.setCiviCrmPageSize(previewSize); TransPreviewProgressDialog progressDialog = new TransPreviewProgressDialog(shell, previewMeta, new String[] { wStepname.getText() }, new int[] { previewSize }); progressDialog.open(); @@ -758,4 +950,5 @@ protected void preview() { new ErrorDialog(shell, BaseMessages.getString(PKG, "System.Dialog.PreviewError.Title"), e.toString().split(":")[0], e); } } + } diff --git a/src/main/CiviCRMInput/src/es/stratebi/civi/input/CiviInputMeta.java b/src/main/CiviCRMInput/src/es/stratebi/civi/input/CiviInputMeta.java index 64d75fa..506072a 100644 --- a/src/main/CiviCRMInput/src/es/stratebi/civi/input/CiviInputMeta.java +++ b/src/main/CiviCRMInput/src/es/stratebi/civi/input/CiviInputMeta.java @@ -1,5 +1,8 @@ package es.stratebi.civi.input; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -12,6 +15,10 @@ import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.exception.KettleValueException; import org.pentaho.di.core.exception.KettleXMLException; +import org.pentaho.di.core.row.RowMetaInterface; +import org.pentaho.di.core.row.ValueMeta; +import org.pentaho.di.core.row.ValueMetaInterface; +import org.pentaho.di.core.variables.VariableSpace; import org.pentaho.di.core.xml.XMLHandler; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.repository.ObjectId; @@ -30,8 +37,11 @@ public class CiviInputMeta extends CiviMeta implements StepMetaInterface { protected Integer civiCrmPageSize; - protected HashMap filterMap = new HashMap(); - protected ArrayList filterList = new ArrayList(); + protected boolean hasPreviousStep = false; + protected HashMap civiCrmFilterMap = new HashMap(); + protected ArrayList civiCrmFilterList = new ArrayList(); + protected ArrayList civiCrmFilterOperator = new ArrayList(); + protected ArrayList civiCrmPrevFields = new ArrayList(); public CiviInputMeta() { super(); @@ -54,9 +64,9 @@ public Object clone() { // field by field copy is default CiviInputMeta retval = (CiviInputMeta) super.clone(); - retval.filterMap = new HashMap(); - for (String kField : filterMap.keySet()) { - retval.filterMap.put(new String(kField), new String(filterMap.get(kField))); + retval.civiCrmFilterMap = new HashMap(); + for (String kField : civiCrmFilterMap.keySet()) { + retval.civiCrmFilterMap.put(new String(kField), new String(civiCrmFilterMap.get(kField))); } return retval; } @@ -73,21 +83,45 @@ public String getXML() throws KettleValueException { StringBuffer retval = new StringBuffer(150); retval.append(xml); - for (String filterKey : filterList) { + retval.append(" ").append(XMLHandler.addTagValue("PageSize", civiCrmPageSize)); + retval.append(" ").append(XMLHandler.addTagValue("hasPreviousStep", Boolean.toString(hasPreviousStep))); + + for (String filterKey : civiCrmFilterList) { retval.append(" ").append(filterKey).append("").append(Const.CR); } retval.append(" ").append(Const.CR); - for (String fKey : filterMap.keySet()) { - retval.append(" ").append(XMLHandler.addTagValue(fKey, filterMap.get(fKey))); + for (String fKey : civiCrmFilterMap.keySet()) { + retval.append(" ").append(XMLHandler.addTagValue(fKey, civiCrmFilterMap.get(fKey))); } retval.append(" ").append(Const.CR); + for (String field : civiCrmPrevFields) { + retval.append(" ").append(field).append("").append(Const.CR); + } + + for (String field : civiCrmFilterOperator) { + try { + retval.append(" ").append(URLEncoder.encode(field, "UTF8")).append("").append(Const.CR); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + return retval.toString(); } - public void loadXML(Node stepnode, List databases, Map counters) throws KettleXMLException { + public void getFields(RowMetaInterface r, String origin, RowMetaInterface[] info, StepMeta nextStep, VariableSpace space) { + super.getFields(r, origin, info, nextStep, space); + + if (civiCrmResultField != null && !civiCrmResultField.equals("")) { + ValueMetaInterface v = new ValueMeta(civiCrmResultField, ValueMetaInterface.TYPE_STRING); + v.setOrigin(origin); + r.addValueMeta(v); + } + } + public void loadXML(Node stepnode, List databases, Map counters) throws KettleXMLException { try { super.loadXML(stepnode, databases, counters); @@ -98,10 +132,12 @@ public void loadXML(Node stepnode, List databases, Map(); + civiCrmFilterList = new ArrayList(); totalNodes = XMLHandler.countNodes(stepnode, "filter-key"); @@ -109,23 +145,53 @@ public void loadXML(Node stepnode, List databases, Map(); + civiCrmFilterMap = new HashMap(); Node fieldNode = XMLHandler.getNodes(stepnode, "filter").get(0); // Iterando por los campos de la clase - for (String f : fields.keySet()) { + for (String f : civiCrmFilterList) { try { // Extrayendo y actualizando el valor del campo String fValue = XMLHandler.getTagValue(fieldNode, f); if (fValue != null) - filterMap.put(f, (fValue != null) ? fValue : ""); + civiCrmFilterMap.put(f, (fValue != null) ? fValue : ""); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } + } + + civiCrmPrevFields = new ArrayList(); + + totalNodes = XMLHandler.countNodes(stepnode, "previous-field"); + + for (int i = 0; i < totalNodes; i++) { + try { + // Extrayendo y actualizando el valor del campo + Node node = XMLHandler.getSubNodeByNr(stepnode, "previous-field", i); + String fieldName = XMLHandler.getNodeValue(node); + civiCrmPrevFields.add(fieldName); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } + } + + civiCrmFilterOperator = new ArrayList(); + + totalNodes = XMLHandler.countNodes(stepnode, "filter-operator"); + + for (int i = 0; i < totalNodes; i++) { + try { + // Extrayendo y actualizando el valor del campo + Node node = XMLHandler.getSubNodeByNr(stepnode, "filter-operator", i); + String fieldName = URLDecoder.decode(XMLHandler.getNodeValue(node), "UTF8"); + civiCrmFilterOperator.add(fieldName); } catch (IllegalArgumentException e) { e.printStackTrace(); } @@ -139,22 +205,37 @@ public void loadXML(Node stepnode, List databases, Map databases, Map counters) throws KettleException { try { super.readRep(rep, id_step, databases, counters); - - civiCrmPageSize = (int) rep.getStepAttributeInteger(id_step, "civiCrmPageSize"); + civiCrmPageSize = (int) rep.getStepAttributeInteger(id_step, "civiCrmPageSize"); + hasPreviousStep = rep.getStepAttributeBoolean(id_step, "civiCrmPageSize"); + + civiCrmFilterList = new ArrayList(); int nFields = rep.countNrStepAttributes(id_step, "filterKey"); for (int i = 0; i < nFields; i++) { String cf = rep.getStepAttributeString(id_step, i, "filterKey"); - filterList.add(cf); + civiCrmFilterList.add(cf); } - filterMap = new HashMap(); + civiCrmFilterMap = new HashMap(); nFields = rep.countNrStepAttributes(id_step, "filter"); for (int i = 0; i < nFields; i++) { String[] cf = rep.getStepAttributeString(id_step, i, "filter").split("="); - filterMap.put(cf[0], cf[1]); + civiCrmFilterMap.put(cf[0], cf[1]); + } + + nFields = rep.countNrStepAttributes(id_step, "prevFields"); + civiCrmPrevFields = new ArrayList(); + for (int i = 0; i < nFields; i++) { + String cf = rep.getStepAttributeString(id_step, i, "prevFields"); + civiCrmPrevFields.add(cf); + } + + nFields = rep.countNrStepAttributes(id_step, "filterOperator"); + civiCrmFilterOperator = new ArrayList(); + for (int i = 0; i < nFields; i++) { + String cf = rep.getStepAttributeString(id_step, i, "filterOperator"); + civiCrmFilterOperator.add(cf); } - } catch (Exception e) { throw new KettleException(BaseMessages.getString(PKG, "CiviCrmStep.Exception.UnexpectedErrorInReadingStepInfo"), e); } @@ -163,17 +244,30 @@ public void readRep(Repository rep, ObjectId id_step, List databas public void saveRep(Repository rep, ObjectId id_transformation, ObjectId id_step) throws KettleException { try { super.saveRep(rep, id_transformation, id_step); - - rep.saveStepAttribute(id_transformation, id_step, "civiCrmPageSize", civiCrmPageSize); + rep.saveStepAttribute(id_transformation, id_step, "civiCrmPageSize", civiCrmPageSize); + rep.saveStepAttribute(id_transformation, id_step, "hasPreviousStep", hasPreviousStep); + + int i = 0; - for (String filterKey : filterList) { + for (String filterKey : civiCrmFilterList) { rep.saveStepAttribute(id_transformation, id_step, i++, "filterKey", filterKey); } i = 0; - for (String filterField : filterMap.keySet()) { - rep.saveStepAttribute(id_transformation, id_step, i++, "filter", filterField + "=" + filterMap.get(filterField)); + for (String filterField : civiCrmFilterMap.keySet()) { + rep.saveStepAttribute(id_transformation, id_step, i++, "filter", filterField + "=" + civiCrmFilterMap.get(filterField)); + } + + i = 0; + for (String previousField : civiCrmPrevFields) { + rep.saveStepAttribute(id_transformation, id_step, i++, "previousField", previousField); + } + + + i = 0; + for (String filterOperator : civiCrmFilterOperator) { + rep.saveStepAttribute(id_transformation, id_step, i++, "filterOperator", filterOperator); } } catch (Exception e) { throw new KettleException(BaseMessages.getString(PKG, "CiviCrmStep.Exception.UnableToSaveStepInfoToRepository") + id_step, e); @@ -188,20 +282,20 @@ protected void setCiviCrmPageSize(Integer civiCrmPageSize) { this.civiCrmPageSize = civiCrmPageSize; } - protected HashMap getFilterMap() { - return filterMap; + protected HashMap getCiviCrmFilterMap() { + return civiCrmFilterMap; } - protected void setFilterMap(HashMap filterMap) { - this.filterMap = filterMap; + protected void setCiviCrmFilterMap(HashMap filterMap) { + this.civiCrmFilterMap = filterMap; } - protected ArrayList getFilterList() { - return filterList; + protected ArrayList getCiviCrmFilterList() { + return civiCrmFilterList; } - protected void setFilterList(ArrayList filterList) { - this.filterList = filterList; + protected void setCiviCrmFilterList(ArrayList filterList) { + this.civiCrmFilterList = filterList; } public StepDialogInterface getDialog(Shell shell, StepMetaInterface meta, TransMeta transMeta, String name) { @@ -216,4 +310,28 @@ public StepDataInterface getStepData() { return new CiviInputData(); } + protected ArrayList getCiviCrmPrevFields() { + return civiCrmPrevFields; + } + + protected void setCiviCrmPrevFields(ArrayList prevFields) { + this.civiCrmPrevFields = prevFields; + } + + protected ArrayList getCiviCrmFilterOperator() { + return civiCrmFilterOperator; + } + + protected void setCiviCrmFilterOperator(ArrayList civiCrmFilterOperator) { + this.civiCrmFilterOperator = civiCrmFilterOperator; + } + + protected boolean hasPreviousStep() { + return hasPreviousStep; + } + + protected void setHasPreviousStep(boolean hasPreviousStep) { + this.hasPreviousStep = hasPreviousStep; + } + } diff --git a/src/main/CiviCRMInput/src/es/stratebi/civi/input/CiviInputStep.java b/src/main/CiviCRMInput/src/es/stratebi/civi/input/CiviInputStep.java index 04171c6..6cb43c5 100644 --- a/src/main/CiviCRMInput/src/es/stratebi/civi/input/CiviInputStep.java +++ b/src/main/CiviCRMInput/src/es/stratebi/civi/input/CiviInputStep.java @@ -1,12 +1,16 @@ package es.stratebi.civi.input; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.json.JSONObject; import org.pentaho.di.core.exception.KettleException; +import org.pentaho.di.core.row.RowDataUtil; import org.pentaho.di.core.row.RowMeta; +import org.pentaho.di.core.row.RowMetaInterface; import org.pentaho.di.core.row.ValueMetaInterface; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.trans.Trans; @@ -21,7 +25,6 @@ import es.stratebi.civi.util.RestUtil; /* - * * * Esta es la clase principal y es la que lleva la logica del plugin, tiene un metodo init llamado * al inicio para definir los valores de inicializacion del paso y luego internamente en la clase @@ -33,6 +36,9 @@ public class CiviInputStep extends CiviStep implements StepInterface { private RestUtil crUtil; + private boolean isSending = false; + private boolean hasPreviousStep = false; + private Object[] previousData; public CiviInputStep(StepMeta s, StepDataInterface stepDataInterface, int c, TransMeta t, Trans dis) { super(s, stepDataInterface, c, t, dis); @@ -50,72 +56,126 @@ public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws K civiData = (CiviInputData) sdi; if (first) { - // first = false; - - // Inicializamos el objeto para enviar los datos hacia el otro paso - ((CiviInputData) civiData).outputRowMeta = new RowMeta(); - - /* - * Aqui se obtiene un listado de los campos y sus tipos de datos para sus conversiones. - * El truco radica en que quien procesa aqui es la clase que definimos para implementar - * la intefaz StepDataInterface, o sea esta clase es actualizada con los valores que - * hemos definido en el dialogo y han sido almacenados en la clase que implementa - * StepMetaInterface en nuestro caso es CiviInputMeta. - */ - ((CiviInputMeta) civiMeta).getFields(((CiviInputData) civiData).outputRowMeta, getStepname(), null, null, this); - - // stores the indices where to look for the key fields in the input rows - ((CiviInputData) civiData).keyFields = new HashMap(); - ((CiviInputData) civiData).conversionMeta = new ValueMetaInterface[((CiviInputMeta) civiMeta).getFields().values().size()]; - List metaList = ((CiviInputData) civiData).outputRowMeta.getValueMetaList(); - int i = 0; - for (ValueMetaInterface metaInterface : metaList) { - ValueMetaInterface returnMeta = metaInterface; - - ValueMetaInterface conversionMeta = returnMeta.clone(); - ((CiviInputData) civiData).conversionMeta[i] = conversionMeta; - i++; + if (((CiviInputMeta) civiMeta).hasPreviousStep() && !this.isSending) { + this.previousData = getRow(); + crUtil.setOffset(0); + if (this.previousData == null) { + setOutputDone(); + return false; } + isSending = true; + } + + /* + * Si existe un paso anterior entonces tomamos los metadatos en la + * variable y ponemos el campo hasPrevious en true para procesar los datos + * antes de llamar al API de CiviCRM + */ + if (getInputRowMeta() != null) { + ((CiviInputData) civiData).previousRowMeta = (RowMetaInterface) getInputRowMeta().clone(); + this.hasPreviousStep = true; + } + + /* + * Inicializamos el objeto para enviar los datos hacia el otro paso, no + * tomamos los datos del metadata que le precede + */ + ((CiviInputData) civiData).outputRowMeta = new RowMeta(); + + /* + * Aqui se obtiene un listado de los campos y sus tipos de datos para sus + * conversiones. El truco radica en que quien procesa aqui es la clase que + * definimos para implementar la intefaz StepDataInterface, o sea esta + * clase es actualizada con los valores que hemos definido en el dialogo y + * han sido almacenados en la clase que implementa StepMetaInterface en + * nuestro caso es CiviInputMeta. + */ + ((CiviInputMeta) civiMeta).getFields(((CiviInputData) civiData).outputRowMeta, getStepname(), null, null, this); + // stores the indices where to look for the key fields in the input rows + ((CiviInputData) civiData).keyFields = new HashMap(); + List metaList = ((CiviInputData) civiData).outputRowMeta.getValueMetaList(); + ((CiviInputData) civiData).conversionMeta = new ValueMetaInterface[metaList.size()]; + int i = 0; + for (ValueMetaInterface metaInterface : metaList) { + ValueMetaInterface returnMeta = metaInterface; - /** - * Aqui deberiamos definir las conversiones dinamicamente sobre los tipos pero no lo he - * entendido bien. Para eso definimos en util La clase CiviFieldType para mapear los - * tipos de datos de CIVICRM contra los de Kettle y usando el API de reflection de JAVA - * se asigna. Actualmente los tengo todos como STRING - */ + ValueMetaInterface conversionMeta = returnMeta.clone(); + ((CiviInputData) civiData).conversionMeta[i] = conversionMeta; + i++; + } } /* - * Buscar los datos de la fila que enviamos hacia el paso siguiente, si no hay mas datos - * entonces finalizamos el paso y retornamos false para que siga la transformaci�n + * Buscar los datos del paso previo si existese y se han terminado de + * procesar los datos obtenidos de la llamada realizada para de la fila + * obtenida del paso anterior y generar la fila que enviamos hacia el paso + * siguiente, si no hay mas datos entonces finalizamos el paso y retornamos + * false para que siga la transformacion */ - Object[] outputRowData = readOneRow(); - if (outputRowData == null) { - setOutputDone(); // Finalizamos pues ya no hay mas filas - return false; // para procesar. + + Object[] outputRowData = null; + if (this.hasPreviousStep) { + if (!first) { + if (!this.isSending) { + this.previousData = getRow(); + crUtil.setOffset(0); + if (this.previousData == null) { + setOutputDone(); + return false; + } + // isSending = true; + } + } + String[] fieldNames = getInputRowMeta().getFieldNames(); + outputRowData = readOneRow(fieldNames, this.previousData); + + isSending = (outputRowData != null); + } else { + outputRowData = readOneRow(); + if (outputRowData == null) { + setOutputDone(); // Finalizamos pues ya no hay mas filas para procesar + return false; + } } - // Aqui convertimos a la cadena parte del JSON con el valor del campo al tipo que le pertenece - int i = 0; - List metaList = ((CiviInputData) civiData).outputRowMeta.getValueMetaList(); - for (String outputField : ((CiviInputMeta) civiMeta).getKeyList()) { + if (first) + first = false; + + if (outputRowData != null) { + // Aqui convertimos a la cadena parte del JSON con el valor del campo al + // tipo que le pertenece + int i = 0; + List metaList = ((CiviInputData) civiData).outputRowMeta.getValueMetaList(); + for (String outputField : ((CiviInputMeta) civiMeta).getCiviCrmKeyList()) { try { - Object value = getObjectValue(outputField, (String) outputRowData[i]); - outputRowData[i] = metaList.get(i).convertData(((CiviInputData) civiData).conversionMeta[i], value); + Object value = getObjectValue(outputField, (String) outputRowData[i]); + outputRowData[i] = metaList.get(i).convertData(((CiviInputData) civiData).conversionMeta[i], value); } catch (Exception e) { - e.printStackTrace(); + e.printStackTrace(); } i++; - } - // Enviando la salida hacia el paso que sigue. - putRow(((CiviInputData) civiData).outputRowMeta, outputRowData); + } - /* - * No estoy haciendo los logs aun, debo enviar esos datos mas adelante. Debo aclara esta - * parte - */ - // if (checkFeedback(getLinesInput())) logBasic(BaseMessages.getString(PKG, "FixedInput.Log.LineNumber", Long.toString(getLinesInput()))); //$NON-NLS-1$ + // Add the constant data to the end of the row. + RowMetaInterface rowMeta = null; + Object[] rowData = null; + if (hasPreviousStep) { + rowMeta = ((CiviInputData) civiData).previousRowMeta.clone(); + rowMeta.mergeRowMeta(((CiviInputData) civiData).outputRowMeta); + rowData = RowDataUtil.addRowData(previousData, getInputRowMeta().size(), outputRowData); + } else { + rowMeta = ((CiviInputData) civiData).outputRowMeta; + rowData = outputRowData; + } + + putRow(rowMeta, rowData); + // Enviando la salida hacia el paso que sigue. + // putRow(((CiviInputData) civiData).outputRowMeta, outputRowData); + + if (checkFeedback(getLinesInput())) + logBasic(BaseMessages.getString(PKG, "CiviCrmStep.Msg.LinesReaded", Long.toString(getLinesRead()))); + } return true; } @@ -123,13 +183,16 @@ public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws K * Leemos solo una fila de la lista y la devolvemos para que sea enviada hacia * el paso siguiente Deberiamos hacer las conversiones de tipo aqui, pero debo * analizar esta parte, de momento todo es tratado como String + * + * @param inData + * @param fieldNames */ - protected Object[] readOneRow() throws KettleException { + protected Object[] readOneRow(String[] fieldNames, Object[] inData) throws KettleException { ArrayList outputRow = new ArrayList(); /* * Estos es para iterar y buscar nuevos datos de CIVICRM, la idea es - * deopsitar el resultado de cada llamada en un array y devolver siempre + * deopsitar el resultado de cada llamada en un arreglo y devolver siempre * el primero y luego eliminarlo de la lista asi garantizamos que no estemos * leyendo duplicados y no colapse el sistema por falta de memoria. */ @@ -140,12 +203,45 @@ protected Object[] readOneRow() throws KettleException { * sean aplicados a la llamada devolviendo lo que necesitamos */ String options = ""; - for (String kField : ((CiviInputMeta) civiMeta).getFilterMap().keySet()) { - String oValue = ((CiviInputMeta) civiMeta).getFilterMap().get(kField); - if (oValue != null && !oValue.equals("")) - options = options + "&" + kField + "=" + oValue; + int index = 0; + boolean isFilterField = false; + for (String filterField : ((CiviInputMeta) civiMeta).getCiviCrmFilterList()) { + isFilterField = false; + String oValue = ((CiviInputMeta) civiMeta).getCiviCrmFilterOperator().get(index); + String filterFieldValue = ((CiviInputMeta) civiMeta).getCiviCrmFilterMap().get(filterField); + if (oValue != null && !oValue.equals("") && filterFieldValue != null && !filterFieldValue.equals("")) { + oValue = oValue.trim(); + for (int i = 0; i < fieldNames.length; i++) { + // Buscando el campo dentro del flujo de campos de entrada al paso + if (fieldNames[i].equals(filterFieldValue)) { + try { + options = options + "&" + filterField + (oValue.equals("=") ? "=" : "[" + (oValue.toLowerCase().contains("like") ? URLEncoder.encode((String) oValue, "UTF-8") : oValue) + "]=") + + (oValue.toLowerCase().contains("like") ? URLEncoder.encode((String) inData[i], "UTF-8") : inData[i]); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + isFilterField = true; + break; + } + } + if (!isFilterField) { + // El usuario introdujo un valor que no es un nombre de campo + options = options + "&" + filterField + oValue + filterFieldValue; + } + } } + + String fields = ""; + for (String kField : ((CiviInputMeta) civiMeta).getCiviCrmKeyList()) { + fields = fields + (fields.equals("") ? "" : ",") + kField; + } + + if (!fields.equals("")) { + options = options + "return=" + fields; + } + crUtil.setLimit(((CiviInputMeta) civiMeta).getCiviCrmPageSize()); + crUtil.setDebug(((CiviInputMeta) civiMeta).getCiviCrmDebugMode()); crUtil.setOptions(options); /* @@ -153,18 +249,26 @@ protected Object[] readOneRow() throws KettleException { * a retornar por lo que siempre se hace una llamada de mas */ try { - if (first && ((CiviInputMeta) civiMeta).getCiviCrmPageSize() == 0) { + if ((first || !isSending) && ((CiviInputMeta) civiMeta).getCiviCrmPageSize() == 0) { // Si es la primera y no hay limites en el tamaño del resultado // obtener todos ((CiviInputData) civiData).jsonBuffer = crUtil.getNextValues(); + if (log.isRowLevel()) { + logRowlevel("Call no limit url\n\t\t" + crUtil.getCallUrl()); + } } else if (((CiviInputMeta) civiMeta).getCiviCrmPageSize() != 0) { // Si hay limites en el tamaño del resultado obtener todos ((CiviInputData) civiData).jsonBuffer = crUtil.getNextValues(); + if (log.isRowLevel()) { + logRowlevel("Call page url\n\t\t" + crUtil.getCallUrl()); + } } + // Some basic logging first = false; } catch (Exception e) { logError("Error \n" + BaseMessages.getString(PKG, "CiviCrmStep.Error.APIExecError", e.toString())); - throw new KettleException(BaseMessages.getString(PKG, "CiviCrmStep.Error.InputData"), new Exception(BaseMessages.getString(PKG, "CiviCrmStep.Error.ErrorTitle"))); + throw new KettleException(BaseMessages.getString(PKG, "CiviCrmStep.Error.InputData"), new Exception(BaseMessages.getString(PKG, + "CiviCrmStep.Error.ErrorTitle"))); } /* @@ -175,25 +279,152 @@ protected Object[] readOneRow() throws KettleException { return null; } - JSONObject jsonValue = ((JSONString) ((CiviInputData) civiData).jsonBuffer.get(0)).jsonObject; + Object jsonValue = ((JSONString) ((CiviInputData) civiData).jsonBuffer.get(0)).jsonObject; + String resultField = environmentSubstitute(((CiviInputMeta) civiMeta).getCiviCrmResultField()); String fieldValue = ""; - for (String outputField : ((CiviInputMeta) civiMeta).getKeyList()) { + for (String outputField : ((CiviInputMeta) civiMeta).getCiviCrmKeyList()) { fieldValue = ""; try { - fieldValue = jsonValue.get(outputField).toString(); + if (jsonValue.getClass().getSimpleName().equals("JSONObject")) + fieldValue = ((JSONObject) jsonValue).get(outputField).toString(); + else + fieldValue = jsonValue.toString(); + } catch (Exception e) { } finally { outputRow.add(fieldValue); } } ((CiviInputData) civiData).jsonBuffer.remove(0); + if (resultField != null && !resultField.equals("")) { + if (log.isRowLevel()) { + logRowlevel("JSON: " + jsonValue); + } + outputRow.add(jsonValue.toString()); + } return outputRow.toArray(); } + /** + * Leemos solo una fila de la lista y la devolvemos para que sea enviada hacia + * el paso siguiente Deberiamos hacer las conversiones de tipo aqui, pero debo + * analizar esta parte, de momento todo es tratado como String + */ + protected Object[] readOneRow() throws KettleException { + + ArrayList outputRow = new ArrayList(); + /* + * Estos es para iterar y buscar nuevos datos de CIVICRM, la idea es + * depositar el resultado de cada llamada en un arreglo y devolver siempre + * el primero y luego eliminarlo de la lista asi garantizamos que no estemos + * leyendo duplicados y no colapse el sistema por falta de memoria. + */ + + if (((CiviInputData) civiData).jsonBuffer.size() == 0) { + // Si no hay limites en el tamaño del resultado y se llego al final + // entonces retornar null + if (!first && ((CiviInputMeta) civiMeta).getCiviCrmPageSize() == 0) { + return null; + } + + /* + * Definimos los valores a establecer en los filtros y lo pasamos para que + * sean aplicados a la llamada devolviendo lo que necesitamos + */ + + String options = ""; + int index = 0; + for (String kField : ((CiviInputMeta) civiMeta).getCiviCrmFilterList()) { + String oValue = ((CiviInputMeta) civiMeta).getCiviCrmFilterMap().get(kField); + if (oValue != null && !oValue.equals("")) { + String op = ((CiviInputMeta) civiMeta).getCiviCrmFilterOperator().get(index).trim(); + try { + options = options + "&" + kField + ((op.equals("") || op.trim().equals("=")) ? "=" : "[" + (op.toLowerCase().contains("like") ? URLEncoder.encode((String) op, "UTF-8") : op) + "]=") + + (op.toLowerCase().contains("like") ? URLEncoder.encode((String) oValue, "UTF-8") : oValue); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + index++; + } + + String fields = ""; + for (String kField : ((CiviInputMeta) civiMeta).getCiviCrmKeyList()) { + fields = fields + (fields.equals("") ? "" : ",") + kField; + } + + if (!fields.equals("")) { + options = options + "&return=" + fields; + } + + crUtil.setLimit(((CiviInputMeta) civiMeta).getCiviCrmPageSize()); + crUtil.setDebug(((CiviInputMeta) civiMeta).getCiviCrmDebugMode()); + crUtil.setOptions(options); + + /* + * Deberiamos tener un contador pero no se la cantidad total de elementos + * a retornar por lo que siempre se hace una llamada de mas + */ + try { + // if (first && ((CiviInputMeta) civiMeta).getCiviCrmPageSize() == 0) { + // // Si es la primera y no hay limites en el tamaño del resultado + // // obtener todos + // ((CiviInputData) civiData).jsonBuffer = crUtil.getNextValues(); + // if (log.isRowLevel()) { + // logRowlevel("Call no limit url\n\t\t" + crUtil.getCallUrl()); + // } + // } else if (((CiviInputMeta) civiMeta).getCiviCrmPageSize() != 0) { + // Si hay limites en el tamaño del resultado obtener todos + ((CiviInputData) civiData).jsonBuffer = crUtil.getNextValues(); + if (log.isRowLevel()) { + logRowlevel("Call page url\n\t\t" + crUtil.getCallUrl()); + } + // } + // Some basic logging + // first = false; + } catch (Exception e) { + logError("Error \n" + BaseMessages.getString(PKG, "CiviCrmStep.Error.APIExecError") + e.toString()); + throw new KettleException(BaseMessages.getString(PKG, "CiviCrmStep.Error.APIExecError") + e.toString(), + // BaseMessages.getString(PKG, "CiviCrmStep.Error.InputData"), + new Exception(BaseMessages.getString(PKG, "CiviCrmStep.Error.ErrorTitle"))); + } + + /* + * Si luego de esta llamada no hay datos entonces retornamos un null para + * indicar que no hay mas datos + */ + if (((CiviInputData) civiData).jsonBuffer.size() == 0) + return null; + } + + Object jsonValue = ((JSONString) ((CiviInputData) civiData).jsonBuffer.get(0)).jsonObject; + String resultField = environmentSubstitute(((CiviInputMeta) civiMeta).getCiviCrmResultField()); + String fieldValue = ""; + for (String outputField : ((CiviInputMeta) civiMeta).getCiviCrmKeyList()) { + fieldValue = ""; + try { + if (jsonValue.getClass().getSimpleName().equals("JSONObject")) + fieldValue = ((JSONObject) jsonValue).get(outputField).toString(); + else + fieldValue = jsonValue.toString(); + } catch (Exception e) { + } finally { + outputRow.add(fieldValue); + } + } + ((CiviInputData) civiData).jsonBuffer.remove(0); + if (resultField != null && !resultField.equals("")) { + if (log.isRowLevel()) { + logRowlevel("JSON: " + jsonValue); + } + outputRow.add(jsonValue.toString()); + } + return outputRow.toArray(); + } /* - * Este metodo es el priero en se llamado cuando se inicia el paso, en caso de - * retornar false e interrumpe el mismo y finaliza la transformacion. + * Este metodo es el primero en ser llamado cuando se inicia el paso, en caso + * de retornar false e interrumpe el mismo y finaliza la transformacion. * * Tener en cuenta que los valores de StepMetaInterface son los que se * obtienen de leer los datos desde el repositorio donde esta la @@ -216,12 +447,10 @@ public boolean init(StepMetaInterface smi, StepDataInterface sdi) { */ boolean passed = super.init(smi, sdi); if (passed) { - crUtil = new RestUtil( - environmentSubstitute(((CiviInputMeta) civiMeta).getCiviCrmRestUrl()), + crUtil = new RestUtil(environmentSubstitute(((CiviInputMeta) civiMeta).getCiviCrmRestUrl()), environmentSubstitute(((CiviInputMeta) civiMeta).getCiviCrmApiKey()), - environmentSubstitute(((CiviInputMeta) civiMeta).getCiviCrmSiteKey()), - environmentSubstitute(((CiviInputMeta) civiMeta).getCiviCrmEntity()) - ); + environmentSubstitute(((CiviInputMeta) civiMeta).getCiviCrmSiteKey()), + environmentSubstitute(((CiviInputMeta) civiMeta).getCiviCrmEntity())); } return passed; } diff --git a/src/main/CiviCRMInput/swing2swt.jar b/src/main/CiviCRMInput/swing2swt.jar new file mode 100644 index 0000000000000000000000000000000000000000..8e13f256d99cdccf3fd1b7f6c66c6ca314fe2b4d GIT binary patch literal 33196 zcma&NQ;;a_mMvPgUA4-#ZQHhO+qP}nwr#AkZQJMH{m{L;Z^t<|zsQKp_mM+$ro0p| z2nqniKc`faQV8JRE))O|02vWw0U8NeQ92m`SqV`QC1qL}(Vs~GfRyAZr%HO1u-BaP z-}#Yk4jT9rL$gi*k8r3+La46ssbYS50pRb;Tc=VtPVI|rk}SHu$DAaiAf!^r8ocjd z`S7VU@coFszOFte{)BFBd9W$z;_4H}`2(pL3NO3&%O{j$|HaR)YiUGWmh^A^ZtiKi zE`J8U3;InVUx=_TL&tLLqQ;|D`0^UB$)aNnZKUJ+!U<&RB{_WGM2@fa(J||(bq60? zo-v*p*^9?{-)jjoB#bKjONsDUB=C)75dJM?utm~<_9j_QLqWQ=afVMJkv%A0fhEKv z=7IR_OI1z)Daffu+nTy-QHRfbN>T^GpBS4!1{>@Ye!J8Jc?*|%_-}$2ZkkSw!L~fM zDrtu@*mHIr9QbDZw~f?M@$uvc|CPXO@-J9AX$J`_AbpLc+PA|a9QRWfHZQ-&GlSl#6gPGi9;EDEsGKQE+DP z!io)`4#W)w-sr%I(PjlkY9nT7ni5im_1tX*#4UAS@Z_NWA+a4=RkNXnZmj!#m6;{U z-OJzgdRkc0&8Cd1)y0<5&Z;v=xMRxX^dMp3acj=|8UDG~bc`0y+TzDg9CLjQSFi-#h`Tqo7 z+5ZQ40RII%5g};_c_k4&S|!nxWQn9qd6bY>o#o#F5i|*n$$Uoj6wva${-fYMxP1b6 zg!tFw{nas9#S~|BndzI}8Mhm*)19u6)8T?i4XqIA+jxMeauy;i4y3z>aP{4J#% zkdHXSEl8hCU48u$4el9#m8fPn?wY_DY^Pm4JyH&P`a4g6*NPS0WJ=3@5h1XGAxnJOzPahx_Zo~K%+Ry{YTP8 zK*$YBC2Z0VVL1;?7hMfO^IRnEx$|>P4{o{0ynUe2j_mDGSO;msFyq zU2t=9a}LOATT3A(_s}U!bwY#cIF;TNijaT%uO>>Y3Ol>}4{a`q5o%d#7;;qR6J5ev zRX)CA%pcrQ&#oK}>~gB*s|)EfZ0WfpiI^;N>iNlz@h5LgOH1O`dZ(7jtqi;ft-xY&ei5@u0snj-o@4 z$}mh`^{an2dJwFrQ5=E|hi5L6*wg^Fg2DtKZ36(2Ni2pKRceYB{^k}!vc}`;i;oRO zG|mqwfTfAge@q!3+jB?Z-F&lED%D0dkyPcl!E$xHdz`(K?F8q?OLgn5lm5{OOU>2i zrMl!n0J-eptJw7&N(kgst7d9b8hE8a@5up@68vkjqKavDoVXyCmY&(5l&iv`NsdkO2Ye!{D9XUK=rvr5Ie* z`E$qcOkT=#tz(QEVI*Z||5{~$c+-y)AAZ(anFW~~IdUb->zO_K)D0)@_jx8$8Ot=}#-~z%eLY%>|__tK9-slG6D0PdCk}Xu?aa z$pqplC7g%VC3a8pr<2e6NC7b8C6YhFC2VjyCn6YZ!GbzP5dUX`!okl9aS;H2LArvq zbU+40qA^eKQ`3FI^vE$Cm(4Vf+GKbC!r>UKzS3o zmxoVYZO$1BD=W?QIqI}UPw}k-wWa9eGq%&HZlS3Pebe84dnp?iQ!ihMjzgr)SUo4s zYuo!8DQ-I2dGy}bt}qN52;p0s=^IMMtSAO=>KDR`eqk2p9k-DiK5 z1B&Dd*G*@S= zkWbwj5Dxm88nMU+khw%K14A1?{KNS4Sj_%UE;n-58wJ-sX5X+#(;SKgd zMu)O+6wVAmf#U1QT8U5WBy|Y_mubbxH`dns;npInMN%nFh>V0785lW}M~X3}M8jdC zNAp-;2Y2PJF;p`(bG+NtS59f;yoMk=v$x2K1_&FzC~kL8re^7EDkqci>1 zsv(NwSBc%UuEWcvy<+sJiksUdEta&}a4nwoHr+-l$TF*2%h|0q|!Kst5&?mufHE^%@Fln zYIwZ9()fqym)}Q-12*?N)+H*ju;-GL=8&%QGIan1zbNpBQzY?45-{?Lnv9=g+kLYQ ztEBRLKjQ8NKW}f0lmLjK4d28**D{br$=(?-tx2;0?M#g#F|?%vCX_JH${Ko*Tij(hmym?tdB^SUu6Z=_o%&AR@<77|l zF^Sb=nYpC14T#Q}4pc=kulM;jz#mV2evrI_p>S8DIas*NTFlN4hTw5J(!OExmXn-$ zr&eBh2qYwo>I?F@*2)WOOztvyZ|^gm<3^qW7O6OZ{@8Mow_LNcD7U>?YtH>0&4B6A z-(C6!b#;h?GV04#QGUXe)#O_<_v?1i-+Ra^;W$xm6|ev*_!^9gzD&|l`Vd4 zE?Wngqzt^fWXTwD0~?|}H2K{5SNFKfqq_3tlxQ!AAt+-S#9Rs=VCN!&(&Hw53>mU2 zP7VA*cbcG&TdEJM)nz)iaJRC}@Q62tUH81SE)B6^q^w_n9#^RtY2=+<1dj?jyofzy z0HD;^DJ&4-AK;_Rh-dIZX=|shw|_B1mSHWqkKW~$%8&f{V0$_7v!x5xB%Y@TmhBg$ z`NAHM3M+0GqR>;vfIyS-zs7(di3`YZi1px3WuQqk;|3ENdPlVXt+(r0s7J{s2}Uc# zROA6A2?0YY_M?qeRm!GXqg`SdDpA%k?SAOF%6bqtRuLoTm4D%w= z9L|Mmo8P-ls1JqGn)khn6nEO^g?Yn#j`@m&pA`OjLH^V)8XR4t3*Mz>mn5w=>u-d& z4tNqea1CbBZqJF0^v7#m(~4&I#QGu~_)fQnR;m{3RZ=Lp%OY7Bj(w-8T!WVQ`ZK=P zeg_fXX51Yv($22gxfTfGCE!W)Fp1b>Ty2amj+tZH{-FiF0@R~`$xmTP6g66KPdHYC zb@y%>BAdaL$*f$Q!RG5Bwg3;i+`9|fjj`8VV5M>=#Y5m&lFUI=3|F@YsKFc6Q+ng0iizeh=dXC&hV3}p2n$EcS*2|ra|5nvJy`m{ zq$oyoe#hJT!}u6z;SjV*M+nv;ALH7uElH$2I%v9LKZKf0B2x=C(GQRJhZ>BFsdyXR zSU!nD3Go8+S^;|yvPb7CBjqG(XR#m;7n#k7z;-z+ooM%Ab|ma{Df4l7(Rv z8$y%t`Icn0Q_>c*LFUkr8WZ^E>Fe13-^)-o2`{-OPg|`Ag|L>2Wu>5xi}(Ym*$Ju! zP^rIyo_UzKBh%y^Uyg^ycBHXvIv+`~2d+2@E5^_7$!a*FY>C-a*XBd-ZQ^PrF<*bc z`>HqA>eQ=Io?DwPa~C@=-GBpW;RU6J&ZYjGg3vNkwdH%BH$&2@qfxc&bNMZ(=eO>= zzc`fWVV7>dO)$QX4@0$GOH`G}W_SA@#qwGTVo`Q4%-htq7-t=Q%j(i&}& z3%w7)96x4NKD%Lp@jk>2@@B`+GrU!dB8wXQ{<2(jH! zzYE>CTeCWf=KMR0DXxul2$o1Sb;72s+ggVU!-4G^w&2`iv$1WO6j)Ss{N0$ii@Mdq z5ASDeTV1}NRk@acdMZbU|05lb>zTuB;AN^6F4WH-4cX**I4c6a_2k-2GF_!uJz-_O z-iG|^a*2$JSA!b$xUm(R<>uGA&2?q8CJZye+toCbN@OXiy5~*G&8)MV;2e%gc+FXJ zw-B|zpM3MU*h-Z(Ma{I_jfb<7AoIdWqGX!taz?!Qc^n#zrS@K5K;oWLVNmYzx{65u zO}5k+ncZEmG^UJP2(DB0`kqy6*T+1t=)L?jg6?zzGn}I~q+kCh+YavdTI0Y~sp7yk zn8mUqWC1fLne{6q=@M;C&Zz_o zA@g44#cbz}PsLRTYJYgNHMkk}e3Ff!YyFhP1qf+w3U}MQ*G!J_Wc5xk4dY=}3GJoz z8+c*I$%^I5@K~mLO#FRs(*hU_B3e2<7pEdHyW@^b? z_jj_c#eSu^jgq8*%2t~cxesXyY?Oxu0oJVwzWe*u$eKq}%4KuxEr)}(`dlj*U%2m_ z6%|2?MMW(Y*=eI0aL&@xLEMri)m5H9?h6S>bvp%#n@Qb7-n@NbO)V6*O8F9(xC8_+ z5Re4!83_>ys=`xB!60_(9ClkX3Ew?s8_&&J@#;W3!&!u zu*IU$4U}3N+_$&6oGKIbIoAed`dRqV4}D>ymJ2#ee^K^|!Z7OtsGy*gphmbM`ms&I zQbkKfrf?31LC3=s0*U{Qmq3YXTxMF zV^?> zetLlgHIR0^VS37ZC<!1PBDP7_DjMVMr1y(V2 zvANB^(9QGfX~|8FcnP0eagA&_tR*~o$;E6O;6w!3k@Py!zBDaYB~#;pUp(1eztuQV z?Q^NxRhy7;YY5gJ&0{{1avuX_2NqkvPVkwmMx5PybRUJ`6!XS3g+T_&pvyI3@DeBW zzG9A!A8jXu^3(KgU=zVh7+X;Y-tEAr@?#;nm=9J3j+?&A{o!ilITpdyb2jaz8SuU~ zKF9Ue`R4fCPEwI^fwn8w>$tnW$6WUoc57&tm{$Auqyg*TlWXO)uVMQy^1z}_>V@_7uVHY4wy)wbN-JFX9)vJheI_4b6?v&ITXEo+#%=oZH+pV zc047O2jKbgB)G8+mor)ndNd0=OM}tbHv>m@U*7yKs&wrfE!k_ z4k_r3Hbcx1-x?3Os#KHeKQGoNa$ni@Us4uQT|#_4=C8Qk25*#AO?7n+DQhP{*BkJX zoe_3XIdxEZ+ca0I+Ub-!UyXs~H-*QwhN|l6JV&$M%)^vuKj{Bzh-z>=v3C&x03vYz zy&)?3zg3?mM%EVgPA0S#wx&vO&;4JOD~_uj_rF#B0QmpBIJsHa znlU=LIn!Aic-Xl((+Q|4OaI3ct&z2XlT(a>jU2K7f^X`Jr@UrA6s0`Ba(&4lMQ>jK zn54CJa{&mD-ngTVmsD)miLF(U-wdPyZ3`ylf&%DR3Qot=zq@}4&xk)Yi5P(Pue>b84zNJn1es_E>p`h4!r;vbY zTHi669fg&~4J2K1?->0JxQoBDqDQFnVe?Z$JxR|;cW9>q{N?-ThC^Gsqp|p5%f=z*Uuh0fFzIZj1O|tl z;rs|_n4sg?0K6rv4U4oFD-{)f;pA-UJO)yO#^b)J!Uq(eJJsHzxpN;RTh3Jq{9mn$ z=h@nN7JCx6((+#e=>j}asG*JFg%TO+5L|63f{+T_=)F$X4q{P;Bw@4=;?a0HLu@vT z4_VRdB_xY)Dc_i0av3DS5uTRWZPM+}sYT?vOfN1%^+T@Od9N3no7zYIi%$hcjpwWY z8r5Q|gQRqPLjQzT5Yma=5-oHOpM!)RA>q^*u5p5DY zF{~xAIKFurfnNFXdf;ilp>ZOkwYS&;I*e^>R$c?ytaTyv&ycG%`7Z#rS2=RVCk*#U zU21)RsP;fJ#BIT@W5k@;L}eod=LlnG5d}Pv2J(wgi5yP{4o)xvJYnoMKfr%|6(wQW zm-7Ggrj#K6j?O(67^Z(mC*J=Zot6f!1~n=Jwws~|J>YkI(k_Xxs!)qXi204eW5UE* z2qx_pBnw(-x38-Hn*l?!S_4q~;=I(al1i4kKvd5C@BskAr z4cV#P6JW|OR|DHRrEu>(YfITOoZeK09hr!|_Zx`}lD zm(VEhHJ!}Uam@^_;N3wFAr(9-2kl84No>a?;l?urA$+MH3YMxRZTT_e5?$O~A z{d2NwX6N@1{BJpo29KP`02@*}zeOtS>s8n& zh2cc*jM@~>q7)<+aVvuq=q{j6=YyIB-w8pE6?2lOz)+1HQRw$Gkq5gcQS35hRGGx* z?wpdQ6fvbro>(+!MV}@}Wr!maNGtwUG3N#X6V|*k2NJ>)-|ipm5;uIp&X4WIpJ602 zNg9pOWX;~;5V<+mn4~;gK(=Ufqi*aN+r&%89fb?u!L~`qJYnr3(TFo*Q6`MO*|BKM ze%jM`ix}%=rex<%HYrmoqms_afBG9Dg*7sT&ZwQJfBC7jtCkh7lkHNVCj#|BakWD6 zHz1H;bPa7@7|)uV?63TQoCI2(E+(sSS!BwP(4_T|4JIq>1S>MX7@OO z^O1v!zpi>m>=b!^P`?=B+p`E5W^#G?T3xx~Hz}&f!mZ&2D~C*O>DwloX5X&iDEFr9 zz>bP~Sxx@3X7>`ab|2V{qL#Rj&_E2`z)C?y8U~8VNm)+X7x>L!iRYyT?LAkOGrXp% z3Rkb$3ZQxU2_Kcr$bxgwX@A@T#W6(Yd=h z)s#aiLZQH6r4jr#t5~D>qP`5;1#C2?by6!>-r_2*z z`=QtN`_M^aBlMl^>nYbsJB602xgjwnB&5f88u26|{0_i{0$u%RN7LnRVIYuK%xGf=>De+6a8;QCurwrY~uLelvwRj4to{#cjo4b z$?8zP4%zUIsR74xNvTh{@}onM@mZzK9R{7MVy5@ zc~zk+%Cw=Z5IfZtqa;@0df|i|84XbpK_X3DOq$IS!*Gz}2*by;ge78-hWn1dp&*G; z^EsDh^;$@*bSwT__dbyF8f@XRFr32etl8)`-TAbM>6iBCewxf*Ijzxh0}atx9qE2x zC~R`)ERq`%b^2-VfIwY&*O}tOj_DEU%5;ijC7)Q6)Q4bH6@63HY7GH8tRh1yiREq{ zYbvexhv1|Cz zWb7(!ZIcQSVZGGds0>66%b~XiEE{7Drxq6&b=wfa*8S!*suJu!D2?b?ngv1l&ahygh$6m55H&?+&M8Y=01blG1hRs)3t%dQ3GU*0RlYYhdn&zgJ9gpL>Gqtctvl zFV`xzWaO&B*@?%uBTk;LI=pxQy*xu#*2WE$x>lf$Yuj@98Mp&FF^~jhAv5}t{wiqi(- ze({fo$5$h4crs8E6AdFUQWDb@;}1t4cqA9X*z-o-9tfiB3Mq`MqgW&txdWaCt1AS0 zyx`X66ah0*ai`)OXKNEy$IJ-WgE5XkJ$E*1FnUrM5rr<_>M}i_JF+TakE@rSB$42))XD@AW4_80+zE_nJg~WDW9@K0??V7Xavp3 zcqOh=ZXU|&&Lxqv#euGgDJ<-8fJW{*4%R7sB{2_@Ar?PGkMA(5~2nQqxlSnWYOh6p|c7j&gJAhkQT!rzG1dpplBaJxOL?vaj; z%8>h3v=J^%oSkLXr5A{urI!OA8$RCo4Gw2U*Q9QZwU?2GqN5lb5=;iX!VLxPQGpku zBv*(zM*tV=Wh8D8m#uYK8}#3#^24`gdS9v%gx4mm81-}y5}xy@%InL@8M510w;t;P zJ%31TsmVN6<~WKU)Ay_sJ5yXW_GG)>J-e)+g+*t3K()B@=U%Yfqg6Y7p+r)_lX;a} zJ=?5|p#e{u4jWIn&5P&b)^!eH9gB-fJuAzO&xv1N-3#Na&ON_LvOP0y-c^q`ySuxu z?03KE$gjZL13HbCtZr(*5!xNYUtR+{-x*)+Q_#CVD(6EtKb7ELnQG@YS02E0;COUL zkLIf2-gtD8Xu8CleYb^qUQ1<_a-d^(uggb)lW$!rc@ad^RhL_(JIsa4$PEt#@5#J* z6%bn5$}BVauaxH92C7oVjwXcARiuv2&%&f?qz_~tU+;hs*>_0q^6y`FzyH!(!Ixe} zJa7Pjakzii+Xt8b9(xJ@pL+YRY%!z0Yquee;M*(tjaTXs_&22dH9bmMFguC_2+=h& zs*;!5J)j4pZmuiTzU=3gtx5Nn5TUYEMN4JiYS#O6W}2-_w{xscZ=mb;9sWL_#YRYv zG)s9J9jp7%>MNBL$KB8Ifs3CmvVWRfyyM_JGAw7cZk|rvUfw!G7&}pUR;ksxf)!%f zgaW)H)&n95*1h4xV!An=A!?6XiSR^nfF+Ce4AQ}zAp;9Ko?;xM#|+<|Cq*V10#piA zZJtxmRLn--L7keBM*L8bJz6~>{XzYHK0w`4p0QE;)&xwdl>rxy+JxNnO+vmvo)a}m z+G!qoco`bTQB9j6(@vjsiR7RrM0Z?TXpmJ3*J?iT;bgv?QCbT_Ru#oavv7zI%2j9Nycnyr~UnHzI=X3rK%w8=U?rUhk=?7f9uKx;zS&RWQ*zJeuUI#jy`_Rwc%iy1% z^Zs`mfFT6{;M)!8EocZ)xO_7Mt)burl0luW!yi<*r`etW^erJfcfd4V`eG7VhZx+g zr_q4bKAfjfdnc}5%y-(x*W<*YT@6ZQ^3q~q&;nt0MZ_q=4%U_;)`kVegzVMX&Q z?PO|Fb$wi$Q2Ay!$$9sN2yKU=xj}&hKgiN(&KXMyBpYiAYt3aKiu4IcF%Z@PMnat6 zqOUOPiIX)vWzLitQ*4$(e}yK~1XA6Qt>_C0?M*|WP>2_0eDg3HaT=ru-wQUjH$=}vCvLW~$FZl%ko&Qe)jp(EKO zaMgFW7Cx19MmduZrKEV@A>nu82N*Rz(G)13)!}76x=vPx8R`emAI%#cJOEuh`xaF; zXg`g+y@e8T!Y#u2tk?6{ruquQ`eADC_L!Otf|M+IixFN#kam=5khrxt9_@b>VF3=rl6k6F&pf=>5 z?3~Q;)*mkwcwI`CL0=9);Ij1`-VEr73Df+7uVEpchpoBgX8gP zYIM9Nq*@~wXa^2BdgJymqae=;fJw`mFZDA&j-{*Ykxx+bT8AcUqN7O36s^gdI$b`6Y?&}#EorO|MV_p+X5X_1?YZt_t<1js9j;Fc!@dq&@y??m@8mmPu3b4 z`GUXCr$$m@R1VK=Q}z+OO!lC8wPZtfd{{m|*>a6%N)Tx*-|bYR#`jIO>V%q0_EDLX zoZ7ZnUkk|$Lya`A(>VcQ$96t#RU{Q&Y!0ZQfpp8k#dQ&{jHizL>XymdyjW@aqLJC?(`MM&=sz7I1Dn{>Yd3P*lN}C zD`PudTmfu4^rkGTyY4V+c^RWi8J?v~Skl#-GRd7>I!M{jCgb&~HQeNFzH;|4Ubsa) zS=P%xpP=ylQs8tW#GSjp0=R#%sZrmiMSYSnc$V-cJ&F^IkQmmwb~OnL5fLSvb*IQ) zII`o`vf&_S8?KK~p3)*=*IeAX8-w%He(&X(B02Zk2o8_+Mh3&c`WL~ZGSH?!cTEdU>{drk6v4|%@KyI2+Ybb)^! z2YRlO(u?2|| zDLArHS+FwlV=+w9=M3Kbmp{*<&uN7rAfCCUrHRR`m&xoTi{o>uNi1%E6i^-LW}{P= z1RR9BMZv0MBbJt!MgQ>JkayXXRB|bq7~wXwX{E5DK$r00kO4zgX%(ho6&p{*J$+Je$$E5l{#($#c}hqBo;DuaP_JW1`y zdPZ(N!?2|!ta8*fOs$MQqa)M1J_eR4p-F1wRxe0v$T{I_P0u|kWn^Vctz7iZ*S{+@ zv?V<)RpS=?J6)L@oy){44VnH6XZ=v`H1!+3isYx=%OFtr0CoTb6fY7DdXd127zlvf zaB2XX`w69J{eR|xAr9OD>h^m8Sc{g!z?!8TCc{Lt;}42at`+UCAvV6;k;}e=v+oZP zIKSPY6(|gSu}3xd2+!gVux~v&WWbMOPGQ;67^I` z#LQcqwny6feh6rn?Y#VVyrB3bJ5;xe!Q9mw<48!&ZCvNehqxXp6`;$NxYxqb$V%HG zW8C*{Ud_+ky6_6?BsSUNen@+Mcs+0TlDQ102^8@bgG7yvU-Hdx)3Uk=YJPbS2s zxLv3mz#hv*L3?yz9)-=WMLlMMB)c!2hn}f;d|gQ<&|q9DdEEtb$N2IKB%D6(Q@9GL zIJ1OuMVxP-Ed+{mX*#r1jGMJ+nG~J*5Q)J2L>LtIz1Mw!-_fJU2HB;A#}F z<{X}OiNuGN#-X0Zu0O;+mioNJH#*QE$N>z^#t<8qaHL*B5B=x0{e@`JeQ>}l62?~u zt9#L^Xm|V&lQbA!qybTF1Wh`MQX82i9r5{%AA25)3rQ%(0glTk8VR-w@^I##Qk00zlhl>>?>F5 zpPwb<{#$Jb`#*^Jf1Qu~7cu`U!yK#X*d2(X_~=>u4%y^NuUIWUCEQeo#*ZQqLnN6N zEmvaQ0W4v_KSTqzZT#*q9l~P|-jrTTb}4!Qc-_2qobD9(d^~{m{AA+25t*$N=4zi- zs8h3mZWHV*wuqgYneidMJ4mY*k{?Hw{lWF1)9bfwJStwZ#BtIrb4+MVDbgfX&ML`1 zV%~9r+eI<`^TE z1_SY?(eM;t#XU%Hbs-(?iK#(AQ7Xl@WuDPVlp6^PuxYPE$tECE0Z$mg-Pqi55%;<6b3nFHVutM~3XE7#zTdv0{q~1&ep_9G0lTnZ14p@Em(ZOsq^qREB!+Ly4`WIB zZd`X`%$+!Kwu8Kl@W+u$c>m-VV$;xwNJ2=rP!a0b;}zEx{b@Jz5Xug$sFZmUCjkur zYJZ~$1o6wjz?Ddu<4`SMRj|pm)!Af|vY1xgF^}~~B-IvSC{_03yZ+LD1|wL*;qLhN3W2xkT`GveXR0-P%Gm2rrzz$y%Y zO4k5=+#<%nJP~89ImyM*JQ5(KfFc4{XmiDIf2-FLa{>T&&OFa*f+}4;?mMk6s z3q>t`*V@*NC`|rU93tUc1s+K)cW<<)mV?{{h+EPeIjDd!PYTn?KN1ONW@j<)(oM#Q zk8+o`BF%f69z2j8NFN%N5wa%MQ|5V@e@>D`SM+5IDpEQf+3HKMbPI{+F1`jCuY!|r zG!nztfkUK+8Q7=>_gZF4)klNT3^s3Z?s85fipTr1lF9tmV-+gurk$tFX{T)fmCv?s zf4cCC*_>D2yAOOy-i%7j&qr$FuY*0U^~#QvA5tYk?ih}qry;XbLWS|D$`p&B(;YXN z<(*naw-F=xI+WB`$F(wi9HAo?c6Il=?t87fS2d(*;qElJ9IB z_Od&iS1yztZ2s)};crztBtL*uxhBO-L8JOQ(sABs>*twCm)!ysHw0<{Qdnl{N4Y5%hZ1sZDx=(Vy z^#}c1>erQ?!<}Q6J?T_{9pUa8H&U#F70}agxmX8TWoVU$0?Vo&;&DvS9`F5XH%+8@ zHO9MK=5$xUE;{F+lZr{Z87>sw>JlL_XLG!3->45GYf^8+l|<-PxH#?CF7O5_P?H$$ zU1Q);#2tFIWn_~SwhcTt%NM?xGj76n{B*X7bpNx^LFHOW@N{POXiPmDugCjJw10K? zUyL2e07Po?4`XZov+MC+`xgJxN)!BV#gnMDo!h^A=@?ZVd!<#xpIVo?T4xsmetAuU zX+3j8=x`-*W%}S@jG&zGJgl+cJks7&lXD~jjt_w^VvFof8VRXEJ#%p_AexFSW*Z4` zkfmnkrHrQnyKCvZkHxayrwXQ=bD@mV-CU}vNE_|AF)!EGtM%>2>)f7?Lq9*CKfKig zbTAirZO3r;?JsnygMIBvQt$!ug=TsO<>2ocUvRtCFCY+sbuCA{Z^6&jIZ>@JX zdYrg;M!4FZ7lq_rUubIsc5+{C+BX(3#!g}29G52AE2=|1EU(FrA1ACCZcLM&IOC~I zz@eLE=V=pMnVR7%UE;j5!2m}d{jJRsWp#s6#@n6ebLBVz$N^gk1TD6191kGmU9Np(j>= zlq8OG_M5ZFn{Q?-rmEYk1mF)D*d`3$jf)z&#EqeLM!Gv`d%9#=)8|Y|Az5r2$OgWn zi}>M=F9;f;^XhyJ3O`H@x{C=M1Jm4upLFk^0xM4n1=nXvS0wr2J62wLdhRJhW0Y9i zOdOBzb$ZfWF(vs5zc5Yeeni)UG>FDG81MjO#Dfs>5Ol%~4h)d>SQ}P`Ig$TJH)pJw z8zx1JNjqn*iB2CdwT_FzLLVgk@t-ug N^xVWSWYp0m1D?K)X=2K8<1R1Wu=0f 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 0)) { + if ((((CiviOutputMeta) input).getCiviCrmOutputMap() != null) && (((CiviOutputMeta) input).getCiviCrmOutputMap().size() > 0)) { // Si hay elementos para filtrar entonces mostrarlos en la tabla int i = 0; - String[] streamFields = new String[((CiviOutputMeta) input).getOutputMap().size()]; -// for (String cField : ((CiviOutputMeta) input).getOutputMap().keySet()) { - for (String cField : ((CiviOutputMeta) input).getKeyList()) { + String[] streamFields = new String[((CiviOutputMeta) input).getCiviCrmOutputMap().size()]; + for (String cField : ((CiviOutputMeta) input).getCiviCrmKeyList()) { TableItem item = tOutputFields.table.getItem(i); item.setText(1, cField); - item.setText(2, ((CiviOutputMeta) input).getOutputMap().get(cField)); + item.setText(2, ((CiviOutputMeta) input).getCiviCrmOutputMap().get(cField)); streamFields[i++] = cField; } this.streamFieldColumn.setComboValues(streamFields); - } else { - // getInputFields(false); } this.outputFieldsColumn.setComboValues(comboValues); @@ -500,54 +544,36 @@ public void getData() { * campos que admite la entidad, los cuales son desplegados en las tablas que * muestran los campos y filtros */ - protected void getEntityFields() { + protected boolean getEntityFields() { try { - if (((CiviOutputMeta) input).getFields().size() > 0) { + if (((CiviOutputMeta) input).getCiviCrmFields().size() > 0) { MessageDialog.setDefaultImage(GUIResource.getInstance().getImageSpoon()); boolean goOn = MessageDialog.openConfirm(shell, BaseMessages.getString(PKG, "CiviCrmDialog.DoMapping.ReplaceFields.Title"), BaseMessages.getString(PKG, "CiviCrmDialog.DoMapping.ReplaceFields.Msg")); if (!goOn) { - return; + return false; } } // Eliminamos los campos de salida y volvemos a actualizar la tabla con - // los campos - // de entrada mas los de la entidad seleccionada mapeando los que se - // llamen igual + // los campos de entrada mas los de la entidad seleccionada mapeando los + // que se llamen igual + tOutputFields.clearAll(); tOutputFields.removeAll(); if (prevFields != null) { prevFields.clear(); } + + activeEntity = wCiviCrmEntity.getText(); + + //Obtenemos y llenamos la tabla con los campos que llegan del paso anterior prevFields = transMeta.getPrevStepFields(stepname); if (prevFields != null && !prevFields.isEmpty()) { - BaseStepDialog.getFieldsFromPrevious(prevFields, tOutputFields, 1, new int[] { 1, 2 }, new int[] {}, -1, -1, null); + BaseStepDialog.getFieldsFromPrevious(prevFields, tOutputFields, 1, new int[] { 1 }, new int[] {}, -1, -1, null); streamFieldColumn.setComboValues(prevFields.getFieldNames()); - - /* - * Verificamos que los elementos de salida siempre tengan un campo - * valido de CIVICRM asignado si lo tiene, en caso de no tenerlo se - * busca y se asigna si existe. Si lo tiene y no existe entonces se - * reemplaza por el campo asociado si lo hubiera con igual nombre - */ - HashMap lFields = ((CiviOutputMeta) input).getFields(); - - if (lFields != null && lFields.size() > 0) { - int nrKeys = tOutputFields.nrNonEmpty(); - for (int i = 0; i < nrKeys; i++) { - TableItem item = tOutputFields.getNonEmpty(i); - String streamField = item.getText(1); - if (streamField != null && !streamField.equals("")) - if (lFields.get(streamField) != null) { - item.setText(2, streamField); - } else { - item.setText(2, ""); - } - } - } } - + String restUrl = variables.environmentSubstitute(wCiviCrmRestUrl.getText()); String apiKey = variables.environmentSubstitute(wCiviCrmApiKey.getText()); String siteKey = variables.environmentSubstitute(wCiviCrmSiteKey.getText()); @@ -555,31 +581,29 @@ protected void getEntityFields() { RestUtil crUtil = new RestUtil(restUrl, apiKey, siteKey, "getfields", wCiviCrmEntity.getText()); crUtil.setEntity(wCiviCrmEntity.getText()); - HashMap lFields = crUtil.getFieldLists(true); - ((CiviOutputMeta) input).setFields(lFields); + HashMap fieldMap = crUtil.getFieldLists(true); - String[] comboValues = new String[lFields.size()]; + String[] comboValues = new String[fieldMap.size()]; int index = 0; // Actualizar campos de salida del plugin - for (FieldAttrs field : lFields.values()) { + for (FieldAttrs field : fieldMap.values()) { comboValues[index++] = field.getfFieldKey(); } + this.outputFieldsColumn.setComboValues(this.comboFieldList); + // Verificamos que los elementos de salida siempre tengan un campo válido - // de CIVICRM - // asignado si lo tiene, en caso de no tenerlo se busca y se asigna si - // existe. Si lo - // tiene y no existe entonces se reemplaza por el campo asociado si lo - // hubiera ocn - // igual nombre + // de CIVICRM asignado si lo tiene, en caso de no tenerlo se busca y se + // asigna si existe. Si lo tiene y no existe entonces se reemplaza por + // el campo asociado si lo hubiera con igual nombre int nrKeys = tOutputFields.nrNonEmpty(); for (int i = 0; i < nrKeys; i++) { TableItem item = tOutputFields.getNonEmpty(i); String streamField = item.getText(1); // String outputField = item.getText(2); if (streamField != null && !streamField.equals("")) - if (lFields.get(streamField) != null) { + if (fieldMap.get(streamField) != null) { item.setText(2, streamField); } else { item.setText(2, ""); @@ -596,14 +620,13 @@ protected void getEntityFields() { new ErrorDialog(shell, BaseMessages.getString(PKG, "CiviCrmStep.Error.EntityListError"), e.toString().split(":")[0], e); //$NON-NLS-1$ //$NON-NLS-2$ logBasic(BaseMessages.getString(PKG, "CiviCrmStep.Error.APIExecError", e.toString())); } + return true; } - - protected boolean ok() { + protected boolean ok() { int nrKeys = tOutputFields.nrNonEmpty(); - boolean matchFields = true; - HashMap fields = ((CiviMeta) input).getFields(); + HashMap fields = ((CiviMeta) input).getCiviCrmFields(); ArrayList keyList = new ArrayList(); List streamFields = Arrays.asList(streamFieldColumn.getComboValues()); @@ -612,54 +635,50 @@ protected boolean ok() { for (int i = 0; i < nrKeys; i++) { TableItem item = tOutputFields.getNonEmpty(i); // Verificamos que los elementos de salida siempre tengan un campo - // seleccionado y luego si no hay un alias le ponemos el mismo nombre del + // seleccionado y luego si no hay un alias le ponemos el mismo nombre + // del // campo - - if (item.getText(1) != null && !item.getText(1).equals("")) { - String streamField = item.getText(1); - String fieldKey = item.getText(2); - - matchFields = (streamFields.indexOf(streamField) != -1); - if (!matchFields) { - String msg = ""; - msg = BaseMessages.getString(PKG, "CiviCrmStep.Error.StreamFieldNotMatch") - .replace("$1", streamField); - Exception e = new Exception(); - new ErrorDialog(shell, BaseMessages.getString(PKG, "CiviCrmStep.Error.UnableFindField"), msg, e); - break; - } - matchFields = (fields.get(fieldKey) != null); - if (!matchFields) { - String msg = ""; - msg = BaseMessages.getString(PKG, "CiviCrmStep.Error.FieldNotMatch") - .replace("$1", fieldKey) - .replace("$2", activeEntity); - Exception e = new Exception(); - new ErrorDialog(shell, BaseMessages.getString(PKG, "CiviCrmStep.Error.UnableFindField"), msg, e); - break; - } + if (item.getText(1) != null && !item.getText(1).equals("")) { keyList.add(item.getText(1)); hOutput.put(item.getText(1), (item.getText(2) != null && !item.getText(2).equals("")) ? item.getText(2) : item.getText(1)); } } - if (matchFields) { - stepname = wStepname.getText(); + stepname = wStepname.getText(); - ((CiviOutputMeta) input).setCiviCrmRestUrl(wCiviCrmRestUrl.getText()); - ((CiviOutputMeta) input).setCiviCrmApiKey(wCiviCrmApiKey.getText()); - ((CiviOutputMeta) input).setCiviCrmSiteKey(wCiviCrmSiteKey.getText()); - ((CiviOutputMeta) input).setCiviCrmEntity(wCiviCrmEntity.getText()); + ((CiviOutputMeta) input).setCiviCrmRestUrl(wCiviCrmRestUrl.getText()); + ((CiviOutputMeta) input).setCiviCrmApiKey(wCiviCrmApiKey.getText()); + ((CiviOutputMeta) input).setCiviCrmSiteKey(wCiviCrmSiteKey.getText()); + ((CiviOutputMeta) input).setCiviCrmEntity(wCiviCrmEntity.getText()); + ((CiviOutputMeta) input).setCiviCrmResultField(wCiviCrmResultField.getText()); + ((CiviOutputMeta) input).setCiviCrmDebugMode(wCiviCrmDebugMode.getSelection()); - ((CiviOutputMeta) input).setKeyList(keyList); - ((CiviOutputMeta) input).setOutputMap(hOutput); - dispose(); - return true; - } - - return false; + ((CiviOutputMeta) input).setCiviCrmKeyList(keyList); + ((CiviOutputMeta) input).setCiviCrmOutputMap(hOutput); + dispose(); + return true; } + protected void updatePreviousFields() { + try { + prevFields = transMeta.getPrevStepFields(stepname); + if (prevFields != null && !prevFields.isEmpty()) { + streamFieldColumn.setComboValues(prevFields.getFieldNames()); + /* + * int nrKeys = tFilterFields.nrNonEmpty(); for (int i = 0; i < nrKeys; + * i++) { TableItem item = tFilterFields.getNonEmpty(i); String field = + * item.getText(1); item.setText(3, ""); if (field != null && + * !field.equals("")) { for (int t = 0; t < prevFields.length; t++) { if + * (field.equalsIgnoreCase(prevFields[t])) { item.setText(3, field); + * break; } } } } } else { prevFields = null; int nrKeys = + * tFilterFields.nrNonEmpty(); for (int i = 0; i < nrKeys; i++) { + * TableItem item = tFilterFields.getNonEmpty(i); item.setText(3, ""); } + */ + } + } catch (Exception e) { + e.printStackTrace(); + } + } } diff --git a/src/main/CiviCRMOutput/src/es/stratebi/civi/output/CiviOutputMeta.java b/src/main/CiviCRMOutput/src/es/stratebi/civi/output/CiviOutputMeta.java index 4c5c1e3..ad30e47 100644 --- a/src/main/CiviCRMOutput/src/es/stratebi/civi/output/CiviOutputMeta.java +++ b/src/main/CiviCRMOutput/src/es/stratebi/civi/output/CiviOutputMeta.java @@ -1,6 +1,10 @@ package es.stratebi.civi.output; import org.eclipse.swt.widgets.Shell; +import org.pentaho.di.core.row.RowMetaInterface; +import org.pentaho.di.core.row.ValueMeta; +import org.pentaho.di.core.row.ValueMetaInterface; +import org.pentaho.di.core.variables.VariableSpace; import org.pentaho.di.trans.Trans; import org.pentaho.di.trans.TransMeta; import org.pentaho.di.trans.step.StepDataInterface; @@ -32,5 +36,13 @@ public StepInterface getStep(StepMeta stepMeta, StepDataInterface stepDataInterf public StepDataInterface getStepData() { return new CiviOutputData(); } - + + public void getFields(RowMetaInterface r, String origin, RowMetaInterface[] info, StepMeta nextStep, VariableSpace space) { +// super.getFields(r, origin, info, nextStep, space); + if (civiCrmResultField != null && !civiCrmResultField.equals("")) { + ValueMetaInterface v = new ValueMeta(civiCrmResultField, ValueMetaInterface.TYPE_STRING); + v.setOrigin(origin); + r.addValueMeta(v); + } + } } diff --git a/src/main/CiviCRMOutput/src/es/stratebi/civi/output/CiviOutputStep.java b/src/main/CiviCRMOutput/src/es/stratebi/civi/output/CiviOutputStep.java index 0dbb6d9..ca28146 100644 --- a/src/main/CiviCRMOutput/src/es/stratebi/civi/output/CiviOutputStep.java +++ b/src/main/CiviCRMOutput/src/es/stratebi/civi/output/CiviOutputStep.java @@ -1,7 +1,12 @@ package es.stratebi.civi.output; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.row.RowMetaInterface; +import org.pentaho.di.core.row.ValueMetaInterface; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.trans.Trans; import org.pentaho.di.trans.TransMeta; @@ -14,89 +19,114 @@ import es.stratebi.civi.util.RestUtil; public class CiviOutputStep extends CiviStep implements StepInterface { - private RestUtil crUtil; + private RestUtil crUtil; - public CiviOutputStep(StepMeta s, StepDataInterface stepDataInterface, int c, TransMeta t, Trans dis) { - super(s, stepDataInterface, c, t, dis); - } + public CiviOutputStep(StepMeta s, StepDataInterface stepDataInterface, int c, TransMeta t, Trans dis) { + super(s, stepDataInterface, c, t, dis); + } - public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException { + public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException { - civiMeta = (CiviOutputMeta) smi; - civiData = (CiviOutputData) sdi; + civiMeta = (CiviOutputMeta) smi; + civiData = (CiviOutputData) sdi; - Object[] inData = getRow(); // get row, blocks when needed! - if (inData == null) // no more input to be expected... - { - setOutputDone(); - // Closing CiviCrm Server connection - crUtil.closeSocketConnection(); - return false; - } + Object[] inData = getRow(); // get row, blocks when needed! + if (inData == null) // no more input to be expected... + { + setOutputDone(); + // Closing CiviCrm Server connection + // crUtil.closeSocketConnection(); + return false; + } - if (first) { - first = false; - // determine output field structure - ((CiviOutputData) civiData).outputRowMeta = (RowMetaInterface) getInputRowMeta().clone(); - ((CiviOutputMeta) civiMeta).getFields(((CiviOutputData) civiData).outputRowMeta, getStepname(), null, null, this); - } - String params = ""; - String[] fieldNames = getInputRowMeta().getFieldNames(); - for (String field : ((CiviOutputMeta) civiMeta).getKeyList()) { - params = params + "&" + field; - int i = 0; - for(String fName: fieldNames) { - if (fName.equals(field)) { - if (inData[i] != null && !inData[i].toString().isEmpty()) { - params = params + "=" + inData[i]; - } else { - params += "="; - } - - } - i++; - } - } + if (first) { + first = false; + // Tomar el flujo de entrada + ((CiviOutputData) civiData).outputRowMeta = (RowMetaInterface) getInputRowMeta().clone(); + // Actualizar los metadatos de los campos existentes y añadir result field name + ((CiviOutputMeta) civiMeta).getFields(((CiviOutputData) civiData).outputRowMeta, getStepname(), null, null, this); + List metaList = ((CiviOutputData) civiData).outputRowMeta.getValueMetaList(); + + ((CiviOutputData) civiData).conversionMeta = new ValueMetaInterface[metaList.size()]; + int i = 0; + for (ValueMetaInterface metaInterface : metaList) { + ValueMetaInterface returnMeta = metaInterface; - // Open CiviCrm server connection and send rows to CiviCrm Rest API - String msg = crUtil.putValues(params, "", false); - if (!msg.equals("")) { - logError("Error \n" + msg); - throw new KettleException(BaseMessages.getString(PKG, "CiviCrmStep.Error.OuputData"), new Exception(BaseMessages.getString(PKG, "CiviCrmStep.Error.ErrorTitle"))); - } - - putRow(((CiviOutputData) civiData).outputRowMeta, inData); + ValueMetaInterface conversionMeta = returnMeta.clone(); + ((CiviOutputData) civiData).conversionMeta[i] = conversionMeta; + i++; + } + } + + String params = ""; + String[] fieldNames = getInputRowMeta().getFieldNames(); + for (String field : ((CiviOutputMeta) civiMeta).getCiviCrmKeyList()) { + String civiField = ((CiviOutputMeta) civiMeta).getCiviCrmOutputMap().get(field); + params = params + "&" + civiField; + int i = 0; + for (String fName : fieldNames) { + if (fName.equals(field)) { + if (inData[i] != null && !inData[i].toString().isEmpty()) { + params = params + "=" + inData[i]; + } else { + params += "="; + } - // Some basic logging - if (checkFeedback(getLinesRead())) { - if (log.isBasic()) - logBasic("Linenr " + getLinesRead()); } - - return true; + i++; + } } - public boolean init(StepMetaInterface smi, StepDataInterface sdi) { - boolean passed = super.init(smi, sdi); - if (passed) { - crUtil = new RestUtil( - ((CiviOutputMeta) civiMeta).getCiviCrmRestUrl(), - ((CiviOutputMeta) civiMeta).getCiviCrmApiKey(), - ((CiviOutputMeta) civiMeta).getCiviCrmSiteKey(), - ((CiviOutputMeta) civiMeta).getCiviCrmEntity() - ); - crUtil.setAction("CREATE"); + crUtil.setDebug(((CiviOutputMeta) civiMeta).getCiviCrmDebugMode()); + + // Open CiviCrm server connection and send rows to CiviCrm Rest API + String jsonResult = crUtil.putValues(params, "", false); + String resultField = environmentSubstitute(((CiviOutputMeta) civiMeta).getCiviCrmResultField()); + if (log.isRowLevel()) { + logRowlevel("Call no limit url\n\t\t" + crUtil.getCallUrl()); + if (!resultField.equals("")) { + logRowlevel("JSON: " + jsonResult); + } + } + ArrayList inList = new ArrayList(Arrays.asList(inData)); + if (resultField != null && !resultField.equals("")) { + if (inData.length > ((CiviOutputData) civiData).outputRowMeta.size()) { + int index = ((CiviOutputData) civiData).outputRowMeta.indexOfValue(resultField); + inList.set(index, jsonResult); + } else { + inList.add(jsonResult); } - return passed; } + putRow(((CiviOutputData) civiData).outputRowMeta, inList.toArray()); - public void dispose(StepMetaInterface smi, StepDataInterface sdi) { - super.dispose(smi, sdi); + // Some basic logging + if (checkFeedback(getLinesRead())) { + if (log.isBasic()) + logBasic(BaseMessages.getString(PKG, "CiviCrmStep.Msg.LinesReaded", Long.toString(getLinesWritten()))); } - @Override - protected Object[] readOneRow() throws KettleException { - return null; + return true; + } + + public boolean init(StepMetaInterface smi, StepDataInterface sdi) { + boolean passed = super.init(smi, sdi); + if (passed) { + crUtil = new RestUtil(environmentSubstitute(((CiviOutputMeta) civiMeta).getCiviCrmRestUrl()), + environmentSubstitute(((CiviOutputMeta) civiMeta).getCiviCrmApiKey()), + environmentSubstitute(((CiviOutputMeta) civiMeta).getCiviCrmSiteKey()), + environmentSubstitute(((CiviOutputMeta) civiMeta).getCiviCrmEntity())); + crUtil.setAction("CREATE"); } + return passed; + } + + public void dispose(StepMetaInterface smi, StepDataInterface sdi) { + super.dispose(smi, sdi); + } + + @Override + protected Object[] readOneRow() throws KettleException { + return null; + } } diff --git a/src/main/CiviCRMUtil/.classpath b/src/main/CiviCRMUtil/.classpath index a794c1c..cae5952 100644 --- a/src/main/CiviCRMUtil/.classpath +++ b/src/main/CiviCRMUtil/.classpath @@ -1,16 +1,16 @@ - + - - - - - - - - + + + + + + + + diff --git a/src/main/CiviCRMUtil/src/es/stratebi/civi/CiviData.java b/src/main/CiviCRMUtil/src/es/stratebi/civi/CiviData.java index 7d291f7..74ba685 100644 --- a/src/main/CiviCRMUtil/src/es/stratebi/civi/CiviData.java +++ b/src/main/CiviCRMUtil/src/es/stratebi/civi/CiviData.java @@ -12,7 +12,6 @@ import es.stratebi.civi.util.JSONString; /* - * * * Esta clase es la que mantiene los datos que se van a enviar hacia el paso que sigue. El truco que * hemos usado es crear una lista con todos aquellos valores que devueltos por el API de CIVICRM @@ -21,6 +20,7 @@ public class CiviData extends BaseStepData implements StepDataInterface { public RowMetaInterface outputRowMeta; + public RowMetaInterface previousRowMeta; public HashMap keyFields; public HashMap outputField; diff --git a/src/main/CiviCRMUtil/src/es/stratebi/civi/CiviDialog.java b/src/main/CiviCRMUtil/src/es/stratebi/civi/CiviDialog.java index b230816..99a2b3a 100644 --- a/src/main/CiviCRMUtil/src/es/stratebi/civi/CiviDialog.java +++ b/src/main/CiviCRMUtil/src/es/stratebi/civi/CiviDialog.java @@ -7,6 +7,7 @@ import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CCombo; +import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.TableItem; import org.pentaho.di.core.variables.Variables; @@ -25,7 +26,6 @@ import es.stratebi.civi.util.RestUtil; /* - * * * Este es el dialogo de conexion a la API REST de CiviCRM */ @@ -49,6 +49,11 @@ public abstract class CiviDialog extends BaseStepDialog implements StepDialogInt protected String[] comboFieldList = new String[0]; protected ColumnInfo outputFieldsColumn = null; + protected Button wCiviCrmDebugMode; + protected TextVar wCiviCrmResultField; + + protected HashMap civiCrmFields = new HashMap(); + // Constructor public CiviDialog(Shell parent, Object in, TransMeta transMeta, String sname) { super(parent, (BaseStepMeta) in, transMeta, sname); @@ -64,14 +69,15 @@ public CiviDialog(Shell parent, Object in, TransMeta transMeta, String sname) { * Ver comentario del método ok(), no obstante los valores guardados en la * clase de intercambio CiviInputMeta son leídos aquí y cargados en el * dialogo, pues este método siempre es llamado antes de hacer visible el - * mismo. Hay que notar que la primera vez que se ejecuta el dialogo al no + * mismo. Hay que notar que la primera vez que se ejecuta el dialogo y al no * tener nada guardado se usan los valores establecidos en el método * setDefault de CiviInputMeta. */ public void getData() { wStepname.selectAll(); - + + if (((CiviMeta) input).getCiviCrmRestUrl() != null) { wCiviCrmRestUrl.setText(((CiviMeta) input).getCiviCrmRestUrl()); } @@ -94,23 +100,42 @@ public void getData() { wCiviCrmEntity.setItems(eArray); } - if (((CiviMeta) input).getFields() != null) { + if (((CiviMeta) input).getCiviCrmResultField() != null) { + wCiviCrmResultField.setText(((CiviMeta) input).getCiviCrmResultField()); + } + + if (((CiviMeta) input).getCiviCrmDebugMode() != null) { + wCiviCrmDebugMode.setSelection(((CiviMeta) input).getCiviCrmDebugMode()); + } + + civiCrmFields.clear(); + if (((CiviMeta) input).getCiviCrmFields() != null) { + civiCrmFields.putAll(((CiviMeta) input).getCiviCrmFields()); + } + + if (((CiviMeta) input).getCiviCrmFields() != null) { - this.comboFieldList = new String[((CiviMeta) input).getFields().size()]; + this.comboFieldList = new String[((CiviMeta) input).getCiviCrmFields().size()]; int index = 0; - for (String cField : ((CiviMeta) input).getFields().keySet()) { + for (String cField : ((CiviMeta) input).getCiviCrmFields().keySet()) { this.comboFieldList[index++] = cField; } + Arrays.sort(this.comboFieldList); - if (((CiviMeta) input).getOutputMap() != null) { + if (((CiviMeta) input).getCiviCrmOutputMap() != null) { // Si hay elementos para salida entonces mostrarlos en la tabla int i = 0; - // for (String cFilter : ((CiviMeta) input).getOutputs().keySet()) { - for (String cField : ((CiviMeta) input).getKeyList()) { - TableItem item = tOutputFields.table.getItem(i); + for (String cField : ((CiviMeta) input).getCiviCrmKeyList()) { + TableItem item = null; + // IndexOutOfBounds Exception + if (i < tOutputFields.table.getItemCount()) { + item = new TableItem(tOutputFields.table, SWT.NONE); + } else { + item = tOutputFields.table.getItem(i); + } item.setText(1, cField); - item.setText(2, ((CiviMeta) input).getOutputMap().get(cField)); + item.setText(2, ((CiviMeta) input).getCiviCrmOutputMap().get(cField)); i++; } } @@ -118,7 +143,6 @@ public void getData() { this.comboFieldList = new String[0]; } - Arrays.sort(this.comboFieldList); this.outputFieldsColumn.setComboValues(this.comboFieldList); tOutputFields.removeEmptyRows(); @@ -131,14 +155,14 @@ public void getData() { * campos que admite la entidad, los cuales son desplegados en las tablas que * muestran los campos y filtros */ - protected void getEntityFields() { + protected boolean getEntityFields() { try { - if (((CiviMeta) input).getFields().size() > 0) { + if (((CiviMeta) input).getCiviCrmFields().size() > 0) { MessageDialog.setDefaultImage(GUIResource.getInstance().getImageSpoon()); boolean goOn = MessageDialog.openConfirm(shell, BaseMessages.getString(PKG, "CiviCrmDialog.DoMapping.ReplaceFields.Title"), BaseMessages.getString(PKG, "CiviCrmDialog.DoMapping.ReplaceFields.Msg")); if (!goOn) { - return; + return false; } } @@ -149,25 +173,24 @@ protected void getEntityFields() { RestUtil crUtil = new RestUtil(restUrl, apiKey, siteKey, "getfields", wCiviCrmEntity.getText()); - HashMap lFields = crUtil.getFieldLists(true); - ((CiviMeta) input).setFields(lFields); + civiCrmFields = crUtil.getFieldLists(true); tOutputFields.removeAll(); - this.comboFieldList = new String[lFields.size()]; + this.comboFieldList = new String[civiCrmFields.size()]; int index = 0; - for (FieldAttrs field : lFields.values()) { - TableItem outputItem = new TableItem(tOutputFields.table, SWT.NONE); - outputItem.setText(1, field.getfFieldKey()); - outputItem.setText(2, field.getfFieldKey()); - - /* - * Actualizando elementos desplegables de la tabla - */ + for (FieldAttrs field : civiCrmFields.values()) { this.comboFieldList[index++] = field.getfFieldKey(); } Arrays.sort(this.comboFieldList); + + for (String field : this.comboFieldList) { + TableItem outputItem = new TableItem(tOutputFields.table, SWT.NONE); + outputItem.setText(1, field); + outputItem.setText(2, field); + } + this.outputFieldsColumn.setComboValues(this.comboFieldList); tOutputFields.removeEmptyRows(); @@ -178,6 +201,7 @@ protected void getEntityFields() { new ErrorDialog(shell, BaseMessages.getString(PKG, "CiviCrmStep.Error.EntityListError"), e.toString().split(":")[0], e); logBasic(BaseMessages.getString(PKG, "CiviCrmStep.Error.APIExecError", e.toString())); } + return true; } protected void testConnection() { @@ -249,6 +273,7 @@ protected boolean ok() { ((CiviMeta) input).setCiviCrmApiKey(wCiviCrmApiKey.getText()); ((CiviMeta) input).setCiviCrmSiteKey(wCiviCrmSiteKey.getText()); ((CiviMeta) input).setCiviCrmEntity(wCiviCrmEntity.getText()); + ((CiviMeta) input).setCiviCrmDebugMode(wCiviCrmDebugMode.getSelection()); int nrKeys = tOutputFields.nrNonEmpty(); ArrayList keyList = new ArrayList(); @@ -268,7 +293,7 @@ protected boolean ok() { } - HashMap fields = ((CiviMeta) input).getFields(); + HashMap fields = ((CiviMeta) input).getCiviCrmFields(); boolean matchFields = true; for (String fieldKey : keyList) { matchFields = (fields.get(fieldKey) != null); @@ -284,8 +309,8 @@ protected boolean ok() { } if (matchFields) { - ((CiviMeta) input).setKeyList(keyList); - ((CiviMeta) input).setOutputMap(hOutput); + ((CiviMeta) input).setCiviCrmKeyList(keyList); + ((CiviMeta) input).setCiviCrmOutputMap(hOutput); } return matchFields; } diff --git a/src/main/CiviCRMUtil/src/es/stratebi/civi/CiviMeta.java b/src/main/CiviCRMUtil/src/es/stratebi/civi/CiviMeta.java index 350ba13..c38d04f 100644 --- a/src/main/CiviCRMUtil/src/es/stratebi/civi/CiviMeta.java +++ b/src/main/CiviCRMUtil/src/es/stratebi/civi/CiviMeta.java @@ -47,9 +47,12 @@ public abstract class CiviMeta extends BaseStepMeta implements StepMetaInterface protected String civiCrmEntity; protected ArrayList civiCrmEntityList = new ArrayList(); - protected HashMap fields = new HashMap(); + protected HashMap civiCrmFields = new HashMap(); protected HashMap outputMap = new HashMap(); - protected ArrayList keyList = new ArrayList(); + protected ArrayList civiCrmKeyList = new ArrayList(); + + protected Boolean civiCrmDebugMode; + protected String civiCrmResultField; public CiviMeta() { super(); @@ -89,23 +92,23 @@ public void setCiviCrmEntity(String civiCrmEntity) { this.civiCrmEntity = civiCrmEntity; } - public ArrayList getKeyList() { - return keyList; + public ArrayList getCiviCrmKeyList() { + return civiCrmKeyList; } - public void setKeyList(ArrayList keyList) { - this.keyList = keyList; + public void setCiviCrmKeyList(ArrayList keyList) { + this.civiCrmKeyList = keyList; } public ArrayList getCiviCrmEntityList() { return civiCrmEntityList; } - public HashMap getOutputMap() { + public HashMap getCiviCrmOutputMap() { return outputMap; } - public void setOutputMap(HashMap outputMap) { + public void setCiviCrmOutputMap(HashMap outputMap) { this.outputMap = outputMap; } @@ -113,12 +116,13 @@ public void setCiviCrmEntityList(ArrayList civiCrmEntityList) { this.civiCrmEntityList = civiCrmEntityList; } - public HashMap getFields() { - return fields; + public HashMap getCiviCrmFields() { + return civiCrmFields; } - public void setFields(HashMap fields) { - this.fields = fields; + public void setCiviCrmFields(HashMap fields) { + this.civiCrmFields.clear(); + this.civiCrmFields.putAll(fields); } /* @@ -133,6 +137,11 @@ public void setDefault() { civiCrmSiteKey = ""; civiCrmEntity = ""; civiCrmRestUrl = ""; + +// civiCrmRestUrl = "http://localhost/drupal/modules/civicrm-4.3.4-drupal/civicrm/extern/rest.php"; +// civiCrmApiKey = "juan"; +// civiCrmSiteKey = "123456789"; +// civiCrmEntity = "Contact"; } /* @@ -151,9 +160,12 @@ public void getFields(RowMetaInterface r, String origin, RowMetaInterface[] info * un atributo privado de CiviInput Aqui decimos el tipo de dato del campo */ - for (String cField : keyList) { + for (String cField : civiCrmKeyList) { try { - ValueMetaInterface v = new ValueMeta(outputMap.get(cField), getMetaInterfaceType(fields.get(cField).getfType())); + // Añadido una verifición para evitar que campos ----------> Line no existentes queden fuera de la salida del paso al + // no encontrarse en el listado de campos devuelto por CiviCRM. En este caso se asume + // que el campo es una cadena automáticamente + ValueMetaInterface v = new ValueMeta(outputMap.get(cField), (civiCrmFields.get(cField) != null) ? getMetaInterfaceType(civiCrmFields.get(cField).getfType()) : ValueMetaInterface.TYPE_STRING); v.setOrigin(origin); r.addValueMeta(v); } catch (Exception e) { @@ -166,7 +178,6 @@ public int getMetaInterfaceType(String type) { // Valor por defecto para las conversiones en caso de que no podamos // identificar la constante int returnTypeValue = ValueMetaInterface.TYPE_STRING; - try { Field f = FieldType.class.getDeclaredField("cType" + type); f.setAccessible(true); @@ -189,18 +200,18 @@ public Object clone() { // field by field copy is default CiviMeta retval = (CiviMeta) super.clone(); - retval.fields = new HashMap(); - for (FieldAttrs cField : fields.values()) { + retval.civiCrmFields = new HashMap(); + for (FieldAttrs cField : civiCrmFields.values()) { try { - retval.fields.put(cField.getfFieldKey(), (FieldAttrs) cField.clone()); + retval.civiCrmFields.put(cField.getfFieldKey(), (FieldAttrs) cField.clone()); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } - retval.keyList = new ArrayList(); - for (String kField : keyList) { - retval.keyList.add(new String(kField)); + retval.civiCrmKeyList = new ArrayList(); + for (String kField : civiCrmKeyList) { + retval.civiCrmKeyList.add(new String(kField)); } retval.outputMap = new HashMap(); @@ -212,8 +223,8 @@ public Object clone() { } /* - * Este m�todo se llama siempre antes de ejecutar una transformaci�n, aqui - * est�n los valores de cada par�metro de los pasos que la componen por lo que + * Este metodo se llama siempre antes de ejecutar una transformacion, aqui + * estan los valores de cada parametro de los pasos que la componen por lo que * lo valores que se toman son los que va a tener los atributos de cada paso * * @see org.pentaho.di.trans.step.BaseStepMeta#getXML() @@ -226,12 +237,14 @@ public String getXML() throws KettleValueException { retval.append(" ").append(XMLHandler.addTagValue("SiteKey", civiCrmSiteKey)); retval.append(" ").append(XMLHandler.addTagValue("Entity", civiCrmEntity)); retval.append(" ").append(XMLHandler.addTagValue("RestUrl", civiCrmRestUrl)); + retval.append(" ").append(XMLHandler.addTagValue("ResultField", civiCrmResultField)); + retval.append(" ").append(XMLHandler.addTagValue("DebugMode", civiCrmDebugMode)); for (String entity : civiCrmEntityList) { retval.append(" ").append(entity).append("").append(Const.CR); } - for (FieldAttrs cf : fields.values()) { + for (FieldAttrs cf : civiCrmFields.values()) { retval.append(" ").append(Const.CR); // Iterando por los campos de la clase Field[] fList = cf.getClass().getDeclaredFields(); @@ -250,7 +263,7 @@ public String getXML() throws KettleValueException { retval.append(" ").append(Const.CR); } - for (String entity : keyList) { + for (String entity : civiCrmKeyList) { retval.append(" ").append(entity).append("").append(Const.CR); } @@ -272,6 +285,8 @@ public void loadXML(Node stepnode, List databases, Map(); int totalNodes = XMLHandler.countNodes(stepnode, "entity-name"); @@ -288,7 +303,7 @@ public void loadXML(Node stepnode, List databases, Map(); + civiCrmFields = new HashMap(); for (int i = 0; i < totalNodes; i++) { Node fieldNode = XMLHandler.getSubNodeByNr(stepnode, "field", i); @@ -307,10 +322,10 @@ public void loadXML(Node stepnode, List databases, Map(); + civiCrmKeyList = new ArrayList(); totalNodes = XMLHandler.countNodes(stepnode, "key-index"); @@ -319,7 +334,7 @@ public void loadXML(Node stepnode, List databases, Map databas civiCrmSiteKey = rep.getStepAttributeString(id_step, "siteKey"); civiCrmEntity = rep.getStepAttributeString(id_step, "entity"); civiCrmRestUrl = rep.getStepAttributeString(id_step, "restUrl"); + civiCrmResultField = rep.getStepAttributeString(id_step, "resultField"); + civiCrmDebugMode = Boolean.valueOf(rep.getStepAttributeString(id_step, "civiCrmDebugMode")); int nFields = rep.countNrStepAttributes(id_step, "entityList"); for (int i = 0; i < nFields; i++) { @@ -361,17 +378,17 @@ public void readRep(Repository rep, ObjectId id_step, List databas civiCrmEntityList.add(cf); } - fields = new HashMap(); + civiCrmFields = new HashMap(); nFields = rep.countNrStepAttributes(id_step, "field"); for (int i = 0; i < nFields; i++) { FieldAttrs cf = new FieldAttrs(rep.getStepAttributeString(id_step, i, "field")); - fields.put(cf.getfFieldKey(), cf); + civiCrmFields.put(cf.getfFieldKey(), cf); } nFields = rep.countNrStepAttributes(id_step, "keyList"); for (int i = 0; i < nFields; i++) { String cf = rep.getStepAttributeString(id_step, i, "keyList"); - keyList.add(cf); + civiCrmKeyList.add(cf); } outputMap = new HashMap(); @@ -390,21 +407,23 @@ public void saveRep(Repository rep, ObjectId id_transformation, ObjectId id_step rep.saveStepAttribute(id_transformation, id_step, "apiKey", civiCrmApiKey); rep.saveStepAttribute(id_transformation, id_step, "siteKey", civiCrmSiteKey); rep.saveStepAttribute(id_transformation, id_step, "entity", civiCrmEntity); - rep.saveStepAttribute(id_transformation, id_step, "restUrl", civiCrmRestUrl); - + rep.saveStepAttribute(id_transformation, id_step, "restUrl", civiCrmRestUrl); + rep.saveStepAttribute(id_transformation, id_step, "resultField", civiCrmResultField); + rep.saveStepAttribute(id_transformation, id_step, "civiCrmDebugMode", civiCrmDebugMode); + int i = 0; for (String entity : civiCrmEntityList) { rep.saveStepAttribute(id_transformation, id_step, i++, "entityList", entity); } i = 0; - for (Iterator itField = fields.values().iterator(); itField.hasNext();) { + for (Iterator itField = civiCrmFields.values().iterator(); itField.hasNext();) { FieldAttrs field = (FieldAttrs) itField.next(); rep.saveStepAttribute(id_transformation, id_step, i++, "field", field.toString()); } i = 0; - for (String entity : keyList) { + for (String entity : civiCrmKeyList) { rep.saveStepAttribute(id_transformation, id_step, i++, "keyList", entity); } @@ -457,4 +476,20 @@ public void check(List remarks, TransMeta transmeta, StepM public abstract StepDataInterface getStepData(); + public Boolean getCiviCrmDebugMode() { + return civiCrmDebugMode; + } + + public void setCiviCrmDebugMode(Boolean civiDebugMode) { + this.civiCrmDebugMode = civiDebugMode; + } + + public String getCiviCrmResultField() { + return civiCrmResultField; + } + + public void setCiviCrmResultField(String string) { + this.civiCrmResultField = string; + } + } diff --git a/src/main/CiviCRMUtil/src/es/stratebi/civi/CiviStep.java b/src/main/CiviCRMUtil/src/es/stratebi/civi/CiviStep.java index 68750d8..3f970a4 100644 --- a/src/main/CiviCRMUtil/src/es/stratebi/civi/CiviStep.java +++ b/src/main/CiviCRMUtil/src/es/stratebi/civi/CiviStep.java @@ -19,7 +19,6 @@ import es.stratebi.civi.util.FieldAttrs; /* - * * * Esta es la clase principal y es la que lleva la logica del plugin, tiene un metodo init llamado * al inicio para definir los valores de inicializacion del paso y luego internamente en la clase @@ -63,9 +62,11 @@ protected Object getObjectValue(String field, String object) { return null; } - FieldAttrs cf = ((CiviMeta) civiMeta).getFields().get(field); + FieldAttrs cf = ((CiviMeta) civiMeta).getCiviCrmFields().get(field); - int metaType = ((CiviMeta) civiMeta).getMetaInterfaceType(cf.getfType()); + int metaType = ValueMetaInterface.TYPE_STRING; + if (cf != null) + metaType = ((CiviMeta) civiMeta).getMetaInterfaceType(cf.getfType()); switch (metaType) { case ValueMetaInterface.TYPE_INTEGER: diff --git a/src/main/CiviCRMUtil/src/es/stratebi/civi/messages/messages_en_US.properties b/src/main/CiviCRMUtil/src/es/stratebi/civi/messages/messages_en_US.properties index aa2fbcd..da20087 100644 --- a/src/main/CiviCRMUtil/src/es/stratebi/civi/messages/messages_en_US.properties +++ b/src/main/CiviCRMUtil/src/es/stratebi/civi/messages/messages_en_US.properties @@ -5,6 +5,9 @@ CiviCrmDialog.EntityGroup.Label=Entity Settings CiviCrmDialog.FilterGroup.Title=Filter Settings CiviCrmDialog.OutputFieldsGroup.Title=Output Fields +CiviCrmDialog.UpdatePreviousFields.Title=Update previous step fields +CiviCrmDialog.UpdatePreviousFields.Tooltip=Update [Input field/Value] with fields comming from previous step + CiviCrmDialog.RestURL.Label=REST URL CiviCrmDialog.RestURL.Tooltip=REST URL for lookup values @@ -20,6 +23,12 @@ CiviCrmDialog.Entity.Tooltip=Entity to lookup values CiviCrmDialog.PageSize.Label=Rows per page CiviCrmDialog.PageSize.Tooltip=Rows get on every iteration with API. Zero get all records. Default is 25. +CiviCrmDialog.DebugMode.Label=Debug mode +CiviCrmDialog.DebugMode.Tooltip=Enable CiviCRM debug mode on every call to see a log with call parameters in server side + +CiviCrmDialog.ResultFieldName.Label=Result field name +CiviCrmDialog.ResultFieldName.Tooltip=Field to put JSON result from CiviCRM API call. + CiviCrmDialog.objectType.Contacts=Contact CiviCrmDialog.objectType.Others=Others @@ -35,10 +44,15 @@ CiviCrmDialog.UpdateOutputFields.Button=Update fields CiviCrmDialog.Return.Label=Key Fields and Output Fields -CiviCrmDialog.ColumnInfo.FieldName=Field -CiviCrmDialog.ColumnInfo.FieldOutput=Output Field -CiviCrmDialog.ColumnInfo.FieldValue=Value -CiviCrmDialog.ColumnInfo.FieldRename=Rename to +CiviCrmDialog.ColumnInfo.NameField=Field +CiviCrmDialog.ColumnInfo.InputField=Input Field +CiviCrmDialog.ColumnInfo.OutputField=Output Field +CiviCrmDialog.ColumnInfo.ValueField=Value +CiviCrmDialog.ColumnInfo.RenameField=Rename to +CiviCrmDialog.ColumnInfo.StreamField=Stream Field +CiviCrmDialog.ColumnInfo.EntityField=Entity Field +CiviCrmDialog.ColumnInfo.InputValueName=Input Field/Value +CiviCrmDialog.ColumnInfo.FilterOperator=Operator CiviCrmDialog.DoMapping.ReplaceFields.Title=Fields exists in step CiviCrmDialog.DoMapping.ReplaceFields.Msg=Some fields already exists. Delete and replace with new ones? @@ -61,6 +75,8 @@ CiviCrmStep.Error.EmptyRestUrl=Error the "Rest Url" value must not be empty. CiviCrmStep.Error.EmptyEntity=Error the "Entity" name value must not be empty. CiviCrmStep.Error.APIExecError=Error executing CIVICRM API call. CiviCrmStep.Error.EntityListError=Error getting CIVICRM API Entity list. +CiviCrmStep.Error.EntityHasChange=Active entity error. +CiviCrmStep.Error.EntityHasChangeError=Active entity has changed but not fields list. Please update entity field list. CiviCrmStep.Error.UnableFindField=Unable to find key field CiviCrmStep.Error.FieldNotMatch=Field "$1" not match with active entity "$2" field list.\nPlease reload entity fields. CiviCrmStep.Error.FilterNotMatch=Field filter "$1" not match with active entity "$2" field list.\nPlease reload entity fields. @@ -75,4 +91,6 @@ CiviCrmStep.Check.MissingFieldsNotFoundInInput=Required fields not found in inpu CiviCrmStep.Check.AllFieldsFoundInInput=All required fields found CiviCrmStep.Check.CouldNotReadFromPreviousSteps=Could not read from previous steps +CiviCrmStep.Msg.LinesReaded=Lines has been readed + diff --git a/src/main/CiviCRMUtil/src/es/stratebi/civi/util/FieldAttrs.java b/src/main/CiviCRMUtil/src/es/stratebi/civi/util/FieldAttrs.java index a0e9279..b405bdc 100644 --- a/src/main/CiviCRMUtil/src/es/stratebi/civi/util/FieldAttrs.java +++ b/src/main/CiviCRMUtil/src/es/stratebi/civi/util/FieldAttrs.java @@ -3,7 +3,6 @@ import java.lang.reflect.Field; /* - * * * Aqui defino todos los atributos que pudiera tener (que he encontrado) un campo retornado por * CIVICRM para evitarme el problema de saber a quien le pongo el valor retornado y hacer multiples diff --git a/src/main/CiviCRMUtil/src/es/stratebi/civi/util/JSONString.java b/src/main/CiviCRMUtil/src/es/stratebi/civi/util/JSONString.java index 4764561..28e1533 100644 --- a/src/main/CiviCRMUtil/src/es/stratebi/civi/util/JSONString.java +++ b/src/main/CiviCRMUtil/src/es/stratebi/civi/util/JSONString.java @@ -1,15 +1,15 @@ package es.stratebi.civi.util; -import org.json.JSONObject; +//import org.json.JSONObject; public class JSONString { - public JSONObject jsonObject; + public Object jsonObject; public String jsonObjectKey; public long jsonIndex; - public JSONString(JSONObject jsonObject, long jsonIndex, String jsonObjectKey) { + public JSONString(Object jsonObject, long jsonIndex, String jsonObjectKey) { super(); this.jsonObject = jsonObject; this.jsonIndex = jsonIndex; diff --git a/src/main/CiviCRMUtil/src/es/stratebi/civi/util/RestUtil.java b/src/main/CiviCRMUtil/src/es/stratebi/civi/util/RestUtil.java index a27d1a9..c09686b 100644 --- a/src/main/CiviCRMUtil/src/es/stratebi/civi/util/RestUtil.java +++ b/src/main/CiviCRMUtil/src/es/stratebi/civi/util/RestUtil.java @@ -22,492 +22,520 @@ import org.json.JSONObject; public class RestUtil { - private String restUrl = ""; - private String apiKey = ""; - private String key = ""; - private String action = "get"; - private String fieldsAction = "getfields"; - private String entity = "Contact"; - private String options = ""; - private int limit = 25; - private int offset = 0; - private boolean isFirst = true; - private boolean isError = false; - private BufferedWriter sockedWriter; - private BufferedReader socketReader; - private Socket civiSocket; - - private HashMap aFields = new HashMap(); - - public RestUtil(String restUrl, String apiKey, String key, String entity) { - this.restUrl = restUrl; - this.apiKey = apiKey; - this.key = key; - this.entity = entity; - } + private String callUrl = ""; + private String restUrl = ""; + private String apiKey = ""; + private String key = ""; + private String action = "get"; + private String fieldsAction = "getfields"; + private String entity = "Contact"; + private String options = ""; + private int limit = 25; + private int offset = 0; + private boolean isFirst = true; + private boolean isError = false; + private boolean isDebug = false; + private BufferedWriter sockedWriter; + private BufferedReader socketReader; + private Socket civiSocket; + + private HashMap aFields = new HashMap(); + + public RestUtil(String restUrl, String apiKey, String key, String entity) { + this.restUrl = restUrl; + this.apiKey = apiKey; + this.key = key; + this.entity = entity; + } + + public RestUtil(String restUrl, String apiKey, String key, String action, String entity) { + this.restUrl = restUrl; + this.apiKey = apiKey; + this.key = key; + this.action = action; + this.entity = entity; + } + + public String getRestUrl() { + return restUrl; + } + + public void setRestUrl(String restUrl) { + this.restUrl = restUrl; + } + + public String getApiKey() { + return apiKey; + } + + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public String getFieldsAction() { + return fieldsAction; + } + + public void setFieldsAction(String fieldsAction) { + this.fieldsAction = fieldsAction; + } + + public String getEntity() { + return entity; + } + + public void setEntity(String entity) { + this.entity = entity; + } + + public String getOptions() { + return options; + } + + public void setOptions(String options) { + this.options = options; + } + + public int getLimit() { + return limit; + } + + public void setLimit(int limit) { + this.limit = limit; + } + + public int getOffset() { + return offset; + } + + public void setOffset(int offset) { + this.offset = offset; + } + + public boolean isFirst() { + return isFirst; + } + + public void setFirst(boolean isFirst) { + this.isFirst = isFirst; + } + + public HashMap getaFields() { + return aFields; + } + + public void setaFields(HashMap aFields) { + this.aFields = aFields; + } + + public boolean isError() { + return isError; + } + + public void setError(boolean isError) { + this.isError = isError; + } + + public HttpURLConnection getHttpConnection(URL url) throws IOException { + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + conn.setRequestProperty("Accept", "application/json"); - public RestUtil(String restUrl, String apiKey, String key, String action, String entity) { - this.restUrl = restUrl; - this.apiKey = apiKey; - this.key = key; - this.action = action; - this.entity = entity; + if (conn.getResponseCode() != 200) { + throw new RuntimeException("HTTP error: " + conn.getResponseCode()); } - public String getRestUrl() { - return restUrl; - } - - public void setRestUrl(String restUrl) { - this.restUrl = restUrl; - } - - public String getApiKey() { - return apiKey; - } + return conn; + } - public void setApiKey(String apiKey) { - this.apiKey = apiKey; - } + public String getJSonString(HttpURLConnection conn) throws IOException { + String response = ""; - public String getKey() { - return key; - } + InputStream input = conn.getInputStream(); + InputStreamReader streamReader = new InputStreamReader(input); + BufferedReader br = new BufferedReader(streamReader); - public void setKey(String key) { - this.key = key; - } + String line = ""; - public String getAction() { - return action; - } - - public void setAction(String action) { - this.action = action; - } + while ((line = br.readLine()) != null) { + response = response.concat(line); + } - public String getFieldsAction() { - return fieldsAction; - } + return response; + } - public void setFieldsAction(String fieldsAction) { - this.fieldsAction = fieldsAction; - } + public URL getUrl(String entity, String action, String params) throws MalformedURLException { + String urlString = ""; - public String getEntity() { - return entity; - } + urlString = restUrl + "?api_key=".concat(apiKey); + urlString = urlString + "&key=".concat(key); - public void setEntity(String entity) { - this.entity = entity; - } + urlString = urlString.concat("&json=1"); + urlString = urlString.concat("&debug=0"); + urlString = urlString.concat("&version=3"); - public String getOptions() { - return options; - } + urlString = urlString + "&entity=".concat(entity); + urlString = urlString + "&action=".concat(action); - public void setOptions(String options) { - this.options = options; - } + urlString = urlString + params; - public int getLimit() { - return limit; - } + URL url = new URL(urlString); - public void setLimit(int limit) { - this.limit = limit; - } + return url; + } - public int getOffset() { - return offset; - } + public boolean isValidJSONObject(String json) { + boolean valid; - public void setOffset(int offset) { - this.offset = offset; - } + try { + new JSONObject(json); + valid = true; + } catch (JSONException e) { + valid = false; + } - public boolean isFirst() { - return isFirst; - } + return valid; + } - public void setFirst(boolean isFirst) { - this.isFirst = isFirst; - } + public boolean isValidJSONArray(String json) { + boolean valid; - public HashMap getaFields() { - return aFields; - } + try { + new JSONArray(json); + valid = true; + } catch (JSONException e) { + valid = false; + } - public void setaFields(HashMap aFields) { - this.aFields = aFields; - } + return valid; + } - public boolean isError() { - return isError; - } + public HashMap getFieldLists(boolean reset) throws IOException, CiviCRMException { + if (reset) + getFields(); - public void setError(boolean isError) { - this.isError = isError; - } + return aFields; + } - public HttpURLConnection getHttpConnection(URL url) throws IOException { - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("GET"); - conn.setRequestProperty("Accept", "application/json"); + private void getFields() throws IOException, CiviCRMException { + try { + String params = "&options[limit]=0"; - if (conn.getResponseCode() != 200) { - throw new RuntimeException("HTTP error: " + conn.getResponseCode()); - } - - return conn; - } + URL url = getUrl(this.entity, this.fieldsAction, params); + HttpURLConnection conn = getHttpConnection(url); + String json = getJSonString(conn); - public String getJSonString(HttpURLConnection conn) throws IOException { - String response = ""; + assert isValidJSONObject(json) : "String is not a valid JSON."; - InputStream input = conn.getInputStream(); - InputStreamReader streamReader = new InputStreamReader(input); - BufferedReader br = new BufferedReader(streamReader); + JSONObject response = new JSONObject(json); - String line = ""; + // Aqui debo chequear si hay un error de acceso + if (response.get("is_error").toString().equals("1")) { + throw new CiviCRMException("CiviCRM API Error: " + response.get("error_message").toString()); + } else if (response.get("is_error").toString().equals("0") && response.get("count").toString().equals("0")) { + throw new CiviCRMException("CiviCRM Error: Entity [" + this.entity + "] has not fields or not exists "); + } else if (isValidJSONObject(response.get("values").toString())) { + JSONObject values = response.getJSONObject("values"); - while ((line = br.readLine()) != null) { - response = response.concat(line); - } + @SuppressWarnings("unchecked") + Iterator fieldIterator = values.keys(); - return response; - } + JSONObject jsonField = null; - public URL getUrl(String entity, String action, String params) throws MalformedURLException { - String urlString = ""; + while (fieldIterator.hasNext()) { + String fieldName = fieldIterator.next(); + jsonField = values.getJSONObject(fieldName); - urlString = restUrl + "?api_key=".concat(apiKey); - urlString = urlString + "&key=".concat(key); + @SuppressWarnings("unchecked") + Iterator fieldsIterator = jsonField.keys(); + FieldAttrs cf = new FieldAttrs(); + cf.setfFieldKey(fieldName); - urlString = urlString.concat("&json=1"); - urlString = urlString.concat("&debug=0"); - urlString = urlString.concat("&version=3"); + while (fieldsIterator.hasNext()) { + String fName = fieldsIterator.next(); + String fValue = jsonField.get(fName).toString(); - urlString = urlString + "&entity=".concat(entity); - urlString = urlString + "&action=".concat(action); - - urlString = urlString + params; - - URL url = new URL(urlString); - - return url; - } - - public boolean isValidJSONObject(String json) { - boolean valid; - - try { - new JSONObject(json); - valid = true; - } catch (JSONException e) { - valid = false; + try { + cf.set("f" + fName.substring(0, 1).toUpperCase() + fName.substring(1).replace(".", "_"), fValue); + } catch (Exception e) { + // e.printStackTrace(); + } + } + aFields.put(fieldName, cf); } + } else if (isValidJSONArray(response.get("values").toString())) { + JSONArray values = response.getJSONArray("values"); - return valid; + for (int i = 0; i <= values.length() - 1; i++) { + // System.out.println(values.get(i).toString()); + } + } else { + System.out.println("Error!"); + } + } catch (JSONException e) { + e.printStackTrace(); + } catch (MalformedURLException e1) { + e1.printStackTrace(); } + } - public boolean isValidJSONArray(String json) { - boolean valid; + public ArrayList getEntityList() throws IOException, JSONException, CiviCRMException { + ArrayList entityList = new ArrayList(); + URL url = getUrl("Entity", "get", ""); + HttpURLConnection conn = getHttpConnection(url); + String json = getJSonString(conn); - try { - new JSONArray(json); - valid = true; - } catch (JSONException e) { - valid = false; - } + assert isValidJSONObject(json) : "String is not a valid JSON."; - return valid; - } + JSONObject response = new JSONObject(json); - public HashMap getFieldLists(boolean reset) throws IOException, CiviCRMException { - if (reset) getFields(); - - return aFields; - } + // Aqui debo chequear si hay un error de acceso + if (response.get("is_error").toString().equals("1")) { + throw new CiviCRMException("CiviCRM API Error: " + response.get("error_message").toString()); + } else if (isValidJSONArray(response.get("values").toString())) { + JSONArray values = response.getJSONArray("values"); - private void getFields() throws IOException, CiviCRMException { - try { - String params = "&options[limit]=0"; - - URL url = getUrl(this.entity, this.fieldsAction, params); - HttpURLConnection conn = getHttpConnection(url); - String json = getJSonString(conn); - - assert isValidJSONObject(json) : "String is not a valid JSON."; - - JSONObject response = new JSONObject(json); - - // Aqui debo chequear si hay un error de acceso - if (response.get("is_error").toString().equals("1")) { - throw new CiviCRMException("CiviCRM API Error: " + response.get("error_message").toString()); - } else - if (response.get("is_error").toString().equals("0") && response.get("count").toString().equals("0")) { - throw new CiviCRMException("CiviCRM Error: Entity [" + this.entity + "] has not fields or not exists "); - } else - if (isValidJSONObject(response.get("values").toString())) { - JSONObject values = response.getJSONObject("values"); - - @SuppressWarnings("unchecked") - Iterator fieldIterator = values.keys(); - - JSONObject jsonField = null; - - while (fieldIterator.hasNext()) { - String fieldName = fieldIterator.next(); - jsonField = values.getJSONObject(fieldName); - - @SuppressWarnings("unchecked") - Iterator fieldsIterator = jsonField.keys(); - FieldAttrs cf = new FieldAttrs(); - cf.setfFieldKey(fieldName); - - while (fieldsIterator.hasNext()) { - String fName = fieldsIterator.next(); - String fValue = jsonField.get(fName).toString(); - - try { - cf.set("f" + fName.substring(0, 1).toUpperCase() + fName.substring(1).replace(".", "_"), fValue); - } catch (Exception e) { - // e.printStackTrace(); - } - } - aFields.put(fieldName, cf); - } - } else if (isValidJSONArray(response.get("values").toString())) { - JSONArray values = response.getJSONArray("values"); - - for (int i = 0; i <= values.length() - 1; i++) { - //System.out.println(values.get(i).toString()); - } - } else { - System.out.println("Error!"); - } - } catch (JSONException e) { + for (int i = 0; i <= values.length() - 1; i++) { + entityList.add(values.get(i).toString()); + } + } else { + System.out.println("Error!"); + } + return entityList; + } + + public List getNextValues() throws IOException, JSONException, CiviCRMException { + ArrayList jsonObjectList = new ArrayList(); + this.offset = (this.isFirst ? 0 : this.offset + this.limit); + this.isFirst = false; + String params = (this.options.equals("") ? "" : this.options) + "&options[limit]=" + this.limit + "&options[offset]=" + this.offset + + (isDebug ? "&debug=1" : ""); + + URL url = getUrl(entity, action, params); + this.callUrl = "GET: " + url.toString(); + HttpURLConnection conn = getHttpConnection(url); + String json = getJSonString(conn); + + assert isValidJSONObject(json) : "String is not a valid JSON."; + + JSONObject response = new JSONObject(json); + + // Aqui debo chequear si hay un error de acceso + if (response.get("is_error").toString().equals("1")) { + throw new CiviCRMException("CiviCRM API Error: " + response.get("error_message").toString()); + } else if (isValidJSONObject(response.get("values").toString())) { + JSONObject values = response.getJSONObject("values"); + + @SuppressWarnings("unchecked") + Iterator keysIterator = values.keys(); + + Object jsonObject = null; + + int index = this.offset; + // Chequear si el contenido devuelto en values es un conjunto de campos + // {k1:v1, k2:v2,...} de un objeto o un campo llave + un objeto + // id1:{k1:v1, k2:v2,...} + String k1 = (String) values.keys().next(); + if (!isValidJSONObject(values.getString(k1))) { + jsonObject = values.get(k1); + JSONString cjs = new JSONString(values, index++, "-1"); + jsonObjectList.add(cjs); + } else { + while (keysIterator.hasNext()) { + String jsonObjectKey = keysIterator.next(); + try { + // Object jsonValue = values.getJSONObject(jsonObjectKey); + jsonObject = values.get(jsonObjectKey); + JSONString cjs = new JSONString(jsonObject, index++, jsonObjectKey); + jsonObjectList.add(cjs); + } catch (Exception e) { e.printStackTrace(); - } catch (MalformedURLException e1) { - e1.printStackTrace(); + } } + } + } else if (isValidJSONArray(response.get("values").toString())) { + JSONArray values = response.getJSONArray("values"); + + for (int i = 0; i <= values.length() - 1; i++) { + // System.out.println(values.get(i).toString()); + } + } else { + System.out.println("Error!"); } - - public ArrayList getEntityList() throws IOException, JSONException, CiviCRMException { - ArrayList entityList = new ArrayList(); - URL url = getUrl("Entity", "get", ""); - HttpURLConnection conn = getHttpConnection(url); - String json = getJSonString(conn); - - assert isValidJSONObject(json) : "String is not a valid JSON."; - - JSONObject response = new JSONObject(json); - - // Aqui debo chequear si hay un error de acceso - if (response.get("is_error").toString().equals("1")) { - throw new CiviCRMException("CiviCRM API Error: " + response.get("error_message").toString()); - } else - if (isValidJSONArray(response.get("values").toString())) { - JSONArray values = response.getJSONArray("values"); - - for (int i = 0; i <= values.length() - 1; i++) { - entityList.add(values.get(i).toString()); - } - } else { - System.out.println("Error!"); - } - return entityList; - } + return jsonObjectList; + } - public List getNextValues() throws IOException, JSONException, CiviCRMException { - ArrayList jsonObjectList = new ArrayList(); - this.offset = (this.isFirst ? 0 : this.offset + this.limit); - this.isFirst = false; - String params = (this.options.equals("") ? "" : this.options) + "&options[limit]=" + this.limit - + "&options[offset]=" + this.offset; - - URL url = getUrl(entity, action, params); - HttpURLConnection conn = getHttpConnection(url); - String json = getJSonString(conn); - - - assert isValidJSONObject(json) : "String is not a valid JSON."; - - JSONObject response = new JSONObject(json); - - // Aqui debo chequear si hay un error de acceso - if (response.get("is_error").toString().equals("1")) { - throw new CiviCRMException("CiviCRM API Error: " + response.get("error_message").toString()); - } else - if (isValidJSONObject(response.get("values").toString())) { - JSONObject values = response.getJSONObject("values"); - - @SuppressWarnings("unchecked") - Iterator keysIterator = values.keys(); - - JSONObject jsonObject = null; - - int index = this.offset; - while (keysIterator.hasNext()) { - String jsonObjectKey = keysIterator.next(); - jsonObject = values.getJSONObject(jsonObjectKey); - JSONString cjs = new JSONString(jsonObject, index++, jsonObjectKey); - jsonObjectList.add(cjs); - } - } else if (isValidJSONArray(response.get("values").toString())) { - JSONArray values = response.getJSONArray("values"); - - for (int i = 0; i <= values.length() - 1; i++) { - //System.out.println(values.get(i).toString()); - } - } else { - System.out.println("Error!"); - } - return jsonObjectList; - } + public String[] preparePostUrlString(String entity, String action, String params) { + String[] preparedUrl = new String[2]; + preparedUrl[0] = restUrl; - public String[] preparePostUrlString(String entity, String action, String params) { - String[] preparedUrl = new String[2]; + preparedUrl[1] = "api_key=".concat(apiKey); + preparedUrl[1] = preparedUrl[1] + "&key=".concat(key); - preparedUrl[0] = restUrl; + preparedUrl[1] = preparedUrl[1].concat("&json=1"); + preparedUrl[1] = preparedUrl[1].concat("&debug=1"); + preparedUrl[1] = preparedUrl[1].concat("&version=3"); - - preparedUrl[1] = "api_key=".concat(apiKey); - preparedUrl[1] = preparedUrl[1] + "&key=".concat(key); + preparedUrl[1] = preparedUrl[1] + "&entity=".concat(entity); + preparedUrl[1] = preparedUrl[1] + "&action=".concat(action); - preparedUrl[1] = preparedUrl[1].concat("&json=1"); - preparedUrl[1] = preparedUrl[1].concat("&debug=1"); - preparedUrl[1] = preparedUrl[1].concat("&version=3"); + preparedUrl[1] = preparedUrl[1] + params; - preparedUrl[1] = preparedUrl[1] + "&entity=".concat(entity); - preparedUrl[1] = preparedUrl[1] + "&action=".concat(action); - - preparedUrl[1] = preparedUrl[1] + params; + return preparedUrl; + } - return preparedUrl; - } + public String putValues(String params, String filters, boolean closeConnection) { + boolean error = false; + String msg = ""; + try { + // Ver lor filtros para la actualizacion + String apiUrlString[] = preparePostUrlString(entity, action, params); + /* + * Estos dos metodos hacen lo mismo, depende del gusto el que se use, creo + * que es mejor usando socket pues es mas simple tener la traza completa + * para depurar y mantener la conexion abierta hasta finalizar + */ - public String putValues(String params, String filters, boolean closeConnection) { - boolean error = false; - String msg = ""; - try { - // Ver lor filtros para la actualizacion - String apiUrlString[] = preparePostUrlString(entity, action, params); - /* - * Estos dos metodos hacen lo mismo, depende del gusto el que se use, creo que es mejor - * usando socket pues es mas simple tener la traza completa para depurar y mantener la - * conexion abierta hasta finalizar - */ - - msg = tryPostWithUrl(apiUrlString); - //String result = tryPostWithSocket(apiUrlString, closeConnection); - // Si aparece la cadena "error_code" se ha producido un error, hay que verificar otros - // casos con la variable is_error - error = (msg.indexOf("error_code") >= 0) || (msg.indexOf("error_message") >= 0); - - } catch (Exception e) { - e.printStackTrace(); - } - if (!error) { - msg = ""; - } - return msg; - } + msg = tryPostWithUrl(apiUrlString); + // String result = tryPostWithSocket(apiUrlString, closeConnection); + // Si aparece la cadena "error_code" se ha producido un error, hay que + // verificar otros + // casos con la variable is_error - public void closeSocketConnection() { - try { - if (socketReader != null) { - socketReader.close(); - } - if (sockedWriter != null) { - sockedWriter.close(); - } - if (civiSocket != null && !civiSocket.isClosed()) { - civiSocket.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } + } catch (Exception e) { + e.printStackTrace(); } + return msg; + } + + public void closeSocketConnection() { + try { + if (socketReader != null) { + socketReader.close(); + } + if (sockedWriter != null) { + sockedWriter.close(); + } + if (civiSocket != null && !civiSocket.isClosed()) { + civiSocket.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public String tryPostWithSocket(String params[], boolean closeConnection) { + String postResult = ""; + try { + // Construct data + String data = params[1]; + URL url = new URL(params[0]); + + // Create a socket to the host + String hostname = url.getHost(); + int port = url.getPort() == -1 ? 80 : url.getPort(); + InetAddress addr = InetAddress.getByName(hostname); + if (!closeConnection && (civiSocket == null || civiSocket.isClosed())) { + civiSocket = new Socket(addr, port); + } + + // Send header + String path = url.getPath(); + if (!closeConnection && sockedWriter == null) { + sockedWriter = new BufferedWriter(new OutputStreamWriter(civiSocket.getOutputStream(), "UTF8")); + } + + sockedWriter.write("POST " + path + " HTTP/1.0\r\n"); + sockedWriter.write("Content-Length: " + data.length() + "\r\n"); + sockedWriter.write("Content-Type: application/x-www-form-urlencoded\r\n"); + sockedWriter.write("\r\n"); + + sockedWriter.write(data); + sockedWriter.flush(); + + // Get the response + if (!closeConnection && socketReader == null) { + socketReader = new BufferedReader(new InputStreamReader(civiSocket.getInputStream())); + } + String line; + while ((line = socketReader.readLine()) != null) { + postResult += line + "\n"; + } + + if (closeConnection) { + sockedWriter.close(); + socketReader.close(); + civiSocket.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } + return postResult; + } + + public String tryPostWithUrl(String params[]) { + String postResult = ""; + try { + // Construct data + String data = params[1]; + URL url = new URL(params[0]); + + data = data + (isDebug ? "&debug=1" : ""); + this.callUrl = "POST: " + url.toString() + "\nSend data: " + data; + + // Send data + URLConnection conn = url.openConnection(); + conn.setDoOutput(true); + OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream()); + + wr.write(data); + wr.flush(); + + // Get the response + BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String line; + while ((line = rd.readLine()) != null) { + postResult += line + "\n"; + } + wr.close(); + rd.close(); + } catch (Exception e) { + e.printStackTrace(); + } + return postResult; + } - public String tryPostWithSocket(String params[], boolean closeConnection) { - String postResult = ""; - try { - // Construct data - String data = params[1]; - URL url = new URL(params[0]); - - // Create a socket to the host - String hostname = url.getHost(); - int port = url.getPort() == -1 ? 80 : url.getPort(); - InetAddress addr = InetAddress.getByName(hostname); - if (!closeConnection && (civiSocket == null || civiSocket.isClosed())) { - civiSocket = new Socket(addr, port); - } - - // Send header - String path = url.getPath(); - if (!closeConnection && sockedWriter == null) { - sockedWriter = new BufferedWriter(new OutputStreamWriter(civiSocket.getOutputStream(), "UTF8")); - } - - sockedWriter.write("POST " + path + " HTTP/1.0\r\n"); - sockedWriter.write("Content-Length: " + data.length() + "\r\n"); - sockedWriter.write("Content-Type: application/x-www-form-urlencoded\r\n"); - sockedWriter.write("\r\n"); + public boolean isDebug() { + return isDebug; + } - sockedWriter.write(data); - sockedWriter.flush(); + public void setDebug(boolean isDebug) { + this.isDebug = isDebug; + } - // Get the response - if (!closeConnection && socketReader == null) { - socketReader = new BufferedReader(new InputStreamReader(civiSocket.getInputStream())); - } - String line; - while ((line = socketReader.readLine()) != null) { - postResult += line + "\n"; - } + public String getCallUrl() { + return callUrl; + } - if (closeConnection) { - sockedWriter.close(); - socketReader.close(); - civiSocket.close(); - } - } catch (Exception e) { - e.printStackTrace(); - } - return postResult; - } - - public String tryPostWithUrl(String params[]) { - String postResult = ""; - try { - // Construct data - String data = params[1]; - URL url = new URL(params[0]); - - // Send data - URLConnection conn = url.openConnection(); - conn.setDoOutput(true); - OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream()); - - wr.write(data); - wr.flush(); - - // Get the response - BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); - String line; - while ((line = rd.readLine()) != null) { - postResult += line + "\n"; - } - wr.close(); - rd.close(); - } catch (Exception e) { - e.printStackTrace(); - } - return postResult; - } + public void setCallUrl(String callUrl) { + this.callUrl = callUrl; + } }