From 8dfa6382383501bf18dfc5bf728b352c9a2c7494 Mon Sep 17 00:00:00 2001 From: "dalvarellos@genexus.com" Date: Thu, 31 Mar 2022 14:58:58 -0300 Subject: [PATCH 01/10] Implementation of the external object GXDynamicCall --- gxdynamiccall/pom.xml | 23 ++ .../genexus/gxdynamiccall/GXDynamicCall.java | 315 ++++++++++++++++++ pom.xml | 1 + 3 files changed, 339 insertions(+) create mode 100644 gxdynamiccall/pom.xml create mode 100644 gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java diff --git a/gxdynamiccall/pom.xml b/gxdynamiccall/pom.xml new file mode 100644 index 000000000..94f352a11 --- /dev/null +++ b/gxdynamiccall/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + + com.genexus + parent + 2.5-SNAPSHOT + + + gxdynamiccall + GeneXus DynamicCall external object + + + + ${project.groupId} + gxcommon + ${project.version} + + + diff --git a/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java b/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java new file mode 100644 index 000000000..61b63acb0 --- /dev/null +++ b/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java @@ -0,0 +1,315 @@ +package com.genexus.gxdynamiccall; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import com.genexus.CommonUtil; +import com.genexus.GXBaseCollection; +import com.genexus.GXSimpleCollection; +import com.genexus.SdtMessages_Message; +import com.genexus.common.interfaces.SpecificImplementation; +import com.genexus.xml.GXXMLSerializable; + +public class GXDynamicCall { + + private String defaultMethod; + private String namespace; + private String externalName; + private String packageName; + private GXXMLSerializable properties; + private Object object; + public String ObjectName; + + public GXDynamicCall() { + + namespace = null; + properties = null; + externalName = "execute"; + object = null; + } + + public GXXMLSerializable getProperties() { + return properties; + } + + public void setProperties(GXXMLSerializable props) { + try { + properties = props; + Field f; + f = props.getClass().getDeclaredField("gxTv_SdtJavaProperties_Externalname"); + f.setAccessible(true); + externalName = (String) f.get(props); + f = props.getClass().getDeclaredField("gxTv_SdtJavaProperties_Namespace"); + f.setAccessible(true); + namespace = (String) f.get(props); + f = props.getClass().getDeclaredField("gxTv_SdtJavaProperties_Packagename"); + f.setAccessible(true); + packageName = (String) f.get(props); + } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + private void VerifyDefaultProperties() { + if (packageName.isEmpty()) { + packageName = SpecificImplementation.Application.getPACKAGE(); + if (!packageName.equals("")) { + packageName += "."; + } + } + + } + + public void Execute(Object[] parametersArray, Object[] errorsArray) { + // Take the collection of Message from de array + GXBaseCollection errors = (GXBaseCollection) errorsArray[0]; + // Take the collection of parameters from de array + GXSimpleCollection parameters = (GXSimpleCollection) parametersArray[0]; + + Create(null, errors); + if (errors.size() == 0) { + try { + this.ExecuteMethod(this.object, this.defaultMethod, parameters, errors,false); + parametersArray[0] = parameters; + } catch (Exception e) { + CommonUtil.ErrorToMessages("CallMethod Error", e.getMessage(), errors); + } + } + } + + public Object Execute(Object[] parametersArray, GXXMLSerializable methodconfiguration, Object[] errorsArray) { + // Take the collection of Message from de array + GXBaseCollection errors = (GXBaseCollection) errorsArray[0]; + // Take the collection of parameters from de array + Object result=null; + Object objectToInvoke; + GXSimpleCollection parameters = (GXSimpleCollection) parametersArray[0]; + Field f; + boolean isStatic=false; + String methodName; + try { + f = methodconfiguration.getClass().getDeclaredField("gxTv_Java"); + f.setAccessible(true); + GXXMLSerializable methodPlatformSubLevel=(GXXMLSerializable) f.get(methodconfiguration); + f = methodPlatformSubLevel.getClass().getDeclaredField("gxTpr_Methodname"); + f.setAccessible(true); + methodName = (String)f.get(methodconfiguration); + f = methodPlatformSubLevel.getClass().getDeclaredField("gxTpr_Methodisstatic"); + f.setAccessible(true); + isStatic = (boolean)f.get(methodconfiguration); + if (!isStatic) + { + if (this.object != null) + { + objectToInvoke = this.object; + //result = this.ExecuteMethod(this.object, methodName.isEmpty() ? defaultMethod : methodName, parameters, errors, isStatic); + } + else + { + objectToInvoke=null; + CommonUtil.ErrorToMessages("NullInstance Error", "You must invoke create method before execute a non static one", errors); + } + } + else + { + VerifyDefaultProperties(); + Class auxClass=null; + try { + auxClass = loadClass(GXDynamicCall.class.getClassLoader(), this.externalName, packageName); + } catch (ClassNotFoundException e) { + CommonUtil.ErrorToMessages("Load class Error", e.getMessage(), errors); + } + objectToInvoke=auxClass; + } + if(errors.getItemCount()==0 && objectToInvoke!=null){ + result = this.ExecuteMethod(objectToInvoke, methodName.isEmpty() ? defaultMethod : methodName, parameters, errors, isStatic); + } + errorsArray[0]=errors; + parametersArray[0] = parameters; + } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { + CommonUtil.ErrorToMessages("MethodProperties Error", e.getMessage(), errors); + } + return result; + } + + public void Create(GXSimpleCollection constructParameters, GXBaseCollection errors) { + if (errors == null) { + errors = new GXBaseCollection(); + } + String objectNameToInvoke; + + + VerifyDefaultProperties(); + if (constructParameters == null) { + objectNameToInvoke = this.ObjectName; + } else { + objectNameToInvoke = this.externalName; + } + if (!objectNameToInvoke.isEmpty()) { + try { + Class objClass = loadClass(GXDynamicCall.class.getClassLoader(), objectNameToInvoke, packageName); + Object[] auxConstParameters; + Class[] auxConstructorTypes; + if (constructParameters != null && constructParameters.size() > 0) { + auxConstructorTypes = new Class[constructParameters.size()]; + auxConstParameters = constructParameters.toArray(); + int i = 0; + for (Object obj : constructParameters) { + auxConstructorTypes[i] = obj.getClass(); + i++; + } + } else { + auxConstParameters = (Object[]) Array.newInstance(Object.class, 0); + auxConstructorTypes = new Class[] { int.class, + SpecificImplementation.Application.getModelContextClass() }; + } + object = objClass.getConstructor(auxConstructorTypes).newInstance(auxConstParameters); + } catch (Exception e) { + CommonUtil.ErrorToMessages("CreateInstance Error", e.getMessage(), (GXBaseCollection) errors); + } + } + else{ + CommonUtil.ErrorToMessages("CreateInstance Error", "Object name not set", (GXBaseCollection) errors); + } + } + + private Object ExecuteMethod(Object objectToInvoke, String method, GXSimpleCollection params, GXBaseCollection errors, boolean isStatic) { + // Get Method + Object returnObject = null; + Method[] methods; + Method methodToExecute = null; + Class[] paramsType=new Class[params.getItemCount()]; + Object[] callingParams = new Object[params.getItemCount()]; // Array to pass to method.invoke + try{ + for (int i=0; i < params.size(); i++) { + paramsType[0]=params.get(i).getClass(); + } + if(isStatic){ + methodToExecute = ((Class)objectToInvoke).getDeclaredMethod(method,paramsType); + }else{ + methodToExecute = objectToInvoke.getClass().getMethod(method,paramsType); + } + } + catch(NoSuchMethodException e){ + + if(isStatic){ + methods = ((Class)objectToInvoke).getDeclaredMethods(); + }else{ + methods = objectToInvoke.getClass().getMethods(); + } + for (int i = 0; i < methods.length; i++) { + if (methods[i].getName().equalsIgnoreCase(method) && methods[i].getParameterCount() == params.size()) { + methodToExecute = methods[i]; + } + } + if (methodToExecute != null) { + // Create the parameters with the expected type in the method signe + Class[] destParmTypes = methodToExecute.getParameterTypes(); + Class destClass; + int i = 0; + for (Class parmType : destParmTypes) { + boolean destIsArray = parmType.isArray(); + Object parm = params.elementAt(i); + + try { + if (destIsArray) { + destClass = parmType.getComponentType(); + Object[] array = (Object[]) Array.newInstance(destClass, 1); + if (parm.getClass() != destClass) { + if (parm.getClass() != String.class) { // To avoid convert from string + array[0] = CommonUtil.convertObjectTo(parm, destClass); + } else { + CommonUtil.ErrorToMessages("CallMethod Error", "IllegalArgumentException - Type does not match", errors); + } + } else { + array[0] = parm; + } + callingParams[i] = array; + } else { + destClass = parmType.getClass(); + if (parm.getClass() != destClass) { + if (parm.getClass() != String.class) { // To avoid convert from string + callingParams[i] = CommonUtil.convertObjectTo(parm, destClass); + } else { + CommonUtil.ErrorToMessages("CallMethod Error", "IllegalArgumentException - Type does not match", errors); + } + } else { + callingParams[i] = parm; + } + } + i++; + } catch (Exception ex) { + CommonUtil.ErrorToMessages("CallMethod Error", ex.getMessage(), errors); + } + } + } + else{ + CommonUtil.ErrorToMessages("CallMethod Error","NoSuchMethodException - Cant finde method: " + method + "with " + params.size() + " parameters", errors); + } + } + if (methodToExecute != null) { + try { + // Execute the method + returnObject = methodToExecute.invoke(isStatic?null:objectToInvoke, callingParams); + updateParams(params, callingParams); + } catch (Exception e) { + CommonUtil.ErrorToMessages("CallMethod Error", e.getMessage(), errors); + } + } else { + CommonUtil.ErrorToMessages("CallMethod Error","NoSuchMethodException - Cant finde method: " + method + "with " + params.size() + " parameters", errors); + } + return returnObject; + } + + private static void updateParams(GXSimpleCollection originalParameter, Object[] callingParams) + throws Exception { + + for (int i = 0; i < callingParams.length; i++) { + Object parm = originalParameter.get(i); + Object objectToUpdate; + if (callingParams[i].getClass().isArray()) { + Object[] auxArg = (Object[]) callingParams[i]; + if (auxArg[0].getClass() != parm.getClass()) { + objectToUpdate = CommonUtil.convertObjectTo(auxArg[0], parm.getClass()); + } else { + objectToUpdate = auxArg[0]; + } + } else { + if (callingParams[i].getClass() != parm.getClass()) { + objectToUpdate = CommonUtil.convertObjectTo(callingParams[i], parm.getClass()); + } else { + objectToUpdate = callingParams[i]; + } + } + originalParameter.set(i, objectToUpdate); + } + } + + private Class loadClass(ClassLoader cLoader, String className, String sPackage) throws ClassNotFoundException { + String classPackage = SpecificImplementation.Application.getPACKAGE(); + if (!classPackage.equals("")) + classPackage += "."; + String pgmName = CommonUtil.getObjectName(sPackage, className); + Class c = null; + if (!classPackage.equals(sPackage)) { + + try { + c = Class.forName(pgmName); + } catch (ClassNotFoundException e) { + pgmName = CommonUtil.getObjectName(classPackage, className); + } + } + + if (c == null) { + if (cLoader == null) { + c = Class.forName(pgmName); + } else { + + c = cLoader.loadClass(pgmName); + } + } + return c; + } + +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index e6f18be6f..9bbece15b 100644 --- a/pom.xml +++ b/pom.xml @@ -29,6 +29,7 @@ java gxandroidpublisher gxcryptocommon + gxdynamiccall gxmail gxmaps gxoffice From cfa286f246e6edefec12d8a5c0a47d24e09687aa Mon Sep 17 00:00:00 2001 From: "dalvarellos@genexus.com" Date: Fri, 1 Apr 2022 10:58:43 -0300 Subject: [PATCH 02/10] Fix errors array in create method --- .../genexus/gxdynamiccall/GXDynamicCall.java | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java b/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java index 61b63acb0..6ac23a11b 100644 --- a/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java +++ b/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java @@ -25,11 +25,12 @@ public GXDynamicCall() { namespace = null; properties = null; - externalName = "execute"; + externalName = null; object = null; + defaultMethod = "execute"; } - public GXXMLSerializable getProperties() { + public Object getProperties() { return properties; } @@ -51,6 +52,14 @@ public void setProperties(GXXMLSerializable props) { } } + public String getObjectName(){ + return ObjectName; + } + + public void setObjectName(String name){ + this.ObjectName=name; + } + private void VerifyDefaultProperties() { if (packageName.isEmpty()) { packageName = SpecificImplementation.Application.getPACKAGE(); @@ -62,12 +71,12 @@ private void VerifyDefaultProperties() { } public void Execute(Object[] parametersArray, Object[] errorsArray) { - // Take the collection of Message from de array - GXBaseCollection errors = (GXBaseCollection) errorsArray[0]; // Take the collection of parameters from de array GXSimpleCollection parameters = (GXSimpleCollection) parametersArray[0]; - Create(null, errors); + Create(null, errorsArray); + // Take the collection of Message from de array + GXBaseCollection errors = (GXBaseCollection) errorsArray[0]; if (errors.size() == 0) { try { this.ExecuteMethod(this.object, this.defaultMethod, parameters, errors,false); @@ -133,9 +142,10 @@ public Object Execute(Object[] parametersArray, GXXMLSerializable methodconfigur return result; } - public void Create(GXSimpleCollection constructParameters, GXBaseCollection errors) { + public void Create(GXSimpleCollection constructParameters, Object[] errors) { if (errors == null) { - errors = new GXBaseCollection(); + errors = (Object[]) Array.newInstance(Object.class, 1); + errors[0]=new GXBaseCollection(); } String objectNameToInvoke; @@ -166,11 +176,11 @@ public void Create(GXSimpleCollection constructParameters, GXBaseCollect } object = objClass.getConstructor(auxConstructorTypes).newInstance(auxConstParameters); } catch (Exception e) { - CommonUtil.ErrorToMessages("CreateInstance Error", e.getMessage(), (GXBaseCollection) errors); + CommonUtil.ErrorToMessages("CreateInstance Error", e.getMessage(), (GXBaseCollection) errors[0]); } } else{ - CommonUtil.ErrorToMessages("CreateInstance Error", "Object name not set", (GXBaseCollection) errors); + CommonUtil.ErrorToMessages("CreateInstance Error", "Object name not set", (GXBaseCollection) errors[0]); } } From 49f964ae1c76a4c3c2bdbcdf285c443a77a2abe9 Mon Sep 17 00:00:00 2001 From: "dalvarellos@genexus.com" Date: Sun, 3 Apr 2022 21:24:35 -0300 Subject: [PATCH 03/10] Refactoring EODynamicCall --- .../gxdynamiccall/GXDynCallMethodConf.java | 27 ++ .../gxdynamiccall/GXDynCallProperties.java | 23 ++ .../genexus/gxdynamiccall/GXDynamicCall.java | 230 ++++++------------ 3 files changed, 123 insertions(+), 157 deletions(-) create mode 100644 gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynCallMethodConf.java create mode 100644 gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynCallProperties.java diff --git a/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynCallMethodConf.java b/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynCallMethodConf.java new file mode 100644 index 000000000..b2678d320 --- /dev/null +++ b/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynCallMethodConf.java @@ -0,0 +1,27 @@ +package com.genexus.gxdynamiccall; + +public class GXDynCallMethodConf { + private boolean isStatic; + private String methodName; + + public GXDynCallMethodConf(){ + isStatic=false; + methodName="execute"; + } + + public void setIsStatic(boolean is){ + isStatic=is; + } + public boolean getIsStatic(){ + return isStatic; + } + + public void setMethodName(String mn){ + methodName=mn; + } + + public String getMethodName(){ + return methodName; + } + +} diff --git a/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynCallProperties.java b/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynCallProperties.java new file mode 100644 index 000000000..3e168defa --- /dev/null +++ b/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynCallProperties.java @@ -0,0 +1,23 @@ +package com.genexus.gxdynamiccall; + +public class GXDynCallProperties { + private String externalName; + private String packageName; + + public String getExternalName() { + return externalName; + } + public void setExternalName(String name) { + externalName = name; + } + public String getPackageName() { + return packageName; + } + public void setPackageName(String packageN) { + packageName = packageN; + } + + + + +} diff --git a/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java b/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java index 6ac23a11b..964d42816 100644 --- a/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java +++ b/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java @@ -1,7 +1,6 @@ package com.genexus.gxdynamiccall; import java.lang.reflect.Array; -import java.lang.reflect.Field; import java.lang.reflect.Method; import com.genexus.CommonUtil; @@ -9,156 +8,88 @@ import com.genexus.GXSimpleCollection; import com.genexus.SdtMessages_Message; import com.genexus.common.interfaces.SpecificImplementation; -import com.genexus.xml.GXXMLSerializable; public class GXDynamicCall { - private String defaultMethod; - private String namespace; private String externalName; private String packageName; - private GXXMLSerializable properties; - private Object object; - public String ObjectName; + private GXDynCallProperties properties; + private Object instanceObject; + private String objectName; - public GXDynamicCall() { - - namespace = null; - properties = null; - externalName = null; - object = null; - defaultMethod = "execute"; - } - - public Object getProperties() { + + public GXDynCallProperties getProperties() { return properties; } - public void setProperties(GXXMLSerializable props) { - try { - properties = props; - Field f; - f = props.getClass().getDeclaredField("gxTv_SdtJavaProperties_Externalname"); - f.setAccessible(true); - externalName = (String) f.get(props); - f = props.getClass().getDeclaredField("gxTv_SdtJavaProperties_Namespace"); - f.setAccessible(true); - namespace = (String) f.get(props); - f = props.getClass().getDeclaredField("gxTv_SdtJavaProperties_Packagename"); - f.setAccessible(true); - packageName = (String) f.get(props); - } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { - e.printStackTrace(); - } + public void setProperties(GXDynCallProperties properties) { + this.properties = properties; + packageName = properties.getPackageName()==null?SpecificImplementation.Application.getPACKAGE():packageName; + externalName = properties.getExternalName(); } public String getObjectName(){ - return ObjectName; + return objectName; } public void setObjectName(String name){ - this.ObjectName=name; - } - - private void VerifyDefaultProperties() { - if (packageName.isEmpty()) { - packageName = SpecificImplementation.Application.getPACKAGE(); - if (!packageName.equals("")) { - packageName += "."; - } - } - + objectName=name; } - public void Execute(Object[] parametersArray, Object[] errorsArray) { - // Take the collection of parameters from de array - GXSimpleCollection parameters = (GXSimpleCollection) parametersArray[0]; - - Create(null, errorsArray); - // Take the collection of Message from de array - GXBaseCollection errors = (GXBaseCollection) errorsArray[0]; - if (errors.size() == 0) { - try { - this.ExecuteMethod(this.object, this.defaultMethod, parameters, errors,false); - parametersArray[0] = parameters; - } catch (Exception e) { - CommonUtil.ErrorToMessages("CallMethod Error", e.getMessage(), errors); - } - } + public void execute(Object[] parametersArray, Object[] errorsArray) { + //Create the instance with default constructor + create(null, errorsArray); + //Create methodconfiguration + GXDynCallMethodConf method = new GXDynCallMethodConf(); + //Execute with thefault method configuration + execute(parametersArray, method, errorsArray); } - public Object Execute(Object[] parametersArray, GXXMLSerializable methodconfiguration, Object[] errorsArray) { - // Take the collection of Message from de array - GXBaseCollection errors = (GXBaseCollection) errorsArray[0]; + public Object execute(Object[] parametersArray, GXDynCallMethodConf methodConfiguration, Object[] errorsArray) { + + GXBaseCollection errors =new GXBaseCollection(); // Take the collection of parameters from de array + GXSimpleCollection parameters = (GXSimpleCollection) parametersArray[0]; Object result=null; Object objectToInvoke; - GXSimpleCollection parameters = (GXSimpleCollection) parametersArray[0]; - Field f; - boolean isStatic=false; - String methodName; - try { - f = methodconfiguration.getClass().getDeclaredField("gxTv_Java"); - f.setAccessible(true); - GXXMLSerializable methodPlatformSubLevel=(GXXMLSerializable) f.get(methodconfiguration); - f = methodPlatformSubLevel.getClass().getDeclaredField("gxTpr_Methodname"); - f.setAccessible(true); - methodName = (String)f.get(methodconfiguration); - f = methodPlatformSubLevel.getClass().getDeclaredField("gxTpr_Methodisstatic"); - f.setAccessible(true); - isStatic = (boolean)f.get(methodconfiguration); - if (!isStatic) + if (!methodConfiguration.getIsStatic()) + { + if (instanceObject != null) { - if (this.object != null) - { - objectToInvoke = this.object; - //result = this.ExecuteMethod(this.object, methodName.isEmpty() ? defaultMethod : methodName, parameters, errors, isStatic); - } - else - { - objectToInvoke=null; - CommonUtil.ErrorToMessages("NullInstance Error", "You must invoke create method before execute a non static one", errors); - } + objectToInvoke = instanceObject; } else { - VerifyDefaultProperties(); - Class auxClass=null; - try { - auxClass = loadClass(GXDynamicCall.class.getClassLoader(), this.externalName, packageName); - } catch (ClassNotFoundException e) { - CommonUtil.ErrorToMessages("Load class Error", e.getMessage(), errors); - } - objectToInvoke=auxClass; + objectToInvoke=null; + CommonUtil.ErrorToMessages("NullInstance Error", "You must invoke create method before execute a non static one", errors); + return null; } - if(errors.getItemCount()==0 && objectToInvoke!=null){ - result = this.ExecuteMethod(objectToInvoke, methodName.isEmpty() ? defaultMethod : methodName, parameters, errors, isStatic); + } + else + { + Class auxClass=null; + try { + auxClass = loadClass(externalName, packageName); + } catch (ClassNotFoundException e) { + CommonUtil.ErrorToMessages("Load class Error", e.getMessage(), errors); + errorsArray[0]=errors; + return null; } - errorsArray[0]=errors; - parametersArray[0] = parameters; - } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { - CommonUtil.ErrorToMessages("MethodProperties Error", e.getMessage(), errors); + objectToInvoke=auxClass; } + result = executeMethod(objectToInvoke,methodConfiguration.getMethodName(), parameters, errors, methodConfiguration.getIsStatic()); + errorsArray[0]=errors; + parametersArray[0] = parameters; return result; } - public void Create(GXSimpleCollection constructParameters, Object[] errors) { - if (errors == null) { - errors = (Object[]) Array.newInstance(Object.class, 1); - errors[0]=new GXBaseCollection(); - } + public void create(GXSimpleCollection constructParameters, Object[] errors) { + GXBaseCollection error =new GXBaseCollection(); String objectNameToInvoke; - - - VerifyDefaultProperties(); - if (constructParameters == null) { - objectNameToInvoke = this.ObjectName; - } else { - objectNameToInvoke = this.externalName; - } + objectNameToInvoke = constructParameters==null?objectName:externalName; if (!objectNameToInvoke.isEmpty()) { try { - Class objClass = loadClass(GXDynamicCall.class.getClassLoader(), objectNameToInvoke, packageName); + Class objClass = loadClass(objectNameToInvoke, packageName); Object[] auxConstParameters; Class[] auxConstructorTypes; if (constructParameters != null && constructParameters.size() > 0) { @@ -174,23 +105,24 @@ public void Create(GXSimpleCollection constructParameters, Object[] erro auxConstructorTypes = new Class[] { int.class, SpecificImplementation.Application.getModelContextClass() }; } - object = objClass.getConstructor(auxConstructorTypes).newInstance(auxConstParameters); + instanceObject = objClass.getConstructor(auxConstructorTypes).newInstance(auxConstParameters); } catch (Exception e) { - CommonUtil.ErrorToMessages("CreateInstance Error", e.getMessage(), (GXBaseCollection) errors[0]); + CommonUtil.ErrorToMessages("CreateInstance Error", e.getMessage(), (GXBaseCollection) error); } } else{ - CommonUtil.ErrorToMessages("CreateInstance Error", "Object name not set", (GXBaseCollection) errors[0]); + CommonUtil.ErrorToMessages("CreateInstance Error", "Object name not set", (GXBaseCollection) error); } + errors[0]=error; } - private Object ExecuteMethod(Object objectToInvoke, String method, GXSimpleCollection params, GXBaseCollection errors, boolean isStatic) { - // Get Method + private Object executeMethod(Object objectToInvoke, String method, GXSimpleCollection params, GXBaseCollection errors, boolean isStatic) { + Object returnObject = null; Method[] methods; Method methodToExecute = null; - Class[] paramsType=new Class[params.getItemCount()]; - Object[] callingParams = new Object[params.getItemCount()]; // Array to pass to method.invoke + Class[] paramsType=new Class[params.size()]; + Object[] callingParams = new Object[params.size()]; // Array to pass to method.invoke try{ for (int i=0; i < params.size(); i++) { paramsType[0]=params.get(i).getClass(); @@ -231,6 +163,7 @@ private Object ExecuteMethod(Object objectToInvoke, String method, GXSimpleColle array[0] = CommonUtil.convertObjectTo(parm, destClass); } else { CommonUtil.ErrorToMessages("CallMethod Error", "IllegalArgumentException - Type does not match", errors); + return null; } } else { array[0] = parm; @@ -243,6 +176,7 @@ private Object ExecuteMethod(Object objectToInvoke, String method, GXSimpleColle callingParams[i] = CommonUtil.convertObjectTo(parm, destClass); } else { CommonUtil.ErrorToMessages("CallMethod Error", "IllegalArgumentException - Type does not match", errors); + return null; } } else { callingParams[i] = parm; @@ -251,24 +185,25 @@ private Object ExecuteMethod(Object objectToInvoke, String method, GXSimpleColle i++; } catch (Exception ex) { CommonUtil.ErrorToMessages("CallMethod Error", ex.getMessage(), errors); + return null; } } } else{ CommonUtil.ErrorToMessages("CallMethod Error","NoSuchMethodException - Cant finde method: " + method + "with " + params.size() + " parameters", errors); + return null; } } - if (methodToExecute != null) { - try { - // Execute the method - returnObject = methodToExecute.invoke(isStatic?null:objectToInvoke, callingParams); - updateParams(params, callingParams); - } catch (Exception e) { - CommonUtil.ErrorToMessages("CallMethod Error", e.getMessage(), errors); - } - } else { - CommonUtil.ErrorToMessages("CallMethod Error","NoSuchMethodException - Cant finde method: " + method + "with " + params.size() + " parameters", errors); + + try { + // Execute the method + returnObject = methodToExecute.invoke(isStatic?null:objectToInvoke, callingParams); + updateParams(params, callingParams); + } catch (Exception e) { + CommonUtil.ErrorToMessages("CallMethod Error", e.getMessage(), errors); + return null; } + return returnObject; } @@ -296,30 +231,11 @@ private static void updateParams(GXSimpleCollection originalParameter, O } } - private Class loadClass(ClassLoader cLoader, String className, String sPackage) throws ClassNotFoundException { - String classPackage = SpecificImplementation.Application.getPACKAGE(); - if (!classPackage.equals("")) - classPackage += "."; - String pgmName = CommonUtil.getObjectName(sPackage, className); - Class c = null; - if (!classPackage.equals(sPackage)) { - - try { - c = Class.forName(pgmName); - } catch (ClassNotFoundException e) { - pgmName = CommonUtil.getObjectName(classPackage, className); - } - } - - if (c == null) { - if (cLoader == null) { - c = Class.forName(pgmName); - } else { - - c = cLoader.loadClass(pgmName); - } - } + private Class loadClass(String className, String sPackage) throws ClassNotFoundException { + String classPackage = sPackage + "." + className; + Class c = Class.forName(classPackage);; return c; } - +//usar .size +//returns y no preguntar por los null } \ No newline at end of file From d33093e8b8fadf07b89b3cc72436024b1cfe9762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Echag=C3=BCe?= Date: Wed, 6 Apr 2022 14:15:38 -0300 Subject: [PATCH 04/10] Update to version 2.6 --- gxdynamiccall/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gxdynamiccall/pom.xml b/gxdynamiccall/pom.xml index 94f352a11..b564b9e07 100644 --- a/gxdynamiccall/pom.xml +++ b/gxdynamiccall/pom.xml @@ -7,7 +7,7 @@ com.genexus parent - 2.5-SNAPSHOT + 2.6-SNAPSHOT gxdynamiccall From ae76085bc21d534ffbda58e5311e69b983b39135 Mon Sep 17 00:00:00 2001 From: "dalvarellos@genexus.com" Date: Wed, 6 Apr 2022 17:54:21 -0300 Subject: [PATCH 05/10] Unit test and minors changes --- gxdynamiccall/client.cfg | 127 ++++++++++++++++++ gxdynamiccall/pom.xml | 5 + gxdynamiccall/server.cfg | 127 ++++++++++++++++++ .../genexus/gxdynamiccall/GXDynamicCall.java | 62 ++++++--- .../DynamicCallExternalTestProcedure.java | 17 +++ .../test/DynamicCallTestProcedure.java | 78 +++++++++++ .../gxdynamiccall/test/GxDynamicCallTest.java | 89 ++++++++++++ 7 files changed, 488 insertions(+), 17 deletions(-) create mode 100644 gxdynamiccall/client.cfg create mode 100644 gxdynamiccall/server.cfg create mode 100644 gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/DynamicCallExternalTestProcedure.java create mode 100644 gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/DynamicCallTestProcedure.java create mode 100644 gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GxDynamicCallTest.java diff --git a/gxdynamiccall/client.cfg b/gxdynamiccall/client.cfg new file mode 100644 index 000000000..728e2a37d --- /dev/null +++ b/gxdynamiccall/client.cfg @@ -0,0 +1,127 @@ +[Client] +MODEL_NUM= 2 +GENERATOR_NUM= 12 +LOGIN_AS_USERID=0 +SMTP_HOST= +NAME_SPACE= com.genexus.gxdynamiccall.test +NAME_HOST= +CORBA_SERVER_NAME= +DCOM_GUID= +CONN_TIMEOUT=300 +HELP_MODE=WINHTML +HELP_BASEURL= +PREFERRED_UI=BEST +JFC_LF=NATIVE +CALENDAR=1 +CALC=1 +WP_RESIZE=1 +SHOW_STATUS=1 +FIELD_EXIT=Tab +ESCAPE_FUNCTION=Exit_form +KEY_REFRESH=5 +KEY_PROMPT=4 +MDI_FORMS=1 +REMOTE_CALLS=NEVER +IMAGE_SUBST=0 +CS_CONNECT=First +CS_REORG=1 +CS_REORGJAVA=1 +SUBFILE_ORDER=Y +FC_READONLY=GRAYED +PACKAGE=com.genexus.gxdynamiccall.test +DECIMAL_POINT=. +DATE_FMT= MDY +CTOD_DATE_FMT= L +BLANK_EMPTY_DATE=0 +TIME_FMT=12 +YEAR_LIMIT=40 +COMPRESS_HTML=1 +DocumentType=HTML5 +IE_COMPATIBILITY_VIEW=EmulateIE7 +EXPOSE_METADATA= 0 +WEB_IMAGE_DIR=/static +HTTP_BACKEND_URL= +WEB_STATIC_DIR= +ORQ_CLIENT_URL= +ORQ_SERVER_DIR= +TMPMEDIA_DIR=PrivateTempStorage +PRINT_LAYOUT_METADATA_DIR=LayoutMetadata +HTTP_PROTOCOL=Unsecure +SAMESITE_COOKIE=Lax +StorageTimeZone= 1 +GX_BUILD_NUMBER=1302769 +ODBC_CALLS=0 +NameSpace1= com.genexus.gxdynamiccall.test +LANGUAGE=eng +LANG_NAME=English +Theme=Carmine +CS_BLOB_PATH=PublicTempStorage +SUBMIT_POOL_SIZE=5 +CACHE_TTL_0=-1 +CACHE_TTL_1=60 +CACHE_TTL_2=600 +CACHE_TTL_3=0 +CACHE_STORAGE_SIZE=0 +CACHING=0 +SMART_CACHING=0 +CACHE_INVALIDATION_TOKEN=20224512174246 +EVENT_BEFORE_COMMIT= +EVENT_AFTER_COMMIT= +EVENT_BEFORE_ROLLBACK= +EVENT_AFTER_ROLLBACK= +EVENT_BEFORE_CONNECT= +EVENT_AFTER_CONNECT= +ENABLE_MANAGEMENT=0 +EnableIntegratedSecurity=0 +IntegratedSecurityLoginWeb= +IntegratedSecurityNotAuthorizedWeb= +HTTPCLIENT_MAX_SIZE=1000 +HTTPCLIENT_MAX_PER_ROUTE=1000 +VER_STAMP= +[language|English] +code= eng +time_fmt= 12 +decimal_point= . +thousand_sep= , +date_fmt= MDY +culture= en-US +[com.genexus.gxdynamiccall.test] +GXDB_LOCATION= +JTA=0 +DataSource1=DEFAULT +JDBC_LOG= +JDBCLogEnabled=0 +JDBCUniqueName=0 +JDBCLogPath= +JDBCLogLevel=0 +JDBCLogBuffer=0 +JDBCLogDetail=0 +[com.genexus.gxdynamiccall.test|DEFAULT] +CS_DBNAME=KbPrueba +INFORMIX_DB=ANSI +CS_LIBL400= +CS_PACKAGE400= +DB2400_DATE_DATATYPE= +CS_SCHEMA= +USER_ID=Elj20MqY44RPdvT8FEpDD0== +USER_PASSWORD=tjRYpiaJ+HYQ0GpWgRGwfo8w59nKWO7H1rRFYPoZo/w= +CS_CONNECT=First +WAIT_RECORD=0 +LOCK_RETRY=10 +LoginInServer=1 +JDBC_DRIVER=net.sourceforge.jtds.jdbc.Driver +DB_URL=jdbc:jtds:sqlserver://GXN1088:1433/KbPrueba +USE_JDBC_DATASOURCE=0 +JDBC_DATASOURCE= +MAX_CURSOR=100 +INITIALIZE_NEW=1 +ISOLATION_LEVEL=CR +XBASE_TINT=1 +DBMS=sqlserver +UnlimitedRWPool=1 +PoolRWEnabled=1 +RecycleRW=1 +RecycleRWType=1 +RecycleRWMin=30 +POOLSIZE_RW=10 +POOL_STARTUP=0 diff --git a/gxdynamiccall/pom.xml b/gxdynamiccall/pom.xml index 94f352a11..7e13405ab 100644 --- a/gxdynamiccall/pom.xml +++ b/gxdynamiccall/pom.xml @@ -19,5 +19,10 @@ gxcommon ${project.version} + + ${project.groupId} + gxclassR + ${project.version} + diff --git a/gxdynamiccall/server.cfg b/gxdynamiccall/server.cfg new file mode 100644 index 000000000..362cf5617 --- /dev/null +++ b/gxdynamiccall/server.cfg @@ -0,0 +1,127 @@ +[Client] +MODEL_NUM= 2 +GENERATOR_NUM= 12 +LOGIN_AS_USERID=0 +SMTP_HOST= +NAME_SPACE= com.genexus.gxdynamiccall.test +NAME_HOST= +CORBA_SERVER_NAME= +DCOM_GUID= +CONN_TIMEOUT=300 +HELP_MODE=WINHTML +HELP_BASEURL= +PREFERRED_UI=BEST +JFC_LF=NATIVE +CALENDAR=1 +CALC=1 +WP_RESIZE=1 +SHOW_STATUS=1 +FIELD_EXIT=Tab +ESCAPE_FUNCTION=Exit_form +KEY_REFRESH=5 +KEY_PROMPT=4 +MDI_FORMS=1 +REMOTE_CALLS=NEVER +IMAGE_SUBST=0 +CS_CONNECT=First +CS_REORG=1 +CS_REORGJAVA=1 +SUBFILE_ORDER=Y +FC_READONLY=GRAYED +PACKAGE=com.genexus.gxdynamiccall.test +DECIMAL_POINT=. +DATE_FMT= MDY +CTOD_DATE_FMT= L +BLANK_EMPTY_DATE=0 +TIME_FMT=12 +YEAR_LIMIT=40 +COMPRESS_HTML=1 +DocumentType=HTML5 +IE_COMPATIBILITY_VIEW=EmulateIE7 +EXPOSE_METADATA= 0 +WEB_IMAGE_DIR=/static +HTTP_BACKEND_URL= +WEB_STATIC_DIR= +ORQ_CLIENT_URL= +ORQ_SERVER_DIR= +TMPMEDIA_DIR=PrivateTempStorage +PRINT_LAYOUT_METADATA_DIR=LayoutMetadata +HTTP_PROTOCOL=Unsecure +SAMESITE_COOKIE=Lax +StorageTimeZone= 1 +GX_BUILD_NUMBER=1302769 +ODBC_CALLS=0 +NameSpace1= com.genexus.gxdynamiccall.test +LANGUAGE=eng +LANG_NAME=English +Theme=Carmine +CS_BLOB_PATH=PublicTempStorage +SUBMIT_POOL_SIZE=5 +CACHE_TTL_0=-1 +CACHE_TTL_1=60 +CACHE_TTL_2=600 +CACHE_TTL_3=0 +CACHE_STORAGE_SIZE=0 +CACHING=0 +SMART_CACHING=0 +CACHE_INVALIDATION_TOKEN=20224512174246 +EVENT_BEFORE_COMMIT= +EVENT_AFTER_COMMIT= +EVENT_BEFORE_ROLLBACK= +EVENT_AFTER_ROLLBACK= +EVENT_BEFORE_CONNECT= +EVENT_AFTER_CONNECT= +ENABLE_MANAGEMENT=0 +EnableIntegratedSecurity=0 +IntegratedSecurityLoginWeb= +IntegratedSecurityNotAuthorizedWeb= +HTTPCLIENT_MAX_SIZE=1000 +HTTPCLIENT_MAX_PER_ROUTE=1000 +VER_STAMP= +[language|English] +code= eng +time_fmt= 12 +decimal_point= . +thousand_sep= , +date_fmt= MDY +culture= en-US +[com.genexus.gxdynamiccall.test] +GXDB_LOCATION= +JTA=0 +DataSource1=DEFAULT +JDBC_LOG= +JDBCLogEnabled=0 +JDBCUniqueName=0 +JDBCLogPath= +JDBCLogLevel=0 +JDBCLogBuffer=0 +JDBCLogDetail=0 +[com.genexus.gxdynamiccall.test|DEFAULT] +CS_DBNAME=KbPrueba +INFORMIX_DB=ANSI +CS_LIBL400= +CS_PACKAGE400= +DB2400_DATE_DATATYPE= +CS_SCHEMA= +USER_ID=Elj20MqY44RPdvT8FEpDD0== +USER_PASSWORD=tjRYpiaJ+HYQ0GpWgRGwfo8w59nKWO7H1rRFYPoZo/w= +CS_CONNECT=First +WAIT_RECORD=0 +LOCK_RETRY=10 +LoginInServer=1 +JDBC_DRIVER=net.sourceforge.jtds.jdbc.Driver +DB_URL=jdbc:jtds:sqlserver://GXN1088:1433/KbPrueba +USE_JDBC_DATASOURCE=0 +JDBC_DATASOURCE= +MAX_CURSOR=100 +INITIALIZE_NEW=1 +ISOLATION_LEVEL=CR +XBASE_TINT=1 +DBMS=sqlserver +UnlimitedRWPool=1 +PoolRWEnabled=1 +RecycleRW=1 +RecycleRWType=1 +RecycleRWMin=30 +POOLSIZE_RW=10 +POOL_STARTUP=0 diff --git a/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java b/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java index 964d42816..69823b6b8 100644 --- a/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java +++ b/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java @@ -1,11 +1,13 @@ package com.genexus.gxdynamiccall; import java.lang.reflect.Array; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import com.genexus.CommonUtil; import com.genexus.GXBaseCollection; import com.genexus.GXSimpleCollection; +import com.genexus.ModelContext; import com.genexus.SdtMessages_Message; import com.genexus.common.interfaces.SpecificImplementation; @@ -24,8 +26,8 @@ public GXDynCallProperties getProperties() { public void setProperties(GXDynCallProperties properties) { this.properties = properties; - packageName = properties.getPackageName()==null?SpecificImplementation.Application.getPACKAGE():packageName; - externalName = properties.getExternalName(); + packageName = properties.getPackageName()==null?SpecificImplementation.Application.getPACKAGE():properties.getPackageName(); + externalName = properties.getExternalName()==null?objectName:properties.getExternalName(); } public String getObjectName(){ @@ -40,9 +42,11 @@ public void execute(Object[] parametersArray, Object[] errorsArray) { //Create the instance with default constructor create(null, errorsArray); //Create methodconfiguration - GXDynCallMethodConf method = new GXDynCallMethodConf(); - //Execute with thefault method configuration - execute(parametersArray, method, errorsArray); + if(errorsArray.length>0){ + GXDynCallMethodConf method = new GXDynCallMethodConf(); + //Execute with default method configuration + execute(parametersArray, method, errorsArray); + } } public Object execute(Object[] parametersArray, GXDynCallMethodConf methodConfiguration, Object[] errorsArray) { @@ -86,6 +90,7 @@ public Object execute(Object[] parametersArray, GXDynCallMethodConf methodConfig public void create(GXSimpleCollection constructParameters, Object[] errors) { GXBaseCollection error =new GXBaseCollection(); String objectNameToInvoke; + Constructor constructor=null; objectNameToInvoke = constructParameters==null?objectName:externalName; if (!objectNameToInvoke.isEmpty()) { try { @@ -97,23 +102,45 @@ public void create(GXSimpleCollection constructParameters, Object[] erro auxConstParameters = constructParameters.toArray(); int i = 0; for (Object obj : constructParameters) { - auxConstructorTypes[i] = obj.getClass(); + auxConstructorTypes[i] = obj.getClass(); i++; } - } else { - auxConstParameters = (Object[]) Array.newInstance(Object.class, 0); - auxConstructorTypes = new Class[] { int.class, - SpecificImplementation.Application.getModelContextClass() }; + } else { + auxConstParameters = new Object[] {Integer.valueOf(-1)}; + auxConstructorTypes = new Class[] {int.class}; + } + try{ + constructor = objClass.getConstructor(auxConstructorTypes); + }catch(Exception e1){ + Constructor [] constructors = objClass.getConstructors(); + for (Constructor acutualCons : constructors) { + if(acutualCons.getParameterCount() == Array.getLength(auxConstParameters)){ + constructor=acutualCons; + + } + } + } + if(constructor != null){ + instanceObject=constructor.newInstance(auxConstParameters); + } + else{ + CommonUtil.ErrorToMessages("CreateInstance Error", "None constructor found", error); + errors[0]=error; + return; } - instanceObject = objClass.getConstructor(auxConstructorTypes).newInstance(auxConstParameters); } catch (Exception e) { - CommonUtil.ErrorToMessages("CreateInstance Error", e.getMessage(), (GXBaseCollection) error); + CommonUtil.ErrorToMessages("CreateInstance Error", e.getMessage(), error); + e.printStackTrace(); + errors[0]=error; + return; } } else{ - CommonUtil.ErrorToMessages("CreateInstance Error", "Object name not set", (GXBaseCollection) error); + CommonUtil.ErrorToMessages("CreateInstance Error", "Object name not set", error); + errors[0]=error; + return; } - errors[0]=error; + } private Object executeMethod(Object objectToInvoke, String method, GXSimpleCollection params, GXBaseCollection errors, boolean isStatic) { @@ -232,10 +259,11 @@ private static void updateParams(GXSimpleCollection originalParameter, O } private Class loadClass(String className, String sPackage) throws ClassNotFoundException { - String classPackage = sPackage + "." + className; + String classPackage=""; + if(sPackage != null) + classPackage+= sPackage + "."; + classPackage+= className; Class c = Class.forName(classPackage);; return c; } -//usar .size -//returns y no preguntar por los null } \ No newline at end of file diff --git a/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/DynamicCallExternalTestProcedure.java b/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/DynamicCallExternalTestProcedure.java new file mode 100644 index 000000000..b3172693a --- /dev/null +++ b/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/DynamicCallExternalTestProcedure.java @@ -0,0 +1,17 @@ +package com.genexus.gxdynamiccall.test; + +public class DynamicCallExternalTestProcedure { + private int multiplier = 1; + public DynamicCallExternalTestProcedure(int multiplier){ + this.multiplier=multiplier; + } + + public String calculateAsString(int a, int b) { + return String.valueOf((a + b )* multiplier); + } + + public static String sumAsString(int a, int b){ + return String.valueOf((a + b )); + } + +} diff --git a/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/DynamicCallTestProcedure.java b/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/DynamicCallTestProcedure.java new file mode 100644 index 000000000..d14e388ea --- /dev/null +++ b/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/DynamicCallTestProcedure.java @@ -0,0 +1,78 @@ +package com.genexus.gxdynamiccall.test; +import com.genexus.*; + +public final class DynamicCallTestProcedure extends GXProcedure +{ + public DynamicCallTestProcedure( int remoteHandle ) + { + super( remoteHandle , new ModelContext( DynamicCallTestProcedure.class ), "" ); + } + + public DynamicCallTestProcedure( int remoteHandle , + ModelContext context ) + { + super( remoteHandle , context, "" ); + } + + @SuppressWarnings("unchecked") + public String executeUdp( short aP0 , + short aP1 ) + { + DynamicCallTestProcedure.this.aP2 = new String[] {""}; + execute_int(aP0, aP1, aP2); + return aP2[0]; + } + + public void execute( short aP0 , + short aP1 , + String[] aP2 ) + { + execute_int(aP0, aP1, aP2); + } + + private void execute_int( short aP0 , + short aP1 , + String[] aP2 ) + { + DynamicCallTestProcedure.this.AV8varchar1 = aP0; + DynamicCallTestProcedure.this.AV9varchar2 = aP1; + DynamicCallTestProcedure.this.aP2 = aP2; + initialize(); + /* GeneXus formulas */ + /* Output device settings */ + privateExecute(); + } + + private void privateExecute( ) + { + AV11numAux = (short)(AV8varchar1+AV9varchar2) ; + AV10varchar3 = GXutil.str( AV11numAux, 4, 0) ; + cleanup(); + } + + protected void cleanup( ) + { + this.aP2[0] = DynamicCallTestProcedure.this.AV10varchar3; + CloseOpenCursors(); + exitApp(); + } + + protected void CloseOpenCursors( ) + { + } + + /* Aggregate/select formulas */ + public void initialize( ) + { + AV10varchar3 = "" ; + /* GeneXus formulas. */ + Gx_err = (short)(0) ; + } + + private short AV8varchar1 ; + private short AV9varchar2 ; + private short AV11numAux ; + private short Gx_err ; + private String AV10varchar3 ; + private String[] aP2 ; +} diff --git a/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GxDynamicCallTest.java b/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GxDynamicCallTest.java new file mode 100644 index 000000000..6f2ba8ba2 --- /dev/null +++ b/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GxDynamicCallTest.java @@ -0,0 +1,89 @@ +package com.genexus.gxdynamiccall.test; +import com.genexus.GXBaseCollection; +import com.genexus.GXSimpleCollection; +import com.genexus.gxdynamiccall.GXDynCallMethodConf; +import com.genexus.gxdynamiccall.GXDynCallProperties; +import com.genexus.gxdynamiccall.GXDynamicCall; +import com.genexus.specific.java.Connect; + +import org.junit.Assert; +import org.junit.Test; + +public class GxDynamicCallTest { + + @Test + public void callGxNativeObject(){ + Connect.init(); + GXDynamicCall call = new GXDynamicCall(); + call.setObjectName("com.genexus.gxdynamiccall.test.DynamicCallTestProcedure"); + GXSimpleCollection paramArray = new GXSimpleCollection(); + paramArray.add((short)3); + paramArray.add((short)4); + paramArray.add(new String()); + Object[] parametersArray = {paramArray}; + Object[] errorsArray= new Object[1]; + call.execute(parametersArray, errorsArray); + Assert.assertTrue(((GXBaseCollection)errorsArray[0]).size()==0); + GXSimpleCollection parms= (GXSimpleCollection)parametersArray[0]; + String parm = ((String)parms.get(2)).trim(); + Assert.assertTrue(parm.equals("7")); + } + + @Test + public void callExternalClass(){ + Connect.init(); + GXDynamicCall call = new GXDynamicCall(); + GXDynCallProperties props = new GXDynCallProperties(); + Object[] errorsArray= new Object[1]; + props.setExternalName("DynamicCallExternalTestProcedure"); + props.setPackageName("com.genexus.gxdynamiccall.test"); + call.setProperties(props); + //Constructor + GXSimpleCollection constructParamArray = new GXSimpleCollection(); + constructParamArray.add((int)3); + call.create(constructParamArray, errorsArray); + //Parameters + GXSimpleCollection paramArray = new GXSimpleCollection(); + paramArray.add((short)3); + paramArray.add((short)4); + Object[] parametersArray = {paramArray}; + //MethodConfiguration + GXDynCallMethodConf method = new GXDynCallMethodConf(); + method.setIsStatic(false); + method.setMethodName("calculateAsString"); + String result = (String)call.execute(parametersArray, method, errorsArray); + Assert.assertTrue(((GXBaseCollection)errorsArray[0]).size()==0); + Assert.assertTrue(result.trim().equals("21")); + paramArray.clear(); + paramArray.add((short)4); + paramArray.add((short)4); + parametersArray[0]=paramArray; + result = (String)call.execute(parametersArray, method, errorsArray); + Assert.assertTrue(((GXBaseCollection)errorsArray[0]).size()==0); + Assert.assertTrue(result.trim().equals("24")); + } + + @Test + public void callExternalClassWithStaticMethod(){ + Connect.init(); + GXDynamicCall call = new GXDynamicCall(); + GXDynCallProperties props = new GXDynCallProperties(); + Object[] errorsArray= new Object[1]; + props.setExternalName("DynamicCallExternalTestProcedure"); + props.setPackageName("com.genexus.gxdynamiccall.test"); + call.setProperties(props); + //Parameters + GXSimpleCollection paramArray = new GXSimpleCollection(); + paramArray.add((short)3); + paramArray.add((short)4); + Object[] parametersArray = {paramArray}; + //MethodConfiguration + GXDynCallMethodConf method = new GXDynCallMethodConf(); + method.setIsStatic(true); + method.setMethodName("sumAsString"); + String result = (String)call.execute(parametersArray, method, errorsArray); + Assert.assertTrue(((GXBaseCollection)errorsArray[0]).size()==0); + Assert.assertTrue(result.trim().equals("7")); + } + +} \ No newline at end of file From ef91b030c87468d5c9980da35d31f8cab0cabf7c Mon Sep 17 00:00:00 2001 From: "dalvarellos@genexus.com" Date: Mon, 11 Apr 2022 15:32:50 -0300 Subject: [PATCH 06/10] Change array for vector --- .../genexus/gxdynamiccall/GXDynamicCall.java | 31 +++++++------- .../gxdynamiccall/test/GxDynamicCallTest.java | 40 +++++++++---------- 2 files changed, 33 insertions(+), 38 deletions(-) diff --git a/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java b/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java index 69823b6b8..43482e2cb 100644 --- a/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java +++ b/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java @@ -3,11 +3,10 @@ import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Method; +import java.util.Vector; import com.genexus.CommonUtil; import com.genexus.GXBaseCollection; -import com.genexus.GXSimpleCollection; -import com.genexus.ModelContext; import com.genexus.SdtMessages_Message; import com.genexus.common.interfaces.SpecificImplementation; @@ -38,22 +37,20 @@ public void setObjectName(String name){ objectName=name; } - public void execute(Object[] parametersArray, Object[] errorsArray) { + public void execute(Vector parameters, Vector errorsArray) { //Create the instance with default constructor create(null, errorsArray); //Create methodconfiguration - if(errorsArray.length>0){ + if(errorsArray.size()==0){ GXDynCallMethodConf method = new GXDynCallMethodConf(); //Execute with default method configuration - execute(parametersArray, method, errorsArray); + execute(parameters, method, errorsArray); } } - public Object execute(Object[] parametersArray, GXDynCallMethodConf methodConfiguration, Object[] errorsArray) { + public Object execute(Vector parameters, GXDynCallMethodConf methodConfiguration, Vector errorsArray) { GXBaseCollection errors =new GXBaseCollection(); - // Take the collection of parameters from de array - GXSimpleCollection parameters = (GXSimpleCollection) parametersArray[0]; Object result=null; Object objectToInvoke; if (!methodConfiguration.getIsStatic()) @@ -66,6 +63,7 @@ public Object execute(Object[] parametersArray, GXDynCallMethodConf methodConfig { objectToInvoke=null; CommonUtil.ErrorToMessages("NullInstance Error", "You must invoke create method before execute a non static one", errors); + errorsArray.addAll(errors.getStruct()); return null; } } @@ -76,18 +74,17 @@ public Object execute(Object[] parametersArray, GXDynCallMethodConf methodConfig auxClass = loadClass(externalName, packageName); } catch (ClassNotFoundException e) { CommonUtil.ErrorToMessages("Load class Error", e.getMessage(), errors); - errorsArray[0]=errors; + errorsArray.addAll(errors.getStruct()); return null; } objectToInvoke=auxClass; } result = executeMethod(objectToInvoke,methodConfiguration.getMethodName(), parameters, errors, methodConfiguration.getIsStatic()); - errorsArray[0]=errors; - parametersArray[0] = parameters; + errorsArray.addAll(errors.getStruct()); return result; } - public void create(GXSimpleCollection constructParameters, Object[] errors) { + public void create(Vector constructParameters, Vector errors) { GXBaseCollection error =new GXBaseCollection(); String objectNameToInvoke; Constructor constructor=null; @@ -125,25 +122,25 @@ public void create(GXSimpleCollection constructParameters, Object[] erro } else{ CommonUtil.ErrorToMessages("CreateInstance Error", "None constructor found", error); - errors[0]=error; + errors.addAll(error.getStruct()); return; } } catch (Exception e) { CommonUtil.ErrorToMessages("CreateInstance Error", e.getMessage(), error); e.printStackTrace(); - errors[0]=error; + errors.addAll(error.getStruct()); return; } } else{ CommonUtil.ErrorToMessages("CreateInstance Error", "Object name not set", error); - errors[0]=error; + errors.addAll(error.getStruct()); return; } } - private Object executeMethod(Object objectToInvoke, String method, GXSimpleCollection params, GXBaseCollection errors, boolean isStatic) { + private Object executeMethod(Object objectToInvoke, String method, Vector params, GXBaseCollection errors, boolean isStatic) { Object returnObject = null; Method[] methods; @@ -234,7 +231,7 @@ private Object executeMethod(Object objectToInvoke, String method, GXSimpleColle return returnObject; } - private static void updateParams(GXSimpleCollection originalParameter, Object[] callingParams) + private static void updateParams(Vector originalParameter, Object[] callingParams) throws Exception { for (int i = 0; i < callingParams.length; i++) { diff --git a/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GxDynamicCallTest.java b/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GxDynamicCallTest.java index 6f2ba8ba2..dc47560ef 100644 --- a/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GxDynamicCallTest.java +++ b/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GxDynamicCallTest.java @@ -1,6 +1,7 @@ package com.genexus.gxdynamiccall.test; import com.genexus.GXBaseCollection; import com.genexus.GXSimpleCollection; +import com.genexus.SdtMessages_Message; import com.genexus.gxdynamiccall.GXDynCallMethodConf; import com.genexus.gxdynamiccall.GXDynCallProperties; import com.genexus.gxdynamiccall.GXDynamicCall; @@ -9,6 +10,8 @@ import org.junit.Assert; import org.junit.Test; +import java.util.Vector; + public class GxDynamicCallTest { @Test @@ -16,16 +19,14 @@ public void callGxNativeObject(){ Connect.init(); GXDynamicCall call = new GXDynamicCall(); call.setObjectName("com.genexus.gxdynamiccall.test.DynamicCallTestProcedure"); - GXSimpleCollection paramArray = new GXSimpleCollection(); + Vector paramArray = new Vector<>(); paramArray.add((short)3); paramArray.add((short)4); paramArray.add(new String()); - Object[] parametersArray = {paramArray}; - Object[] errorsArray= new Object[1]; - call.execute(parametersArray, errorsArray); - Assert.assertTrue(((GXBaseCollection)errorsArray[0]).size()==0); - GXSimpleCollection parms= (GXSimpleCollection)parametersArray[0]; - String parm = ((String)parms.get(2)).trim(); + Vector errorsArray= new Vector<>(); + call.execute(paramArray, errorsArray); + Assert.assertTrue(errorsArray.size()==0); + String parm = ((String)paramArray.get(2)).trim(); Assert.assertTrue(parm.equals("7")); } @@ -34,32 +35,30 @@ public void callExternalClass(){ Connect.init(); GXDynamicCall call = new GXDynamicCall(); GXDynCallProperties props = new GXDynCallProperties(); - Object[] errorsArray= new Object[1]; + Vector errorsArray= new Vector<>(); props.setExternalName("DynamicCallExternalTestProcedure"); props.setPackageName("com.genexus.gxdynamiccall.test"); call.setProperties(props); //Constructor - GXSimpleCollection constructParamArray = new GXSimpleCollection(); + Vector constructParamArray = new Vector<>(); constructParamArray.add((int)3); call.create(constructParamArray, errorsArray); //Parameters - GXSimpleCollection paramArray = new GXSimpleCollection(); + Vector paramArray = new Vector<>(); paramArray.add((short)3); paramArray.add((short)4); - Object[] parametersArray = {paramArray}; //MethodConfiguration GXDynCallMethodConf method = new GXDynCallMethodConf(); method.setIsStatic(false); method.setMethodName("calculateAsString"); - String result = (String)call.execute(parametersArray, method, errorsArray); - Assert.assertTrue(((GXBaseCollection)errorsArray[0]).size()==0); + String result = (String)call.execute(paramArray, method, errorsArray); + Assert.assertTrue(errorsArray.size()==0); Assert.assertTrue(result.trim().equals("21")); paramArray.clear(); paramArray.add((short)4); paramArray.add((short)4); - parametersArray[0]=paramArray; - result = (String)call.execute(parametersArray, method, errorsArray); - Assert.assertTrue(((GXBaseCollection)errorsArray[0]).size()==0); + result = (String)call.execute(paramArray, method, errorsArray); + Assert.assertTrue(errorsArray.size()==0); Assert.assertTrue(result.trim().equals("24")); } @@ -68,21 +67,20 @@ public void callExternalClassWithStaticMethod(){ Connect.init(); GXDynamicCall call = new GXDynamicCall(); GXDynCallProperties props = new GXDynCallProperties(); - Object[] errorsArray= new Object[1]; + Vector errorsArray= new Vector<>(); props.setExternalName("DynamicCallExternalTestProcedure"); props.setPackageName("com.genexus.gxdynamiccall.test"); call.setProperties(props); //Parameters - GXSimpleCollection paramArray = new GXSimpleCollection(); + Vector paramArray = new Vector<>(); paramArray.add((short)3); paramArray.add((short)4); - Object[] parametersArray = {paramArray}; //MethodConfiguration GXDynCallMethodConf method = new GXDynCallMethodConf(); method.setIsStatic(true); method.setMethodName("sumAsString"); - String result = (String)call.execute(parametersArray, method, errorsArray); - Assert.assertTrue(((GXBaseCollection)errorsArray[0]).size()==0); + String result = (String)call.execute(paramArray, method, errorsArray); + Assert.assertTrue(errorsArray.size()==0); Assert.assertTrue(result.trim().equals("7")); } From 695d9365630acf1134bcae899e86a359b624f237 Mon Sep 17 00:00:00 2001 From: "dalvarellos@genexus.com" Date: Tue, 12 Apr 2022 14:26:48 -0300 Subject: [PATCH 07/10] Fix convertion type --- .../main/java/com/genexus/gxdynamiccall/GXDynamicCall.java | 7 +++---- .../com/genexus/gxdynamiccall/test/GxDynamicCallTest.java | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java b/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java index 43482e2cb..2a805df00 100644 --- a/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java +++ b/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java @@ -149,7 +149,7 @@ private Object executeMethod(Object objectToInvoke, String method, Vector)objectToInvoke).getDeclaredMethod(method,paramsType); @@ -194,10 +194,9 @@ private Object executeMethod(Object objectToInvoke, String method, Vector paramArray = new Vector<>(); - paramArray.add((short)3); + paramArray.add(Double.parseDouble("3")); paramArray.add((short)4); paramArray.add(new String()); Vector errorsArray= new Vector<>(); From 1916869ccb9a32f8ec6d6c006197b18f2e4fbaf6 Mon Sep 17 00:00:00 2001 From: "dalvarellos@genexus.com" Date: Tue, 17 May 2022 16:45:42 -0300 Subject: [PATCH 08/10] Fixe External class call scenario --- .../genexus/gxdynamiccall/GXDynamicCall.java | 18 ++++++++++-------- .../gxdynamiccall/test/GxDynamicCallTest.java | 6 ++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java b/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java index 2a805df00..d514b8daa 100644 --- a/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java +++ b/gxdynamiccall/src/main/java/com/genexus/gxdynamiccall/GXDynamicCall.java @@ -12,29 +12,31 @@ public class GXDynamicCall { - private String externalName; - private String packageName; private GXDynCallProperties properties; private Object instanceObject; private String objectName; - + public GXDynamicCall(){ + properties = new GXDynCallProperties(); + properties.setPackageName(SpecificImplementation.Application.getPACKAGE()); + } + public GXDynCallProperties getProperties() { return properties; } public void setProperties(GXDynCallProperties properties) { this.properties = properties; - packageName = properties.getPackageName()==null?SpecificImplementation.Application.getPACKAGE():properties.getPackageName(); - externalName = properties.getExternalName()==null?objectName:properties.getExternalName(); } public String getObjectName(){ return objectName; + } public void setObjectName(String name){ objectName=name; + properties.setExternalName(name); } public void execute(Vector parameters, Vector errorsArray) { @@ -71,7 +73,7 @@ public Object execute(Vector parameters, GXDynCallMethodConf methodConfi { Class auxClass=null; try { - auxClass = loadClass(externalName, packageName); + auxClass = loadClass(properties.getExternalName(),properties.getPackageName()); } catch (ClassNotFoundException e) { CommonUtil.ErrorToMessages("Load class Error", e.getMessage(), errors); errorsArray.addAll(errors.getStruct()); @@ -88,10 +90,10 @@ public void create(Vector constructParameters, Vector error =new GXBaseCollection(); String objectNameToInvoke; Constructor constructor=null; - objectNameToInvoke = constructParameters==null?objectName:externalName; + objectNameToInvoke = constructParameters==null?objectName:properties.getExternalName(); if (!objectNameToInvoke.isEmpty()) { try { - Class objClass = loadClass(objectNameToInvoke, packageName); + Class objClass = loadClass(objectNameToInvoke, properties.getPackageName()); Object[] auxConstParameters; Class[] auxConstructorTypes; if (constructParameters != null && constructParameters.size() > 0) { diff --git a/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GxDynamicCallTest.java b/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GxDynamicCallTest.java index 51d0a5fbb..7a3f22374 100644 --- a/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GxDynamicCallTest.java +++ b/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GxDynamicCallTest.java @@ -34,11 +34,9 @@ public void callGxNativeObject(){ public void callExternalClass(){ Connect.init(); GXDynamicCall call = new GXDynamicCall(); - GXDynCallProperties props = new GXDynCallProperties(); Vector errorsArray= new Vector<>(); - props.setExternalName("DynamicCallExternalTestProcedure"); - props.setPackageName("com.genexus.gxdynamiccall.test"); - call.setProperties(props); + call.getProperties().setExternalName("DynamicCallExternalTestProcedure"); + call.getProperties().setPackageName("com.genexus.gxdynamiccall.test"); //Constructor Vector constructParamArray = new Vector<>(); constructParamArray.add((int)3); From d1fc595ebdcfbfa64e90609e2e920884b7e24c39 Mon Sep 17 00:00:00 2001 From: "dalvarellos@genexus.com" Date: Wed, 18 May 2022 17:13:58 -0300 Subject: [PATCH 09/10] Fix test for DynamicCall --- .../com/genexus/gxdynamiccall/test/GXcfg.java | 12 ++++++++++++ .../gxdynamiccall/test/GxDynamicCallTest.java | 15 +++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GXcfg.java diff --git a/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GXcfg.java b/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GXcfg.java new file mode 100644 index 000000000..ee785eef2 --- /dev/null +++ b/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GXcfg.java @@ -0,0 +1,12 @@ +package com.genexus.gxdynamiccall.test; +import com.genexus.*; + +public final class GXcfg +{ + public static int strcmp( String Left , + String Right ) + { + return GXutil.rtrim(Left).compareTo(GXutil.rtrim(Right)); + } + +} \ No newline at end of file diff --git a/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GxDynamicCallTest.java b/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GxDynamicCallTest.java index 7a3f22374..d36e15677 100644 --- a/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GxDynamicCallTest.java +++ b/gxdynamiccall/src/test/java/com/genexus/gxdynamiccall/test/GxDynamicCallTest.java @@ -1,4 +1,5 @@ package com.genexus.gxdynamiccall.test; +import com.genexus.Application; import com.genexus.GXBaseCollection; import com.genexus.GXSimpleCollection; import com.genexus.SdtMessages_Message; @@ -16,9 +17,9 @@ public class GxDynamicCallTest { @Test public void callGxNativeObject(){ - Connect.init(); + Application.init(com.genexus.gxdynamiccall.test.GXcfg.class); GXDynamicCall call = new GXDynamicCall(); - call.setObjectName("com.genexus.gxdynamiccall.test.DynamicCallTestProcedure"); + call.setObjectName("DynamicCallTestProcedure"); Vector paramArray = new Vector<>(); paramArray.add(Double.parseDouble("3")); paramArray.add((short)4); @@ -32,7 +33,7 @@ public void callGxNativeObject(){ @Test public void callExternalClass(){ - Connect.init(); + Application.init(com.genexus.gxdynamiccall.test.GXcfg.class); GXDynamicCall call = new GXDynamicCall(); Vector errorsArray= new Vector<>(); call.getProperties().setExternalName("DynamicCallExternalTestProcedure"); @@ -62,13 +63,11 @@ public void callExternalClass(){ @Test public void callExternalClassWithStaticMethod(){ - Connect.init(); + Application.init(com.genexus.gxdynamiccall.test.GXcfg.class); GXDynamicCall call = new GXDynamicCall(); - GXDynCallProperties props = new GXDynCallProperties(); + call.getProperties().setExternalName("DynamicCallExternalTestProcedure"); + call.getProperties().setPackageName("com.genexus.gxdynamiccall.test"); Vector errorsArray= new Vector<>(); - props.setExternalName("DynamicCallExternalTestProcedure"); - props.setPackageName("com.genexus.gxdynamiccall.test"); - call.setProperties(props); //Parameters Vector paramArray = new Vector<>(); paramArray.add((short)3); From 2b4d61ca6db6fa76f18fbdbf3b071eba2ea25cec Mon Sep 17 00:00:00 2001 From: "dalvarellos@genexus.com" Date: Tue, 13 Sep 2022 15:55:27 -0300 Subject: [PATCH 10/10] GxDynamicCall pom fix --- gxdynamiccall/pom.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gxdynamiccall/pom.xml b/gxdynamiccall/pom.xml index 7f352b2f0..39e0493b6 100644 --- a/gxdynamiccall/pom.xml +++ b/gxdynamiccall/pom.xml @@ -4,11 +4,11 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - - com.genexus - parent - 2.6-SNAPSHOT - + + com.genexus + parent + ${revision}${changelist} + gxdynamiccall GeneXus DynamicCall external object