This post is machine-translated. The original post in german language can be found here.
These post applies to following version:
Dynamics AX 2012
Dynamics AX 2012
|
|
|
|
|
|
|
This post is machine-translated. The original post in german language can be found here.
These post applies to following version:
Dynamics AX 2012
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Anyone who has ever implemented a function using the SysOperation framework knows that creating the necessary (up to) four classes is some work.
lazyefficient contemporaries I have therefore developed the following job, with the help of this time-consuming work can be significantly shortened.In the job you have to set an "base name", which is used for naming the four classes (Controller, Dataprovider, UIBuilder and Service).
In addition there is a map called dataContractParmsMap from - unless you have inserted content in this map - matching parm methods are created when generating the data provider. In example job the map contains two entries for a customer account number and an item number.
How these classes will look like and which methods are generated, the above screenshot is showing.
static void dev_createSysOperationClasses(Args _args) { str 40 baseClassName = "DEV_SysOpTest"; // Your base class name str attributes; Set interfacesSet; str 100 uiBuilderName; str 100 dataContractName; str 100 serviceName; str 100 controllerName; ClassNode createdClassNode; SetIterator interfaceIterator; str runServiceMethodStr; str customMethodStr; ClassBuild classBuildCompile; Map dataContractParmsMap; MapEnumerator dataContractParmsME; Source parmMethodSourcecode; xppSource xppSource; Counter c; Dialog dialog; DialogField df_baseName; #AOT ClassNode createSysOperationClasses(str _newClassName, str _extendsClassName, Set _implementsInterfaces, str _attributes) { // Inspired from SysClassWizard::createEmptyClass() ClassBuild classBuild; str header; SetIterator implementsIterator; ; if(_attributes) { header += _attributes + ' '; } header += 'public class '+_newClassName; if (_extendsClassName) { header = header + ' extends '+_extendsClassName; } if (_implementsInterfaces && _implementsInterfaces.elements() > 0) { implementsIterator = new SetIterator(_implementsInterfaces); implementsIterator.begin(); header = header + ' implements ' + implementsIterator.value() ; implementsIterator.next(); while (implementsIterator.more()) { header = header + ', ' + implementsIterator.value(); implementsIterator.next(); } } classBuild = new ClassBuild(_newClassName); classBuild.addMethod(methodStr(SysClassWizard, classDeclaration), header + ' { } '); classBuild.classNode().AOTcompile(1); return classBuild.classNode(); } void createAbstractMethods(ClassBuild _newclass) { // Inspired from SysClassWizard.createAbstractMethods() DictClass dictClass; DictMethod dictMethod; DictMethod dictMethodFound; SysDictClass sysDictClassNew; int i; int methodActualClassId; ; dictClass = new DictClass(className2Id(_newclass.name())); sysDictClassNew = new SysDictClass(dictClass.id()); while (dictClass.extend() > 0) { dictClass = new DictClass(dictClass.extend()); for (i=1; i<dictClass.objectMethodCnt(); i++) { dictMethod = dictClass.objectMethodObject(i); if (dictMethod.isAbstract()) { // check if method is alreade implemented methodActualClassId = sysDictClassNew.methodsActualClassId(dictMethod.name()); if (methodActualClassId != sysDictClassNew.id()) { dictMethodFound = new DictMethod(UtilElementType::ClassInstanceMethod, methodActualClassId, dictMethod.name()); if ( dictMethodFound && dictMethodFound.isAbstract() ) { _newclass.overrideMethod(dictMethod.name()); } } } } } } void createInterfaceMethods(str _interfaceName, ClassBuild _newclass, boolean _overrideParentMethods) { // Inspired from SysClassWizard.createInterfaceMethods() ClassNode sourceNode; TreeNodeIterator methodIterator; MemberFunction method; str todoString; ; sourceNode = TreeNode::findNode(#ClassesPath + '' + _interfaceName); if (!sourceNode) { Box::warning("@SYS65036"); return; } methodIterator = sourceNode.AOTiterator(); if (methodIterator) { method = methodIterator.next(); while (method) { if (method.treeNodeName() != methodStr(SysClassWizard, classDeclaration) && (_overrideParentMethods) || (!_newclass.getMethodImplementation(method.treeNodeName(), true))) { _newclass.addMethod(method.treeNodeName(), method.AOTgetSource()); todoString = strFmt(' //TODO: %1 ', strFmt("@SYS73931", method.treeNodeName())); _newclass.addSourceToMethod(method.treeNodeName(),todoString); } method = methodIterator.next(); } } } uiBuilderName = strFmt("%1%2", baseClassName, "UIBuilder"); dataContractName = strFmt("%1%2", baseClassName, "DataContract"); serviceName = strFmt("%1%2", baseClassName, "Service"); controllerName = strFmt("%1%2", baseClassName, "Controller"); // Use this map to create parm-Methods, if needed dataContractParmsMap = new Map(Types::String, Types::String); // 1=EDT, 2=Name of variable //dataContractParmsMap.insert("CustAccount", "myCustAccount"); //dataContractParmsMap.insert("ItemId", "myItemId"); dataContractParmsME = dataContractParmsMap.getEnumerator(); // Validation if( !baseClassName) { throw error(Error::wrongUseOfFunction(funcName())); } if(strLen(uiBuilderName) > 40) { setPrefix(uiBuilderName); throw error(strFmt("@SYS335263")); } if(strLen(dataContractName) > 40) { setPrefix(dataContractName); throw error(strFmt("@SYS335263")); } if(strLen(serviceName) > 40) { setPrefix(serviceName); throw error(strFmt("@SYS335263")); } if(strLen(controllerName) > 40) { setPrefix(controllerName); throw error(strFmt("@SYS335263")); } runServiceMethodStr = strFmt(@"[SysEntryPointAttribute(true)] public void runService(%1 _dataContract) { if( !_dataContract.validate()) { throw error(error::wrongUseOfFunction(funcName())); } }", dataContractName); // ### UIBuilder interfacesSet = new Set(Types::String); attributes = ""; createdClassNode = createSysOperationClasses(uiBuilderName, "SysOperationAutomaticUIBuilder", interfacesSet, attributes); // ### Datacontract interfacesSet = new Set(Types::String); interfacesSet.add("SysOperationValidatable"); interfacesSet.add("SysOperationInitializable"); attributes = strFmt("[ DataContractAttribute , SysOperationContractProcessingAttribute(classStr(%1)) ]", uiBuilderName); createdClassNode = createSysOperationClasses(dataContractName, "", interfacesSet, attributes); // Create interface methods interfaceIterator = new SetIterator(interfacesSet); interfaceIterator.begin(); while (interfaceIterator.more()) { createInterfaceMethods(interfaceIterator.value(), new ClassBuild(createdClassNode.AOTname()), false); interfaceIterator.next(); } //validate() createdClassNode.AOTsave(); new ClassBuild(dataContractName).addSourceToMethod("validate", " return true;"); // Add parm()-Methodes from Map createdClassNode.AOTsave(); while(dataContractParmsME.moveNext()) { c++; new ClassBuild(dataContractName).addSourceToMethod("classDeclaration", strFmt(" %1 %2;", dataContractParmsME.currentKey(), dataContractParmsME.currentValue())); xppSource = new xppSource(); parmMethodSourcecode = xppSource.parmMethod(dataContractParmsME.currentKey(), dataContractParmsME.currentValue()); parmMethodSourcecode = strFmt("[DataMemberAttribute ,SysOperationDisplayOrderAttribute('%1')] ", c) + parmMethodSourcecode; new ClassBuild(createdClassNode.AOTname()).addMethod(strFmt("parm%1", dataContractParmsME.currentKey()), parmMethodSourcecode); } c = 0; // ### Service interfacesSet = new Set(Types::String); attributes = ""; createdClassNode = createSysOperationClasses(serviceName, "SysOperationServiceBase", interfacesSet, attributes); // Add runService()-Method new ClassBuild(createdClassNode.AOTname()).addMethod("runService", runServiceMethodStr); // ### Controller interfacesSet = new Set(Types::String); attributes = ""; createdClassNode = createSysOperationClasses(controllerName, "SysOperationServiceController", interfacesSet, attributes); customMethodStr = strFmt(@"public static %1 newFromArgs(Args _args) { %1 controller; controller = new %1(classStr(%2), methodStr(%2, runService)); controller.parmArgs(_args); return controller; }", controllerName, serviceName); // Add newFromArgs()-Method new ClassBuild(createdClassNode.AOTname()).addMethod("newFromArgs", customMethodStr); customMethodStr = strFmt(@"public static void main(Args _args) { %1 controller; %2 dataContract; SysOperationStartResult sysOperationStartResult; if (!_args) { throw error('@SYS25407'); } controller = %1::newFromArgs(_args); controller.parmExecutionMode(SysOperationExecutionMode::Synchronous); sysOperationStartResult = controller.startOperation(); }", controllerName, dataContractName, serviceName); // Add main()-Method new ClassBuild(createdClassNode.AOTname()).addMethod("main", customMethodStr); // ### Compile all created classes classBuildCompile = new ClassBuild(uiBuilderName); classBuildCompile.classNode().AOTcompile(1); classBuildCompile = new ClassBuild(dataContractName); classBuildCompile.classNode().AOTcompile(1); classBuildCompile = new ClassBuild(serviceName); classBuildCompile.classNode().AOTcompile(1); classBuildCompile = new ClassBuild(controllerName); classBuildCompile.classNode().AOTcompile(1); }