diff --git a/.gitignore b/.gitignore index e1976198..a5ae4bca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -node_modules/ -package-lock.json -.vscode \ No newline at end of file +node_modules/ +package-lock.json +.vscode diff --git a/lib/Connection.js b/lib/Connection.js index e37c2bac..a6eb7d1a 100644 --- a/lib/Connection.js +++ b/lib/Connection.js @@ -16,81 +16,68 @@ // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -const iXml = require('./ixml'); -const { iRestHttp } = require('./irest'); -const { db2Call } = require('./istoredp'); +const { + iXmlNodeHead, iXmlNodeScriptOpen, iXmlNodeScriptClose, +} = require('./ixml'); -const I_TRANSPORT_REST = 'REST'; -const I_TRANSPORT_DB2 = 'DB2'; +const { iRestHttp } = require('./transports/irest'); +const { db2Call } = require('./transports/istoredp'); + +const availableTransports = { + idb: db2Call, + rest: iRestHttp, +}; class Connection { /** * @description Creates a new Connection object * @constructor - * @param {string} db + * @param {object | string} optionsOrDb * @param {string} user * @param {string} pwd - * @param {object} [option] + * @param {object} [restConfig] */ - constructor(db, user, pwd, option) { - this.conn = {}; - this.cmds = []; - this.timeout = 5000; // Default timeout is 5 seconds for sync mode. - this.I_DEBUG_VERBOSE = false; - this.conn.I_TRANSPORT_DB2_DATABASE = db; // Required Field - this.conn.I_TRANSPORT_DB2_USER = user; // Required Field - this.conn.I_TRANSPORT_DB2_PASSWORD = pwd; // Required Field - this.conn.I_XML_SERVICE_LIB = 'QXMLSERV'; // Default XML Service library - this.conn.I_TRANSPORT_CTL = '*here'; - this.conn.I_TRANSPORT_IPC = '*NA'; - - if (typeof db === 'object') { - this.conn.I_TRANSPORT = I_TRANSPORT_DB2; - return; - } - - if (option && typeof option === 'object') { - if (option.host) { - this.conn.I_TRANSPORT = I_TRANSPORT_REST; - this.conn.I_TRANSPORT_REST_HOST = option.host; - if (option.port) { - this.conn.I_TRANSPORT_REST_PORT = option.port; - } else { - this.conn.I_TRANSPORT_REST_PORT = 80; - } - if (option.path) { - this.conn.I_TRANSPORT_REST_PATH = option.path; - } else { - this.conn.I_TRANSPORT_REST_PATH = '/'; - } - } else { - this.conn.I_TRANSPORT = I_TRANSPORT_DB2; - if (option.xslib && option.xslib.length > 0) { - this.conn.I_XML_SERVICE_LIB = option.xslib; + constructor(optionsOrDb, username, password, restOptions) { + this.commandList = []; + this.returnError = true; + this.verbose = false; + let options = optionsOrDb; + + // maintain compatibility with versions < 1.0 + if (typeof options !== 'object') { + options = { + returnError: false, + transport: 'idb', + transportOptions: { + database: optionsOrDb, + username, + password, + }, + }; + if (restOptions && typeof restOptions === 'object') { + if (restOptions.host) { + // pre v1.0 falls back to idb transport when host is not specified + options.transport = 'rest'; } + options.transportOptions = { ...options.transportOptions, ...restOptions }; } + } - if (option.ctl && option.ctl.length > 0) { - this.conn.I_TRANSPORT_CTL = option.ctl; - } - if (option.ipc && option.ipc.length > 0) { - this.conn.I_TRANSPORT_IPC = option.ipc; - } - if (Number.isNaN(option.buf)) { - this.conn.I_TRANSPORT_REST_XML_OUT_SIZE = option.buf.toString(); - } else { - this.conn.I_TRANSPORT_REST_XML_OUT_SIZE = '500000'; - } - } else { this.conn.I_TRANSPORT = I_TRANSPORT_DB2; } - } + this.transport = options.transport; - /** - * @description override the default timeout value for sync mode. - * @param {number} seconds - */ - setTimeout(seconds) { - if (typeof seconds === 'number') { - this.timeout = seconds * 1000; + if (!(this.transport in availableTransports)) { + throw new Error(`${this.transport} is not a valid transport`); + } + + this.transportCall = availableTransports[this.transport]; + this.transportOptions = options.transportOptions || {}; + + if (typeof options.returnError === 'boolean') { + this.returnError = options.returnError; + } + + if (typeof options.verbose === 'boolean') { + this.verbose = options.verbose; } } @@ -103,18 +90,18 @@ class Connection { */ debug(flag) { if (typeof flag === 'boolean') { - this.I_DEBUG_VERBOSE = flag; + this.verbose = flag; } - return this.I_DEBUG_VERBOSE; + return this.verbose; } /** - * @description returns conn property from Connection object. - * @returns {object} the conn property from Connection object. + * @description returns transportOptions property from Connection object. + * @returns {object} the transportOptions property from Connection object. */ - getConnection() { - return this.conn; + getTransportOptions() { + return this.transportOptions; } /** @@ -123,60 +110,55 @@ class Connection { */ add(xml) { if (typeof xml === 'object') { - this.cmds.push(xml.toXML()); + this.commandList.push(xml.toXML()); } else if (xml && typeof xml === 'string') { - this.cmds.push(xml); + this.commandList.push(xml); } } /** * @description * Invokes transport with XML input from command list - * Calls user provided callback with the XML output - * @param {fuction} callback - * @param {boolean} sync + * Calls user provided callback with the [error] and XML output + * @param {function} callback */ run(callback) { - // Build the XML document. - let xml = iXml.iXmlNodeHead() + iXml.iXmlNodeScriptOpen(); - for (let i = 0; i < this.cmds.length; i += 1) { - xml += this.cmds[i]; + if (typeof callback !== 'function') { + throw new Error('Passing a callback function is required'); + } + if (!this.commandList.length) { + throw new Error('Command list is empty. Make sure you add commands first'); } - xml += iXml.iXmlNodeScriptClose(); - this.cmds = []; + + // Build the XML document. + const xmlInput = iXmlNodeHead() + iXmlNodeScriptOpen() + this.commandList.join() + + iXmlNodeScriptClose(); + // reset the command list + this.commandList = []; + this.transportOptions.verbose = this.verbose; + // Print the XML document if in debug mode. - if (this.I_DEBUG_VERBOSE) { + if (this.verbose) { console.log('============\nINPUT XML\n============'); - console.log(xml); - console.log('============\nOUTPUT XML\n============'); - } - // Post the XML document to XML service program. - if (this.conn.I_TRANSPORT === I_TRANSPORT_REST) { - iRestHttp(callback, - this.conn.I_TRANSPORT_REST_HOST, - this.conn.I_TRANSPORT_REST_PORT, - this.conn.I_TRANSPORT_REST_PATH, - this.conn.I_TRANSPORT_DB2_DATABASE, - this.conn.I_TRANSPORT_DB2_USER, - this.conn.I_TRANSPORT_DB2_PASSWORD, - this.conn.I_TRANSPORT_IPC, - this.conn.I_TRANSPORT_CTL, - xml, - this.conn.I_TRANSPORT_REST_XML_OUT_SIZE); - } else if (this.conn.I_TRANSPORT === I_TRANSPORT_DB2) { - db2Call(callback, - this.conn.I_XML_SERVICE_LIB, - this.conn.I_TRANSPORT_DB2_DATABASE, - this.conn.I_TRANSPORT_DB2_USER, - this.conn.I_TRANSPORT_DB2_PASSWORD, - this.conn.I_TRANSPORT_IPC, - this.conn.I_TRANSPORT_CTL, - xml, - this.conn.I_TRANSPORT_REST_XML_OUT_SIZE, - this.I_DEBUG_VERBOSE); - } else { - callback(iXml.iXmlNodeHead() + iXml.iXmlNodeScriptOpen() + iXml.iXmlNodeError('***Transport error no data***') + iXml.iXmlNodeScriptClose()); + console.log(xmlInput); } + + this.transportCall(this.transportOptions, xmlInput, (error, xmlOutput) => { + if (this.verbose) { + console.log('============\nOUTPUT XML\n============'); + console.log(xmlOutput); + } + // create an Error object if error returned from transport is not one already + let transportError = error; + if (error && !(error instanceof Error)) { + transportError = new Error(error); + } + if (this.returnError) { + callback(transportError, xmlOutput); + } else { + callback(xmlOutput); + } + }); } } diff --git a/lib/Toolkit.js b/lib/Toolkit.js index c8a56537..d234438d 100644 --- a/lib/Toolkit.js +++ b/lib/Toolkit.js @@ -84,7 +84,11 @@ class Toolkit { this.conn.add(pgm.toXML()); let rtValue; // The returned value. - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (Object.prototype.hasOwnProperty.call(output[0], 'success') && output[0].success === true) { rtValue = true; @@ -92,7 +96,7 @@ class Toolkit { rtValue = str; } - cb(rtValue); // Run the call back function against the returned value. + cb(null, rtValue); // Run the call back function against the returned value. }; this.conn.run(toJson); // Post the input XML and get the response. @@ -109,7 +113,11 @@ class Toolkit { this.conn.add(pgm.toXML()); let rtValue; // The returned value. - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (Object.prototype.hasOwnProperty.call(output[0], 'success') && output[0].success === true) { rtValue = output[0].data[3].value; @@ -117,7 +125,7 @@ class Toolkit { rtValue = str; } - cb(rtValue); // Run the call back function against the returned value. + cb(null, rtValue); // Run the call back function against the returned value. }; this.conn.run(toJson); // Post the input XML and get the response. @@ -131,7 +139,11 @@ class Toolkit { this.conn.add(pgm.toXML()); let rtValue; // The returned value. - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (Object.prototype.hasOwnProperty.call(output[0], 'success') && output[0].success === true) { @@ -140,7 +152,7 @@ class Toolkit { rtValue = str; } - cb(rtValue); + cb(null, rtValue); }; this.conn.run(toJson); // Post the input XML and get the response. @@ -191,7 +203,11 @@ class Toolkit { let rtValue; // The returned value. - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (Object.prototype.hasOwnProperty.call(output[0], 'success') && output[0].success === true) { rtValue = { @@ -227,7 +243,7 @@ class Toolkit { Domain_search_list: output[0].data[31].value, }; } else { rtValue = str; } - cb(rtValue); // Run the call back function against the returned value. + cb(null, rtValue); // Run the call back function against the returned value. }; this.conn.run(toJson); // Post the input XML and get the response. @@ -312,7 +328,11 @@ class Toolkit { let rtValue; // The returned value. - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (Object.prototype.hasOwnProperty.call(output[0], 'success') && output[0].success === true) { rtValue = { @@ -365,7 +385,7 @@ class Toolkit { }; } else { rtValue = str; } - cb(rtValue); // Run the call back function against the returned value. + cb(null, rtValue); // Run the call back function against the returned value. }; this.conn.run(toJson); // Post the input XML and get the response. @@ -424,7 +444,11 @@ class Toolkit { let rtValue; // The returned value. - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (output[0].success) { rtValue = { @@ -465,7 +489,7 @@ class Toolkit { Number_of_group_table_entries_returned: output[0].data[36].value, }; } else { rtValue = str; } - cb(rtValue); // Run the call back function against the returned value. + cb(null, rtValue); // Run the call back function against the returned value. }; this.conn.run(toJson); // Post the input XML and get the response. @@ -526,7 +550,11 @@ class Toolkit { let rtValue; - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (output[0].success) { rtValue = { @@ -571,7 +599,7 @@ class Toolkit { Prompt_message_file_text_indicator: output[0].data[40].value, }; } else { rtValue = str; } - cb(rtValue); // Run the call back function against the returned value. + cb(null, rtValue); // Run the call back function against the returned value. }; this.conn.run(toJson); // Post the input XML and get the response. @@ -657,7 +685,11 @@ class Toolkit { let rtValue; - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (output[0].success) { rtValue = { @@ -727,7 +759,7 @@ class Toolkit { 'Uses_argument_optimization_(ARGOPT)': output[0].data[65].value, }; } else { rtValue = str; } - cb(rtValue); // Run the call back function against the returned value. + cb(null, rtValue); // Run the call back function against the returned value. }; this.conn.run(toJson); // Post the input XML and get the response. @@ -792,7 +824,11 @@ class Toolkit { const async = cb && typeof cb === 'function'; // If there is a callback function param, then it is in asynchronized mode. let rtValue; - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (output[0].success) { rtValue = { @@ -841,7 +877,7 @@ class Toolkit { Paging_amount: output[0].data[44].value, }; } else { rtValue = str; } - cb(rtValue); // Run the call back function against the returned value. + cb(null, rtValue); // Run the call back function against the returned value. }; this.conn.run(toJson, !async); // Post the input XML and get the response. @@ -877,7 +913,11 @@ class Toolkit { let rtValue; - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (output[0].success) { rtValue = { @@ -898,7 +938,7 @@ class Toolkit { Block_password_change: output[0].data[16].value, }; } else { rtValue = str; } - cb(rtValue); // Run the call back function against the returned value. + cb(null, rtValue); // Run the call back function against the returned value. }; this.conn.run(toJson); // Post the input XML and get the response. @@ -950,7 +990,11 @@ class Toolkit { let rtValue; - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (output[0].success) { rtValue = { @@ -972,7 +1016,7 @@ class Toolkit { }; } else { rtValue = str; } - cb(rtValue); // Run the call back function against the returned value.; + cb(null, rtValue); // Run the call back function against the returned value.; }; this.conn.run(toJson); // Post the input XML and get the response. @@ -991,10 +1035,18 @@ class Toolkit { let rtValue; // The returned value. - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); - if (output[0].success) { rtValue = true; } else { rtValue = str; } - cb(rtValue); // Run the call back function against the returned value. + if (output[0].success) { + rtValue = true; + } else { + rtValue = str; + } + cb(null, rtValue); // Run the call back function against the returned value. }; this.conn.run(toJson); // Post the input XML and get the response. @@ -1057,7 +1109,11 @@ class Toolkit { let rtValue; // The returned value. - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (Object.prototype.hasOwnProperty.call(output[0], 'success') && output[0].success === true) { rtValue = { @@ -1093,7 +1149,7 @@ class Toolkit { Reserved: output[0].data[32].value, }; } else { rtValue = str; } - cb(rtValue); // Run the call back function against the returned value. + cb(null, rtValue); // Run the call back function against the returned value. }; this.conn.run(toJson); // Post the input XML and get the response. @@ -1164,7 +1220,11 @@ class Toolkit { this.conn.add(pgm.toXML()); let rtValue; // The returned value. - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (Object.prototype.hasOwnProperty.call(output[0], 'success') && output[0].success === true) { rtValue = { @@ -1190,7 +1250,7 @@ class Toolkit { Reserved: output[0].data[21].value, }; } else { rtValue = str; } - callback(rtValue); // Run the call back function against the returned value. + callback(null, rtValue); // Run the call back function against the returned value. }; this.conn.run(toJson); // Post the input XML and get the response. @@ -1243,7 +1303,11 @@ class Toolkit { this.conn.add(pgm.toXML()); let rtValue = []; // The returned value. - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); const { length } = output[0].data; const count = Number(output[0].data[length - 6].value); @@ -1264,7 +1328,7 @@ class Toolkit { }); } } else { rtValue = str; } - cb(rtValue); // Run the call back function against the returned value. + cb(null, rtValue); // Run the call back function against the returned value. }; this.conn.run(toJson); // Post the input XML and get the response. @@ -1285,7 +1349,11 @@ class Toolkit { this.conn.add(pgm.toXML()); let rtValue; // The returned value. - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (Object.prototype.hasOwnProperty.call(output[0], 'success') && output[0].success === true) { rtValue = true; @@ -1293,7 +1361,7 @@ class Toolkit { rtValue = str; } - cb(rtValue); // Run the call back function against the returned value. + cb(null, rtValue); // Run the call back function against the returned value. }; this.conn.run(toJson); // Post the input XML and get the response. @@ -1312,7 +1380,11 @@ class Toolkit { let rtValue; // The returned value. - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (Object.prototype.hasOwnProperty.call(output[0], 'success') && output[0].success === true) { rtValue = true; @@ -1320,7 +1392,7 @@ class Toolkit { rtValue = str; } - cb(rtValue); + cb(null, rtValue); }; this.conn.run(toJson); // Post the input XML and get the response. @@ -1338,7 +1410,11 @@ class Toolkit { let rtValue; // The returned value. - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (Object.prototype.hasOwnProperty.call(output[0], 'success') && output[0].success === true) { rtValue = output[0].data[4].value; @@ -1346,7 +1422,7 @@ class Toolkit { rtValue = str; } - cb(rtValue); // Run the call back function against the returned value. + cb(null, rtValue); // Run the call back function against the returned value. }; this.conn.run(toJson); // Post the input XML and get the response. @@ -1361,11 +1437,15 @@ class Toolkit { let rtValue; // The returned value. - const toJson = (str) => { // Convert the XML output into JSON + const toJson = (error, str) => { // Convert the XML output into JSON + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (Object.prototype.hasOwnProperty.call(output[0], 'success') && output[0].success === true) { rtValue = true; } else { rtValue = str; } - cb(rtValue); // Run the call back function against the returned value. + cb(null, rtValue); // Run the call back function against the returned value. }; this.conn.run(toJson); // Post the input XML and get the response. @@ -1375,16 +1455,14 @@ class Toolkit { let keyValid = false; let type = '10i0'; - sysvalArray.some((value) => { - return value.key.some((key) => { - if (sysValue === key) { - keyValid = true; - ({ type } = value); - return true; - } - return false; - }); - }); + sysvalArray.some(value => value.key.some((key) => { + if (sysValue === key) { + keyValid = true; + ({ type } = value); + return true; + } + return false; + })); // TODO: Throw error if (keyValid === false) { return; } @@ -1413,7 +1491,11 @@ class Toolkit { let rtValue; - const toJson = (str) => { + const toJson = (error, str) => { + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (Object.prototype.hasOwnProperty.call(output[0], 'success') && output[0].success === true) { rtValue = output[0].data[6].value; // Get the returned value from the output array. @@ -1421,7 +1503,7 @@ class Toolkit { rtValue = str; } - cb(rtValue); + cb(null, rtValue); }; this.conn.run(toJson); // Post the input XML @@ -1458,7 +1540,11 @@ class Toolkit { this.conn.add(pgm.toXML()); let rtValue; - const toJson = (str) => { + const toJson = (error, str) => { + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (Object.prototype.hasOwnProperty.call(output[0], 'success') && output[0].success === true) { rtValue = { @@ -1481,7 +1567,7 @@ class Toolkit { }; } else { rtValue = str; } - cb(rtValue); + cb(null, rtValue); }; this.conn.run(toJson); @@ -1536,7 +1622,11 @@ class Toolkit { this.conn.add(pgm.toXML()); let rtValue; - const toJson = (str) => { + const toJson = (error, str) => { + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (Object.prototype.hasOwnProperty.call(output[0], 'success') && output[0].success === true) { rtValue = { @@ -1573,7 +1663,7 @@ class Toolkit { 'Main_storage_size_(long)': output[0].data[35].value, }; } else { rtValue = str; } - cb(rtValue); + cb(null, rtValue); }; this.conn.run(toJson); @@ -1598,7 +1688,11 @@ class Toolkit { let rtValue; - const toJson = (str) => { + const toJson = (error, str) => { + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (Object.prototype.hasOwnProperty.call(output[0], 'success') && output[0].success === true) { rtValue = { @@ -1606,7 +1700,7 @@ class Toolkit { Fully_qualified_job_name: output[0].data[4].value, }; } else { rtValue = str; } - cb(rtValue); + cb(null, rtValue); }; this.conn.run(toJson); @@ -1671,7 +1765,11 @@ class Toolkit { let rtValue; - const toJson = (str) => { + const toJson = (error, str) => { + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (Object.prototype.hasOwnProperty.call(output[0], 'success') && output[0].success === true) { rtValue = { @@ -1712,7 +1810,7 @@ class Toolkit { 'Message_queue_library_ASP_device_name,_when_active_job_waiting_for_a_message': output[0].data[38].value, }; } else { rtValue = str; } - cb(rtValue); + cb(null, rtValue); }; this.conn.run(toJson); } @@ -1743,7 +1841,11 @@ class Toolkit { let rtValue; - const toJson = (str) => { + const toJson = (error, str) => { + if (error) { + cb(error, null); + return; + } const output = xmlToJson(str); if (Object.prototype.hasOwnProperty.call(output[0], 'success') && output[0].success === true) { rtValue = { @@ -1754,7 +1856,7 @@ class Toolkit { Value: output[0].data[6].value, }; } else { rtValue = str; } - cb(rtValue); + cb(null, rtValue); }; this.conn.run(toJson); } diff --git a/lib/istoredp.js b/lib/istoredp.js deleted file mode 100644 index 7d63c9f1..00000000 --- a/lib/istoredp.js +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) International Business Machines Corp. 2017 -// All Rights Reserved - -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, -// including without limitation the rights to use, copy, modify, merge, publish, distribute, -// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -const db = require('idb-connector'); // TODO: This is optional - -const db2Call = (callback, xlib, xdatabase, xuser, xpassword, xipc, xctl, xmlInputScript, xbuf, - debug) => { - const xmlOut = 'NULL'; - let sql = `call ${xlib}.iPLUG512K(?,?,?,?)`; - - if (xbuf !== undefined) { - const xBuf = Number(xbuf); - if (xBuf <= 0) { sql = `call ${xlib}.iPLUG32K(?,?,?,?)`; } else if (xBuf <= 4096) { sql = `call ${xlib}.iPLUG4K(?,?,?,?)`; } else if (xBuf <= 32768) { sql = `call ${xlib}.iPLUG32K(?,?,?,?)`; } else if (xBuf <= 65536) { sql = `call ${xlib}.iPLUG65K(?,?,?,?)`; } else if (xBuf <= 524288) { sql = `call ${xlib}.iPLUG512K(?,?,?,?)`; } else if (xBuf <= 1048576) { sql = `call ${xlib}.iPLUG1M(?,?,?,?)`; } else if (xBuf <= 5242880) { sql = `call ${xlib}.iPLUG5M(?,?,?,?)`; } else if (xBuf <= 10485760) { sql = `call ${xlib}.iPLUG10M(?,?,?,?)`; } else sql = `call ${xlib}.iPLUG15M(?,?,?,?)`; - } - - try { - const conn = new db.dbconn(); // eslint-disable-line new-cap - conn.setConnAttr(db.SQL_ATTR_DBC_SYS_NAMING, db.SQL_FALSE); - if (typeof debug === 'boolean') { conn.debug(debug); } - if (xuser && xuser.length > 0 && xpassword && xpassword.length > 0) { - conn.conn(xdatabase, xuser, xpassword); - } else { - conn.conn(xdatabase); - } - - const stmt = new db.dbstmt(conn); // eslint-disable-line new-cap - - const bindParams = [ - [xipc, db.SQL_PARAM_INPUT, 1], - [xctl, db.SQL_PARAM_INPUT, 1], - [xmlInputScript, db.SQL_PARAM_INPUT, 0], - [xmlOut, db.SQL_PARAM_OUTPUT, 0], - ]; - - stmt.prepare(sql, (prepareErr) => { - if (prepareErr) throw prepareErr; - stmt.bindParam(bindParams, (paramErr) => { - if (paramErr) throw paramErr; - stmt.execute((outArray, executeErr) => { // out is an array of the output parameters. - if (executeErr) throw executeErr; - if (outArray.length === 1) { - // For XML service, there is always only one return XML output. So handle it directly. - callback(outArray[0]); - // For multiple return result, caller should handle it as an array. - } else { callback(outArray); } - conn.disconn(); - }); - }); - }); - } catch (e) { - console.log(e); - } -}; - -exports.db2Call = db2Call; diff --git a/lib/irest.js b/lib/transports/irest.js similarity index 53% rename from lib/irest.js rename to lib/transports/irest.js index 0e58685f..ab3731ac 100644 --- a/lib/irest.js +++ b/lib/transports/irest.js @@ -18,34 +18,68 @@ const http = require('http'); -const iRestHttp = (callback, xhost, xport, xpath, xdatabase, xuser, xpassword, xipc, xctl, - xmlInputScript, xmlOutputMaxSize) => { - const xmlEnc = encodeURI(`db2=${xdatabase - }&uid=${xuser - }&pwd=${xpassword - }&ipc=${xipc - }&ctl=${xctl - }&xmlin=${xmlInputScript - }&xmlout=${xmlOutputMaxSize}`); - // myibmi/cgi-bin/xmlcgi.pgm?xml +const iRestHttp = (config, xmlInput, done) => { + const { + database = '*LOCAL', + username = null, + password = null, + ipc = '*NA', + ctl = '*here', + host = 'localhost', + port = 80, + path = '/', + } = config; + + const outputBuffer = 15728640; // set to the max output buffer 15Mib + + // perform some validation + if (!database || typeof database !== 'string') { + done('Provide a valid data source', null); + return; + } + + if (!username || typeof username !== 'string') { + done('Provide a valid username', null); + return; + } + + if (!password || typeof password !== 'string') { + done('Provide a valid password', null); + return; + } + + const xmlEnc = encodeURI(`db2=${database + }&uid=${username + }&pwd=${password + }&ipc=${ipc + }&ctl=${ctl + }&xmlin=${xmlInput + }&xmlout=${outputBuffer.toString()}`); + const options = { - host: xhost, - port: xport, - path: `${xpath}?${xmlEnc}`, + host, + port, + path: `${path}?${xmlEnc}`, + method: 'GET', }; - const httpCallback = (response) => { - let str = ''; - // another chunk of data has been received, so append it to `str` + + const request = http.request(options, (response) => { + let xmlOutput = ''; + response.on('data', (chunk) => { - str += chunk; + xmlOutput += chunk; }); - // the whole response has been received, so return + response.on('end', () => { - callback(str); + done(null, xmlOutput); }); - }; - // make the call - http.request(options, httpCallback).end(); + }); + + request.on('error', (error) => { + done(error, null); + }); + + request.end(); }; exports.iRestHttp = iRestHttp; diff --git a/lib/transports/istoredp.js b/lib/transports/istoredp.js new file mode 100644 index 00000000..83daa949 --- /dev/null +++ b/lib/transports/istoredp.js @@ -0,0 +1,114 @@ +// Copyright (c) International Business Machines Corp. 2017 +// All Rights Reserved + +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +// associated documentation files (the "Software"), to deal in the Software without restriction, +// including without limitation the rights to use, copy, modify, merge, publish, distribute, +// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +const db2Call = (config, xmlInput, done) => { + const { + dbconn, dbstmt, IN, CLOB, CHAR, SQL_ATTR_DBC_SYS_NAMING, SQL_FALSE, + } = require('idb-connector'); + + const { + database = '*LOCAL', + username = null, + password = null, + ipc = '*NA', + ctl = '*here', + xslib = 'QXMLSERV', + verbose = false, + } = config; + + let xmlOutput = ''; + const sql = `call ${xslib}.iPLUGR512K(?,?,?)`; + // eslint-disable-next-line new-cap + const conn = new dbconn(); + + conn.setConnAttr(SQL_ATTR_DBC_SYS_NAMING, SQL_FALSE); + + if (typeof verbose === 'boolean') { + conn.debug(verbose); + } + + try { + if (username && password) { + conn.conn(database, username, password); + } else { + conn.conn(database); + } + } catch (error) { + done(error, null); + } + // eslint-disable-next-line new-cap + const stmt = new dbstmt(conn); + + const parameters = [ + [ipc, IN, CHAR], + [ctl, IN, CHAR], + [xmlInput, IN, CLOB], + ]; + + function clean(connection, statement) { + statement.close(); + connection.disconn(); + connection.close(); + } + + stmt.prepare(sql, (prepareError) => { + if (prepareError) { + clean(conn, stmt); + done(prepareError, null); + return; + } + stmt.bindParam(parameters, (bindError) => { + if (bindError) { + clean(conn, stmt); + done(bindError, null); + return; + } + stmt.execute((outArray, executeError) => { + if (executeError) { + clean(conn, stmt); + done(executeError, null); + return; + } + stmt.fetchAll((results, fetchError) => { + if (fetchError) { + clean(conn, stmt); + done(fetchError, null); + return; + } + if (!results.length) { + clean(conn, stmt); + done('Empty result set was returned', null); + return; + } + if (results.length === 1) { + clean(conn, stmt); + done(null, results[0].OUT151); + return; + } + results.forEach((chunk) => { + xmlOutput += chunk.OUT151; + }); + done(null, xmlOutput); + clean(conn, stmt); + }); + }); + }); + }); +}; + +exports.db2Call = db2Call; diff --git a/package.json b/package.json index a39a095c..e149b121 100644 --- a/package.json +++ b/package.json @@ -1,51 +1,51 @@ -{ - "name": "itoolkit", - "version": "0.1.6", - "description": "Wrapper over XMLSERVICE for access to all things IBM i", - "main": "lib/itoolkit.js", - "directories": { - "lib": "lib", - "test": "test" - }, - "scripts": { - "test": "./node_modules/mocha/bin/mocha" - }, - "repository": { - "type": "git", - "url": "git+ssh://git@github.com/IBM/nodejs-itoolkit.git" - }, - "keywords": [ - "ibmi", - "xmlservice", - "rpg", - "srvpgm" - ], - "author": "IBM", - "license": "MIT", - "homepage": "https://github.com/IBM/nodejs-itoolkit", - "contributors": [ - { - "name": "Xu Meng", - "email": "dmabupt@gmail.com" - }, - { - "name": "Tony Cairns" - }, - { - "name": "Aaron Bartell", - "email": "aaronbartell@gmail.com" - } - ], - "devDependencies": { - "chai": "^4.1.2", - "eslint": "^5.12.1", - "eslint-config-airbnb-base": "^13.1.0", - "eslint-plugin-import": "^2.15.0", - "mocha": "^5.2.0", - "sinon": "^7.2.3" - }, - "optionalDependencies": { - "idb-connector": "^1.1.8", - "idb-pconnector": "^1.0.2" - } -} +{ + "name": "itoolkit", + "version": "0.1.6", + "description": "Wrapper over XMLSERVICE for access to all things IBM i", + "main": "lib/itoolkit.js", + "directories": { + "lib": "lib", + "test": "test" + }, + "scripts": { + "test": "./node_modules/mocha/bin/mocha" + }, + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/IBM/nodejs-itoolkit.git" + }, + "keywords": [ + "ibmi", + "xmlservice", + "rpg", + "srvpgm" + ], + "author": "IBM", + "license": "MIT", + "homepage": "https://github.com/IBM/nodejs-itoolkit", + "contributors": [ + { + "name": "Xu Meng", + "email": "dmabupt@gmail.com" + }, + { + "name": "Tony Cairns" + }, + { + "name": "Aaron Bartell", + "email": "aaronbartell@gmail.com" + } + ], + "devDependencies": { + "chai": "^4.1.2", + "eslint": "^5.12.1", + "eslint-config-airbnb-base": "^13.1.0", + "eslint-plugin-import": "^2.15.0", + "mocha": "^5.2.0", + "sinon": "^7.2.3" + }, + "optionalDependencies": { + "idb-connector": "^1.1.8", + "idb-pconnector": "^1.0.2" + } +} diff --git a/test/rpg/zzcall.rpgle b/test/rpg/zzcall.rpgle index 043a5ee5..a55d7c84 100644 --- a/test/rpg/zzcall.rpgle +++ b/test/rpg/zzcall.rpgle @@ -1,36 +1,36 @@ - * CRTBNDRPG PGM(xmlservice/zzcall) SRCSTMF('/path/to/nodejs-itoolkit/test/rpg/zzcall.rpgle') - H AlwNull(*UsrCtl) - - D Step s 10i 0 inz(0) - - D INCHARA S 1a - D INCHARB S 1a - D INDEC1 S 7p 4 - D INDEC2 S 12p 2 - D INDS1 DS - D DSCHARA 1a - D DSCHARB 1a - D DSDEC1 7p 4 - D DSDEC2 12p 2 - *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * main(): Control flow - *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - C *Entry PLIST - C PARM INCHARA - C PARM INCHARB - C PARM INDEC1 - C PARM INDEC2 - C PARM INDS1 - /free - Step +=1; - INCHARA = 'C'; - INCHARB = 'D'; - INDEC1 = 321.1234; - INDEC2 = 1234567890.12; - DSCHARA = 'E'; - DSCHARB = 'F'; - DSDEC1 = 333.333; - DSDEC2 = 4444444444.44; - return; - // *inlr = *on; - /end-free \ No newline at end of file + * CRTBNDRPG PGM(xmlservice/zzcall) SRCSTMF('/path/to/nodejs-itoolkit/test/rpg/zzcall.rpgle') + H AlwNull(*UsrCtl) + + D Step s 10i 0 inz(0) + + D INCHARA S 1a + D INCHARB S 1a + D INDEC1 S 7p 4 + D INDEC2 S 12p 2 + D INDS1 DS + D DSCHARA 1a + D DSCHARB 1a + D DSDEC1 7p 4 + D DSDEC2 12p 2 + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * main(): Control flow + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + C *Entry PLIST + C PARM INCHARA + C PARM INCHARB + C PARM INDEC1 + C PARM INDEC2 + C PARM INDS1 + /free + Step +=1; + INCHARA = 'C'; + INCHARB = 'D'; + INDEC1 = 321.1234; + INDEC2 = 1234567890.12; + DSCHARA = 'E'; + DSCHARB = 'F'; + DSDEC1 = 333.333; + DSDEC2 = 4444444444.44; + return; + // *inlr = *on; + /end-free diff --git a/test/rpg/zzsrv6.rpgle b/test/rpg/zzsrv6.rpgle index c2b2a612..fd75e7dd 100644 --- a/test/rpg/zzsrv6.rpgle +++ b/test/rpg/zzsrv6.rpgle @@ -1,403 +1,403 @@ - * CRTRPGMOD MODULE(XMLSERVICE/ZZSRV6) SRCSTMF('/path/to/nodejs-itoolkit/test/rpg/zzsrv6.rpgle') - * CRTSRVPGM SRVPGM(XMLSERVICE/ZZSRV6) EXPORT(*ALL) - H NOMAIN - H AlwNull(*UsrCtl) - - ***************************************************** - * includes - ***************************************************** - D ARRAYMAX c const(999) - - D dcRec_t ds qualified based(Template) - D dcMyName 10A - D dcMyJob 4096A - D dcMyRank 10i 0 - D dcMyPay 12p 2 - - D dcRec3_t ds qualified based(Template) - D dcMyName3 10A - D dcRec3 likeds(dcRec_t) dim(ARRAYMAX) - - D dcRec2_t ds qualified based(Template) - D dcMyName2 10A - D dcRec2 likeds(dcRec3_t) - - D dcRec1_t ds qualified based(Template) - D dcMyName1 10A - D dcRec1 likeds(dcRec2_t) - - - D zzarray3 PR - D myName 10A - D myMax 3s 0 - D wskdist 3a - D wskyear 4a - D wskytyp 1a - D wskschl 4a - D wskusr 20a - D wsksdate 8a - D wskscrse 8a - D wskssect 4a - D wsksmod 2a - D wsoptai 1a - D wsopatdt 1a - D wsoplslot 2a - D myCount 3s 0 - D wsoperrtbl 48000a - D findMe1 likeds(dcRec1_t) - D findMe2 likeds(dcRec2_t) - D findMe3 likeds(dcRec3_t) - - - D zzouch PR - D myName 10A - D myMax 3s 0 - D wskdist 3a - D wskyear 4a - D wskytyp 1a - D wskschl 4a - D wskusr 20a - D wsksdate 8a - D wskscrse 8a - D wskssect 4a - D wsksmod 2a - D wsoptai 1a - D wsopatdt 1a - D wsoplslot 2a - D myCount 3s 0 - D wsoperrtbl 48000a - D findMe1 likeds(dcRec1_t) - D findMe2 likeds(dcRec2_t) - D findMe3 likeds(dcRec3_t) - - - D zzvary4 PR 20A varying(4) - D myName 10A varying(4) - - - - D memset PR ExtProc('__memset') - D pTarget * Value - D nChar 10I 0 Value - D nBufLen 10U 0 Value - - d zznullid pr - D fdate1 D datfmt(*USA) - D fnull1 10A - - d zznullme pr N - D fdate1 D datfmt(*USA) options(*nullind) - - - D zzptr1 PR - D myPtr1 * - D myPtr2 * - D myMax 3s 0 - D wskdist 3a - - - D zzbool1 PR - D myBool1 1N - D myBool2 1N - D myMax 3s 0 - D wskdist 3a - - D zzold1 PR - D Len 2 0 - D Wid 2 0 - D Area 4 0 - D Frog 10 - - *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * zznullid: check indicator - *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - P zznullid B export - D zznullid PI - D fdate1 D datfmt(*USA) - D fnull1 10A - * fake nullind - D dcNULL_t ds qualified based(Template) - D dcData * - D dcNULL * - D tmp S n inz(*ON) - D ddate1 ds likeds(dcNULL_t) - D vdate1 s D datfmt(*USA) - D ndate1 s N inz(*ON) - * fake call out - D procPtr S * ProcPtr - D pMyProc1 Pr 1N ExtProc(procPtr) - D pargv1 * value - /free - vdate1 = fdate1; - ndate1 = *ON; - ddate1.dcData = %addr(vdate1); - ddate1.dcNULL = %addr(ndate1); - - procPtr = %paddr(zznullme); - tmp = pMyProc1(%addr(ddate1)); - - fdate1 = vdate1; - if tmp = *ON; - fnull1 = 'NULL ON'; - else; - fnull1 = 'NULL OFF'; - endif; - /end-free - P E - - *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * zznullme: check indicator - *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - P zznullme B export - D zznullme PI n - D fdate1 D datfmt(*USA) options(*nullind) - /free - fdate1 = d'2014-01-07'; - %nullind(fdate1) = *OFF; - return %nullind(fdate1); - /end-free - P E - - - *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * zzvary4: check return varying - *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - P zzvary4 B export - D zzvary4 PI 20A varying(4) - D myName 10A varying(4) - * vars - D tmp S 20A varying(4) - /free - tmp = 'my name is '; - tmp = tmp + myName; - return tmp; - /end-free - P E - - - - *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * zzarray3: check parameter array aggregate - *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - P zzarray3 B export - D zzarray3 PI - D myName 10A - D myMax 3s 0 - D wskdist 3a - D wskyear 4a - D wskytyp 1a - D wskschl 4a - D wskusr 20a - D wsksdate 8a - D wskscrse 8a - D wskssect 4a - D wsksmod 2a - D wsoptai 1a - D wsopatdt 1a - D wsoplslot 2a - D myCount 3s 0 - D wsoperrtbl 48000a - D findMe1 likeds(dcRec1_t) - D findMe2 likeds(dcRec2_t) - D findMe3 likeds(dcRec3_t) - * vars - D i S 10i 0 inz(0) - D max S 10i 0 inz(ARRAYMAX) - /free - if myMax <= max; - max = myMax; - endif; - wskdist = '123'; - wskyear = '1234'; - wskytyp = 'R'; - wskschl = '1111'; - wskusr = myName; - wsksdate = '20120102'; - wskscrse = 'frog'; - wskssect = '9999'; - wsksmod = '33'; - wsoptai = 'A'; - wsopatdt = 'B'; - wsoplslot= '12'; - wsoperrtbl = 'ok in here'; - // findMe3 - findMe3.dcMyName3 = %trim(myName); - for i = 1 to max; - findMe3.dcRec3(i).dcMyName = %trim(myName) + %char(i); - if myMax > 10; - memset(%ADDR(findMe3.dcRec3(i).dcMyJob):195:4095); // 'C' - else; - findMe3.dcRec3(i).dcMyJob = 'Test 30' + %char(i); - endif; - findMe3.dcRec3(i).dcMyRank = 30 + i; - findMe3.dcRec3(i).dcMyPay = 13.43 * i; - myCount = i; - endfor; - // findMe2 - findMe2.dcMyName2 = %trim(myName); - findMe2.dcRec2.dcMyName3 = %trim(myName); - for i = 1 to max; - findMe2.dcRec2.dcRec3(i).dcMyName = %trim(myName) + %char(i); - if myMax > 10; - memset(%ADDR(findMe2.dcRec2.dcRec3(i).dcMyJob):194:4095); // 'B' - else; - findMe2.dcRec2.dcRec3(i).dcMyJob = 'Test 20' + %char(i); - endif; - findMe2.dcRec2.dcRec3(i).dcMyRank = 20 + i; - findMe2.dcRec2.dcRec3(i).dcMyPay = 13.42 * i; - myCount = i; - endfor; - // findMe1 - findMe1.dcMyName1 = %trim(myName); - findMe1.dcRec1.dcMyName2 = %trim(myName); - findMe1.dcRec1.dcRec2.dcMyName3 = %trim(myName); - for i = 1 to max; - findMe1.dcRec1.dcRec2.dcRec3(i).dcMyName = %trim(myName) + %char(i); - if myMax > 10; - memset(%ADDR(findMe1.dcRec1.dcRec2.dcRec3(i).dcMyJob):193:4095); // 'A' - else; - findMe1.dcRec1.dcRec2.dcRec3(i).dcMyJob = 'Test 10' + %char(i); - endif; - findMe1.dcRec1.dcRec2.dcRec3(i).dcMyRank = 10 + i; - findMe1.dcRec1.dcRec2.dcRec3(i).dcMyPay = 13.41 * i; - myCount = i; - endfor; - return; - /end-free - P E - - - *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * zzouch: check BAD parameter array aggregate - *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - P zzouch B export - D zzouch PI - D myName 10A - D myMax 3s 0 - D wskdist 3a - D wskyear 4a - D wskytyp 1a - D wskschl 4a - D wskusr 20a - D wsksdate 8a - D wskscrse 8a - D wskssect 4a - D wsksmod 2a - D wsoptai 1a - D wsopatdt 1a - D wsoplslot 2a - D myCount 3s 0 - D wsoperrtbl 48000a - D findMe1 likeds(dcRec1_t) - D findMe2 likeds(dcRec2_t) - D findMe3 likeds(dcRec3_t) - * vars - D i S 10i 0 inz(0) - D max S 10i 0 inz(ARRAYMAX) - /free - if myMax <= max; - max = myMax; - endif; - wskdist = '123'; - wskyear = '1234'; - wskytyp = 'R'; - wskschl = '1111'; - wskusr = myName; - wsksdate = '20120102'; - wskscrse = 'frog'; - wskssect = '9999'; - wsksmod = '33'; - wsoptai = 'A'; - wsopatdt = 'B'; - wsoplslot= '12'; - wsoperrtbl = 'ok in here'; - // findMe3 - findMe3.dcMyName3 = %trim(myName); - for i = 1 to max; - findMe3.dcRec3(i).dcMyName = %trim(myName) + %char(i); - if myMax > 10; - memset(%ADDR(findMe3.dcRec3(i).dcMyJob):195:4095); // 'C' - else; - findMe3.dcRec3(i).dcMyJob = 'Test 30' + %char(i); - endif; - findMe3.dcRec3(i).dcMyRank = 30 + i; - findMe3.dcRec3(i).dcMyPay = 13.43 * i; - myCount = i; - endfor; - // findMe2 - findMe2.dcMyName2 = %trim(myName); - findMe2.dcRec2.dcMyName3 = %trim(myName); - // ouch - memset(%addr(findMe2.dcRec2.dcRec3(2).dcMyName):196:32768); // 'D' - return; - /end-free - P E - - *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * zzptr1: check skip ptr - *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - P zzptr1 B export - D zzptr1 PI - D myPtr1 * - D myPtr2 * - D myMax 3s 0 - D wskdist 3a - * vars - D i S 10i 0 inz(0) - D max S 10i 0 inz(ARRAYMAX) - /free - if myMax <= max; - max = myMax; - endif; - wskdist = '123'; - myPtr1 = %addr(myMax); - myPtr2 = %addr(wskdist); - return; - /end-free - P E - - *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * zzbool1: check boolean - *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - P zzbool1 B export - D zzbool1 PI - D myBool1 1N - D myBool2 1N - D myMax 3s 0 - D wskdist 3a - * vars - D i S 10i 0 inz(0) - D max S 10i 0 inz(ARRAYMAX) - /free - if myMax <= max; - max = myMax; - endif; - wskdist = '123'; - myBool1 = *ON; - myBool2 = *OFF; - return; - /end-free - P E - - *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * zzold1: default type - *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - P zzold1 B export - D zzold1 PI - D Len 2 0 - D Wid 2 0 - D Area 4 0 - D Frog 10 - * vars - D i S 10i 0 inz(0) - D max S 10i 0 inz(ARRAYMAX) - /free - Len = 1; - Wid = 2; - Area = 3; - Frog = 'Green'; - return; - /end-free - P E - - + * CRTRPGMOD MODULE(XMLSERVICE/ZZSRV6) SRCSTMF('/path/to/nodejs-itoolkit/test/rpg/zzsrv6.rpgle') + * CRTSRVPGM SRVPGM(XMLSERVICE/ZZSRV6) EXPORT(*ALL) + H NOMAIN + H AlwNull(*UsrCtl) + + ***************************************************** + * includes + ***************************************************** + D ARRAYMAX c const(999) + + D dcRec_t ds qualified based(Template) + D dcMyName 10A + D dcMyJob 4096A + D dcMyRank 10i 0 + D dcMyPay 12p 2 + + D dcRec3_t ds qualified based(Template) + D dcMyName3 10A + D dcRec3 likeds(dcRec_t) dim(ARRAYMAX) + + D dcRec2_t ds qualified based(Template) + D dcMyName2 10A + D dcRec2 likeds(dcRec3_t) + + D dcRec1_t ds qualified based(Template) + D dcMyName1 10A + D dcRec1 likeds(dcRec2_t) + + + D zzarray3 PR + D myName 10A + D myMax 3s 0 + D wskdist 3a + D wskyear 4a + D wskytyp 1a + D wskschl 4a + D wskusr 20a + D wsksdate 8a + D wskscrse 8a + D wskssect 4a + D wsksmod 2a + D wsoptai 1a + D wsopatdt 1a + D wsoplslot 2a + D myCount 3s 0 + D wsoperrtbl 48000a + D findMe1 likeds(dcRec1_t) + D findMe2 likeds(dcRec2_t) + D findMe3 likeds(dcRec3_t) + + + D zzouch PR + D myName 10A + D myMax 3s 0 + D wskdist 3a + D wskyear 4a + D wskytyp 1a + D wskschl 4a + D wskusr 20a + D wsksdate 8a + D wskscrse 8a + D wskssect 4a + D wsksmod 2a + D wsoptai 1a + D wsopatdt 1a + D wsoplslot 2a + D myCount 3s 0 + D wsoperrtbl 48000a + D findMe1 likeds(dcRec1_t) + D findMe2 likeds(dcRec2_t) + D findMe3 likeds(dcRec3_t) + + + D zzvary4 PR 20A varying(4) + D myName 10A varying(4) + + + + D memset PR ExtProc('__memset') + D pTarget * Value + D nChar 10I 0 Value + D nBufLen 10U 0 Value + + d zznullid pr + D fdate1 D datfmt(*USA) + D fnull1 10A + + d zznullme pr N + D fdate1 D datfmt(*USA) options(*nullind) + + + D zzptr1 PR + D myPtr1 * + D myPtr2 * + D myMax 3s 0 + D wskdist 3a + + + D zzbool1 PR + D myBool1 1N + D myBool2 1N + D myMax 3s 0 + D wskdist 3a + + D zzold1 PR + D Len 2 0 + D Wid 2 0 + D Area 4 0 + D Frog 10 + + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * zznullid: check indicator + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + P zznullid B export + D zznullid PI + D fdate1 D datfmt(*USA) + D fnull1 10A + * fake nullind + D dcNULL_t ds qualified based(Template) + D dcData * + D dcNULL * + D tmp S n inz(*ON) + D ddate1 ds likeds(dcNULL_t) + D vdate1 s D datfmt(*USA) + D ndate1 s N inz(*ON) + * fake call out + D procPtr S * ProcPtr + D pMyProc1 Pr 1N ExtProc(procPtr) + D pargv1 * value + /free + vdate1 = fdate1; + ndate1 = *ON; + ddate1.dcData = %addr(vdate1); + ddate1.dcNULL = %addr(ndate1); + + procPtr = %paddr(zznullme); + tmp = pMyProc1(%addr(ddate1)); + + fdate1 = vdate1; + if tmp = *ON; + fnull1 = 'NULL ON'; + else; + fnull1 = 'NULL OFF'; + endif; + /end-free + P E + + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * zznullme: check indicator + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + P zznullme B export + D zznullme PI n + D fdate1 D datfmt(*USA) options(*nullind) + /free + fdate1 = d'2014-01-07'; + %nullind(fdate1) = *OFF; + return %nullind(fdate1); + /end-free + P E + + + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * zzvary4: check return varying + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + P zzvary4 B export + D zzvary4 PI 20A varying(4) + D myName 10A varying(4) + * vars + D tmp S 20A varying(4) + /free + tmp = 'my name is '; + tmp = tmp + myName; + return tmp; + /end-free + P E + + + + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * zzarray3: check parameter array aggregate + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + P zzarray3 B export + D zzarray3 PI + D myName 10A + D myMax 3s 0 + D wskdist 3a + D wskyear 4a + D wskytyp 1a + D wskschl 4a + D wskusr 20a + D wsksdate 8a + D wskscrse 8a + D wskssect 4a + D wsksmod 2a + D wsoptai 1a + D wsopatdt 1a + D wsoplslot 2a + D myCount 3s 0 + D wsoperrtbl 48000a + D findMe1 likeds(dcRec1_t) + D findMe2 likeds(dcRec2_t) + D findMe3 likeds(dcRec3_t) + * vars + D i S 10i 0 inz(0) + D max S 10i 0 inz(ARRAYMAX) + /free + if myMax <= max; + max = myMax; + endif; + wskdist = '123'; + wskyear = '1234'; + wskytyp = 'R'; + wskschl = '1111'; + wskusr = myName; + wsksdate = '20120102'; + wskscrse = 'frog'; + wskssect = '9999'; + wsksmod = '33'; + wsoptai = 'A'; + wsopatdt = 'B'; + wsoplslot= '12'; + wsoperrtbl = 'ok in here'; + // findMe3 + findMe3.dcMyName3 = %trim(myName); + for i = 1 to max; + findMe3.dcRec3(i).dcMyName = %trim(myName) + %char(i); + if myMax > 10; + memset(%ADDR(findMe3.dcRec3(i).dcMyJob):195:4095); // 'C' + else; + findMe3.dcRec3(i).dcMyJob = 'Test 30' + %char(i); + endif; + findMe3.dcRec3(i).dcMyRank = 30 + i; + findMe3.dcRec3(i).dcMyPay = 13.43 * i; + myCount = i; + endfor; + // findMe2 + findMe2.dcMyName2 = %trim(myName); + findMe2.dcRec2.dcMyName3 = %trim(myName); + for i = 1 to max; + findMe2.dcRec2.dcRec3(i).dcMyName = %trim(myName) + %char(i); + if myMax > 10; + memset(%ADDR(findMe2.dcRec2.dcRec3(i).dcMyJob):194:4095); // 'B' + else; + findMe2.dcRec2.dcRec3(i).dcMyJob = 'Test 20' + %char(i); + endif; + findMe2.dcRec2.dcRec3(i).dcMyRank = 20 + i; + findMe2.dcRec2.dcRec3(i).dcMyPay = 13.42 * i; + myCount = i; + endfor; + // findMe1 + findMe1.dcMyName1 = %trim(myName); + findMe1.dcRec1.dcMyName2 = %trim(myName); + findMe1.dcRec1.dcRec2.dcMyName3 = %trim(myName); + for i = 1 to max; + findMe1.dcRec1.dcRec2.dcRec3(i).dcMyName = %trim(myName) + %char(i); + if myMax > 10; + memset(%ADDR(findMe1.dcRec1.dcRec2.dcRec3(i).dcMyJob):193:4095); // 'A' + else; + findMe1.dcRec1.dcRec2.dcRec3(i).dcMyJob = 'Test 10' + %char(i); + endif; + findMe1.dcRec1.dcRec2.dcRec3(i).dcMyRank = 10 + i; + findMe1.dcRec1.dcRec2.dcRec3(i).dcMyPay = 13.41 * i; + myCount = i; + endfor; + return; + /end-free + P E + + + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * zzouch: check BAD parameter array aggregate + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + P zzouch B export + D zzouch PI + D myName 10A + D myMax 3s 0 + D wskdist 3a + D wskyear 4a + D wskytyp 1a + D wskschl 4a + D wskusr 20a + D wsksdate 8a + D wskscrse 8a + D wskssect 4a + D wsksmod 2a + D wsoptai 1a + D wsopatdt 1a + D wsoplslot 2a + D myCount 3s 0 + D wsoperrtbl 48000a + D findMe1 likeds(dcRec1_t) + D findMe2 likeds(dcRec2_t) + D findMe3 likeds(dcRec3_t) + * vars + D i S 10i 0 inz(0) + D max S 10i 0 inz(ARRAYMAX) + /free + if myMax <= max; + max = myMax; + endif; + wskdist = '123'; + wskyear = '1234'; + wskytyp = 'R'; + wskschl = '1111'; + wskusr = myName; + wsksdate = '20120102'; + wskscrse = 'frog'; + wskssect = '9999'; + wsksmod = '33'; + wsoptai = 'A'; + wsopatdt = 'B'; + wsoplslot= '12'; + wsoperrtbl = 'ok in here'; + // findMe3 + findMe3.dcMyName3 = %trim(myName); + for i = 1 to max; + findMe3.dcRec3(i).dcMyName = %trim(myName) + %char(i); + if myMax > 10; + memset(%ADDR(findMe3.dcRec3(i).dcMyJob):195:4095); // 'C' + else; + findMe3.dcRec3(i).dcMyJob = 'Test 30' + %char(i); + endif; + findMe3.dcRec3(i).dcMyRank = 30 + i; + findMe3.dcRec3(i).dcMyPay = 13.43 * i; + myCount = i; + endfor; + // findMe2 + findMe2.dcMyName2 = %trim(myName); + findMe2.dcRec2.dcMyName3 = %trim(myName); + // ouch + memset(%addr(findMe2.dcRec2.dcRec3(2).dcMyName):196:32768); // 'D' + return; + /end-free + P E + + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * zzptr1: check skip ptr + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + P zzptr1 B export + D zzptr1 PI + D myPtr1 * + D myPtr2 * + D myMax 3s 0 + D wskdist 3a + * vars + D i S 10i 0 inz(0) + D max S 10i 0 inz(ARRAYMAX) + /free + if myMax <= max; + max = myMax; + endif; + wskdist = '123'; + myPtr1 = %addr(myMax); + myPtr2 = %addr(wskdist); + return; + /end-free + P E + + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * zzbool1: check boolean + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + P zzbool1 B export + D zzbool1 PI + D myBool1 1N + D myBool2 1N + D myMax 3s 0 + D wskdist 3a + * vars + D i S 10i 0 inz(0) + D max S 10i 0 inz(ARRAYMAX) + /free + if myMax <= max; + max = myMax; + endif; + wskdist = '123'; + myBool1 = *ON; + myBool2 = *OFF; + return; + /end-free + P E + + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * zzold1: default type + *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + P zzold1 B export + D zzold1 PI + D Len 2 0 + D Wid 2 0 + D Area 4 0 + D Frog 10 + * vars + D i S 10i 0 inz(0) + D max S 10i 0 inz(ARRAYMAX) + /free + Len = 1; + Wid = 2; + Area = 3; + Frog = 'Green'; + return; + /end-free + P E + +