From b8e3bcccaf983be3d4d5763da3ea6657cddab606 Mon Sep 17 00:00:00 2001 From: michael Date: Sun, 23 Dec 2018 11:16:40 +0000 Subject: [PATCH] * Add Data Abstract classes and demo (read-only for the moment) --- demo/dataabstract/DataAbstract.js | 1947 ++++++++++++++++++++++ demo/dataabstract/DataAbstract4_intf.js | 665 ++++++++ demo/dataabstract/RemObjectsSDK.js | 2012 +++++++++++++++++++++++ demo/dataabstract/sampleda.html | 57 + demo/dataabstract/sampleda.lpi | 81 + demo/dataabstract/sampleda.lpr | 119 ++ packages/dataabstract/da.pas | 318 ++++ packages/dataabstract/dadataset.pas | 511 ++++++ packages/dataabstract/dasdk.pas | 217 +++ packages/dataabstract/rosdk.pas | 211 +++ 10 files changed, 6138 insertions(+) create mode 100644 demo/dataabstract/DataAbstract.js create mode 100644 demo/dataabstract/DataAbstract4_intf.js create mode 100644 demo/dataabstract/RemObjectsSDK.js create mode 100644 demo/dataabstract/sampleda.html create mode 100644 demo/dataabstract/sampleda.lpi create mode 100644 demo/dataabstract/sampleda.lpr create mode 100644 packages/dataabstract/da.pas create mode 100644 packages/dataabstract/dadataset.pas create mode 100644 packages/dataabstract/dasdk.pas create mode 100644 packages/dataabstract/rosdk.pas diff --git a/demo/dataabstract/DataAbstract.js b/demo/dataabstract/DataAbstract.js new file mode 100644 index 0000000..048f171 --- /dev/null +++ b/demo/dataabstract/DataAbstract.js @@ -0,0 +1,1947 @@ +RemObjects.UTIL.toBase64 = function (aValue) { + if (typeof (btoa) != 'undefined') { + return btoa(aValue); + } else { + throw (new Error("Base64 encoding is not supported by your browser.")); + //return $.base64Encode(aValue); + }; +}; + +RemObjects.UTIL.fromBase64 = function (aValue) { + if (typeof (atob) != 'undefined') { + return atob(aValue.replace(/(\n|\r)+/g, "")); + } else { + throw (new Error("Base64 decoding is not supported by your browser.")); + // return $.base64Decode(aValue); + }; + +}; + +RemObjects.DataAbstract = { + Enum: {}, + + Util: {}, + + Views: {}, + + Scripting: {}, + + DADataType: ["datUnknown", "datString", "datDateTime", "datFloat", "datCurrency", + "datAutoInc", "datInteger", "datLargeInt", "datBoolean", "datMemo", + "datBlob", "datWideString", "datWideMemo", "datLargeAutoInc", "datByte", + "datShortInt", "datWord", "datSmallInt", "datCardinal", "datLargeUInt", + "datGuid", "datXml", "datDecimal", "datSingleFloat", "datFixedChar", "datFixedWideChar", "datCursor"], + + // RemoteDataAdapter : function RemoteDataAdapter(aDataService, aLoginService, aStreamerClass) { //old api + RemoteDataAdapter: function RemoteDataAdapter(aURL, aDataServiceName, aLoginServiceName, aStreamerClass) { + var that = this; + + this.fService = new RemObjects.DataAbstract.Server.DataAbstractService(arguments[0]); + this.fLoginService = new RemObjects.SDK.RemoteService(this.fService.fChannel, this.fService.fMessage, "LoginService"); + if (arguments.length == 0) + this.fService.fChannel = { onLoginNeeded: null }; //hack for docGen + if (!(arguments[0] instanceof RemObjects.SDK.RemoteService)) this.fService.fServiceName = "DataService"; + this.fStreamerClass = RemObjects.DataAbstract.Bin2DataStreamer; + + if (RemObjects.UTIL.checkArgumentTypes(arguments, [RemObjects.SDK.RemoteService, RemObjects.SDK.RemoteService])) { + this.fLoginService = arguments[1]; + this.fStreamerClass = arguments[2] || RemObjects.DataAbstract.Bin2DataStreamer; + } else if (RemObjects.UTIL.checkArgumentTypes(arguments, ["string", "string", "string"])) { //URL, DataServiceName, LoginServiceName + this.fService.fServiceName = arguments[1]; + this.fLoginService.fServiceName = arguments[2]; + if (RemObjects.UTIL.checkArgumentTypes(arguments, ["string", "string", "string", Function])) { + this.fStreamerClass = arguments[3]; + }; + } else if (RemObjects.UTIL.checkArgumentTypes(arguments, ["string", "string"])) { //URL, DataServiceName + this.fService.fServiceName = arguments[1]; + if (RemObjects.UTIL.checkArgumentTypes(arguments, ["string", "string", Function])) { + this.fStreamerClass = arguments[2]; + }; + } else if (RemObjects.UTIL.checkArgumentTypes(arguments, ["string"])) { //URL + if (RemObjects.UTIL.checkArgumentTypes(arguments, ["string", Function])) { + this.fStreamerClass = arguments[1]; + }; + }; + + this.fSavedOnLoginNeeded = this.fService.fChannel.onLoginNeeded; + this.fService.fChannel.onLoginNeeded = function (aCallback) { that.intOnLoginNeeded(aCallback) }; + this.fSendReducedDelta = false; + this.fAutoGetScripts = false; + //methods: + //setSendReducedDelta + //buildDelta + //createStreamer + //onLoginNeeded + //login + + //asynchronous methods (pass callback function): + //getSchema + //createTableFromSchema + //getData + //applyUpdates + //getDataService + //getLoginService + //executeCommand + + + }, + + Deltas: function Deltas() { + this.deltas = []; + //methods + //findByName + + }, + + Delta: function Delta() { + this.name = ""; + this.loggedfields = []; + this.keyfields = []; + this.data = []; + }, + + Change: function Change() { + this.recid = 0; + this.changetype = ""; + this.status = ""; + this.message = ""; + this["old"] = []; + this["new"] = []; + + }, + + DataTable: function DataTable(aName) { + this.name = aName || ""; + this.fields = []; + this.keyfields = []; + this.rows = []; + this.deletedRows = []; + this.fRecordBuffer = []; + this.fNextRecId = 0; + this.fIndex = -1; + this.bofFlag = true; + this.eofFlag = true; + this.dynamicWhere = null; + this.onNewRecord = null; + this.onBeforeDelete = null; + this.onAfterDelete = null; + this.onBeforeScroll = null; + this.onAfterScroll = null; + //methods + //appendRow + //deleteRow + //markDeleted + //currentRow + //first + //next + //prev + //last + //findId + //intFindDeleted + //eof + //bof + //getFieldValue + //setFieldValue + //getFieldAsString + //setFieldAsString + //addLookupField + //fieldNumByName + //fieldByName + //locate + + }, + + Field: function Field(aName, aType) { + this.name = aName || ""; + this.type = aType || ""; + this.logChanges = true; + }, + + LookupField: function LookupField(aName, aType) { + RemObjects.DataAbstract.Field.call(this, aName, aType); + this.logChanges = false; + this.sourceField = ""; + this.lookupTable = null; + this.lookupKeyField = ""; + this.lookupResultField = ""; + }, + + DataTableRow: function DataTableRow() { + this.recId = 0; + this.state = RemObjects.DataAbstract.Enum.RowStates.rsUnchanged; + this.__oldValues = []; + this.__newValues = []; + }, + + DataStreamer: function DataStreamer() { + + }, + + JSONDataStreamer: function JSONDataStreamer() { + //methods: + //setStream + //getStream + //initializeRead + //initializeWrite + }, + + Bin2DataStreamer: function Bin2DataStreamer() { + this.fStream = ""; + this.fStreamPos = 0; + this.fStreamInfoPos = 0; + this.fParser = new BinaryParser(); + //methods: + //setStream + //getStream + //initializeRead + //initializeWrite + //readByte + //readInteger + //readAnsiStringWithLength + //readDataSet + //readField + //writeDelta + }, + + DynamicWhere: function DynamicWhere(anExpression) { + this.fExpression = anExpression; + //toXML + }, + + ConstantExpression: function ConstantExpression(aType, aValue, aNull) { + this.fType = aType; + this.fValue = aValue; + this.fNull = aNull; + //toXML + }, + + NullExpression: function NullExpression() { + + }, + + FieldExpression: function FieldExpression(aName) { + this.fName = aName; + }, + + MacroExpression: function MacroExpression(aName) { + this.fName = aName; + }, + + UnaryExpression: function UnaryExpression(aNode, anOperator) { + this.fNode = aNode; + this.fOperator = anOperator; + }, + + BinaryExpression: function BinaryExpression(aNode1, aNode2, anOperator) { + this.fNode1 = aNode1; + this.fNode2 = aNode2; + this.fOperator = anOperator; + }, + + BetweenExpression: function BetweenExpression(aNode1, aNode2, aNode3) { + this.fNode1 = aNode1; + this.fNode2 = aNode2; + this.fNode3 = aNode3; + }, + + ParameterExpression: function ParameterExpression(aName, aType, aSize) { + this.fName = aName; + this.fType = aType; + this.fSize = aSize; + }, + + ListExpression: function ListExpression(anItems) { + this.fItems = anItems; + } + +}; + +RemObjects.DataAbstract.Enum.RowStates = { + //DataTableRow states + rsUnchanged: 0, + rsModified: 1, + rsNew: 2, + rsDeleted: 3 +}; + +RemObjects.DataAbstract.Enum.ChangeType = { ctInsert: 0, ctUpdate: 1, ctDelete: 2 }; +RemObjects.DataAbstract.Enum.ChangeTypeNames = ["insert", "update", "delete"]; +RemObjects.DataAbstract.Enum.ChangeStatus = { csPending: 0, csResolved: 1, csFailed: 2 }; +RemObjects.DataAbstract.Enum.ChangeStatusNames = ["pending", "resolved", "failed"]; + + +RemObjects.DataAbstract.Util.createDataParameter = function createDataParameter(aName, aValue) { + var result = new RemObjects.DataAbstract.Server.DataParameter(); + result.Name.value = aName; + result.Value.value = aValue; + return result; +}; + + +RemObjects.DataAbstract.Util.createRequestInfo = function createRequestInfo(includeSchema, maxRecords, userFilter, parameters) { + var result = new RemObjects.DataAbstract.Server.TableRequestInfo(); + if (arguments.length == 0) { + result.IncludeSchema.value = true; + result.MaxRecords.value = -1; + result.UserFilter.value = ""; + result.Parameters.value = new RemObjects.DataAbstract.Server.DataParameterArray(); + result.Parameters.value.items = []; + } else { + result.IncludeSchema.value = includeSchema; + result.MaxRecords.value = maxRecords; + result.UserFilter.value = userFilter; + result.Parameters.value = new RemObjects.DataAbstract.Server.DataParameterArray(); + result.Parameters.value.items = parameters; + }; + return result; +}; + +RemObjects.DataAbstract.Util.createRequestInfoV5 = function createRequestInfoV5(includeSchema, maxRecords, userFilter, parameters) { + var ri = RemObjects.DataAbstract.Util.createRequestInfo.apply(this, arguments); + var result = new RemObjects.DataAbstract.Server.TableRequestInfoV5(); + result.IncludeSchema = ri.IncludeSchema; + result.MaxRecords = ri.MaxRecords; + result.UserFilter = ri.UserFilter; + result.Parameters = ri.Parameters; + + result.WhereClause = { dataType: "Xml", value: null }; + result.DynamicSelectFieldNames = { dataType: "StringArray", value: new RemObjects.DataAbstract.Server.StringArray() }; + result.DynamicSelectFieldNames.value.items = []; + result.Sorting = { dataType: "ColumnSorting", value: new RemObjects.DataAbstract.Server.ColumnSorting() }; + result.Sorting.value.fromObject({ FieldName: "", SortDirection: "Ascending" }); + return result; +}; + + +RemObjects.DataAbstract.Util.createRequestInfoV6 = function createRequestInfoV6(sql, maxRecords, userFilter, parameters) { + var result = new RemObjects.DataAbstract.Server.TableRequestInfoV6(); + if (arguments.length == 1) { + result.Sql.value = sql; + result.IncludeSchema.value = true; + result.MaxRecords.value = -1; + result.UserFilter.value = ""; + result.Parameters.value = new RemObjects.DataAbstract.Server.DataParameterArray(); + result.Parameters.value.items = []; + } else { + result.Sql.value = sql; + result.IncludeSchema.value = true; + result.MaxRecords.value = maxRecords; + result.UserFilter.value = userFilter; + result.Parameters.value = new RemObjects.DataAbstract.Server.DataParameterArray(); + result.Parameters.value.items = parameters; + }; + return result; +}; + +RemObjects.DataAbstract.Util.setupScriptingCallbacks = function setupScriptingCallbacks() { + for (var p in RemObjects.DataAbstract.Scripting) { + eval("var " + p + " = RemObjects.DataAbstract.Scripting." + p); + console.log("var " + p + " = RemObjects.DataAbstract.Scripting." + p); + }; +}; + +RemObjects.DataAbstract.Scripting.log = function log(str) { + console.log(str); +}; + +RemObjects.DataAbstract.Scripting.fail = function fail(str) { + throw new Error(str); +}; + +RemObjects.DataAbstract.Scripting.newGuidString = function newGuidString() { + return RemObjects.UTIL.NewGuid(); +}; + +//RO.DA implementation + + + +RemObjects.DataAbstract.Deltas.prototype.findByName = function findByName(aName) { + for (var i = 0; i < this.deltas.length; i++) { + if (this.deltas[i].name.toUpperCase() == aName.toUpperCase()) { + return this.deltas[i]; + }; + }; + return null; +}; + + +RemObjects.DataAbstract.Delta.prototype.intFindId = function intFindId(anId) { + for (var i = 0; i < this.data.length; i++) { + if (this.data[i].recid == anId) { + return i; + }; + }; + return null; +}; + + +RemObjects.DataAbstract.Field.prototype.checkReadOnly = function checkReadOnly() { + if (this instanceof RemObjects.DataAbstract.LookupField) { + throw new Error(this.name + ": lookup fields are read only"); + }; + if (this.readOnly == "True") { + throw new Error(this.name + " is read only."); + }; +}; + +RemObjects.DataAbstract.LookupField.prototype = new RemObjects.DataAbstract.Field(); + +RemObjects.DataAbstract.DataTable.prototype.checkRequired = function checkRequired() { + if (this.fIndex < 0) return; + for (var i = 0; i < this.fields.length; i++) { + if (this.fields[i].required == "True" && (this.fRecordBuffer[i] == null || this.fRecordBuffer[i] == undefined)) { + throw new Error("Field " + this.fields[i].name + " is required."); + }; + }; +}; + + +RemObjects.DataAbstract.DataTable.prototype.locate = function locate(aName, aValue) { + this.post(); + var result = false; + var fieldNum = this.fieldNumByName(aName); + for (var i = 0; i < this.rows.length; i++) { + if (this.rows[i].__newValues[fieldNum] == aValue) { + this.fIndex = i; + result = true; + break; + }; + }; + return result; +}; + + +RemObjects.DataAbstract.DataTable.prototype.addLookupField = function addLookupField(aName, aSourceField, aLookupTable, aLookupKeyField, aLookupResultField) { + var f = new RemObjects.DataAbstract.LookupField(aName); + f.type = aLookupTable.fieldByName(aLookupResultField).type; + f.lookupTable = aLookupTable; + f.sourceField = aSourceField; + f.lookupKeyField = aLookupKeyField; + f.lookupResultField = aLookupResultField; + this.fields.push(f); +}; + + +RemObjects.DataAbstract.DataTable.prototype.getNextId = function getNextId() { + return this.fNextRecId++; +}; + +RemObjects.DataAbstract.DataTable.prototype.intSetupProperties = function intSetupProperties(aRow) { + if (!Object.defineProperty) return; + var that = this; + for (var j = 0; j < this.fields.length; j++) { + (function (fieldNum) { + + Object.defineProperty(aRow, that.fields[fieldNum].name, { + get: function () { + return this.__newValues[fieldNum]; + }, + set: function (aValue) { + if (this.__oldValues.length == 0) + this.__oldValues = this.__newValues.slice(); + this.__oldValues[fieldNum] = this.__newValues[fieldNum]; + this.__newValues[fieldNum] = aValue; + if (this.state == RemObjects.DataAbstract.Enum.RowStates.rsUnchanged) + this.state = RemObjects.DataAbstract.Enum.RowStates.rsModified; + } + }); + + + })(j); + }; + +}; + +RemObjects.DataAbstract.DataTable.prototype.intAppendRow = function intAppendRow() { + var row = new RemObjects.DataAbstract.DataTableRow(); + row.recId = this.getNextId(); + row.state = RemObjects.DataAbstract.Enum.RowStates.rsNew; + row.__newValues = new Array(this.fields.length); + this.rows.push(row); + this.fIndex = this.rows.length - 1; + this.eofFlag = false; + this.bofFlag = false; + + this.intSetupProperties(row); + + return row; +}; + + +RemObjects.DataAbstract.DataTable.prototype.appendRow = function appendRow() { + //this.checkRequired(); + this.post(); + var row = this.intAppendRow(); + for (var i = 0; i < this.fields.length; i++) { + if (typeof (this.fields[i].fAutoIncSequence) != 'undefined') { + row.__newValues[i] = this.fields[i].fAutoIncSequence--; + } else if (this.fields[i].defaultValue != "") { + row.__newValues[i] = this.fields[i].defaultValue; + }; + }; + + if (this.__onNewRow) { + var lRow = {}; + for (var i = 0; i < this.fields.length; i++) { + lRow[this.fields[i].name] = row.__newValues[i]; + }; + this.__onNewRow(lRow); + for (var i = 0; i < this.fields.length; i++) { + row.__newValues[i] = lRow[this.fields[i].name]; + }; + }; + + this.fRecordBuffer = row.__newValues.slice(); + if (this.onNewRecord) this.onNewRecord(row); + return row; +}; + +RemObjects.DataAbstract.DataTable.prototype.deleteRow = function deleteRow() { + if (this.rows.length == 0) + throw new Error("DataTable.deleteRow: table is empty"); + + if (this.__beforeDelete) { + var row = this.currentRow(); + var lRow = {}; + for (var i = 0; i < this.fields.length; i++) { + lRow[this.fields[i].name] = row.__newValues[i]; + }; + this.__beforeDelete(lRow); + }; + + if (this.onBeforeDelete) this.onBeforeDelete(this.currentRow()); + + this.markDeleted(); + this.deletedRows.push(this.rows[this.fIndex]); + this.rows.splice(this.fIndex, 1); + if (this.fIndex == this.rows.length) + this.fIndex--; + this.eofFlag = (this.rows.length == 0); + this.bofFlag = (this.rows.length == 0); + this.fRecordBuffer = []; + + if (this.onAfterDelete && this.rows.length) this.onAfterDelete(this.currentRow()); +}; + +RemObjects.DataAbstract.DataTable.prototype.markDeleted = function markDeleted() { + if (this.rows[this.fIndex].__oldValues.length == 0) + this.rows[this.fIndex].__oldValues = this.rows[this.fIndex].__newValues.slice(); + this.rows[this.fIndex].state = RemObjects.DataAbstract.Enum.RowStates.rsDeleted; +}; + +RemObjects.DataAbstract.DataTable.prototype.fieldNumByName = function fieldNumByName(aName) { + var fieldNum = -1; + for (var i = 0; i < this.fields.length; i++) { + if (this.fields[i].name.toUpperCase() == aName.toUpperCase()) { + fieldNum = i; + break; + }; + }; + if (fieldNum == -1) + throw new Error("DataTable.fieldNumByName: no such field name - " + aName); + return fieldNum; +}; + +RemObjects.DataAbstract.DataTable.prototype.fieldByName = function fieldByName(aName) { + return this.fields[this.fieldNumByName(aName)]; +}; + + +RemObjects.DataAbstract.DataTable.prototype.setFieldValue = function setFieldValue(aField, aValue) { + if (this.rows.length == 0) + throw new Error("DataTable.setFieldValue: table is empty"); + var fieldNum = this.fieldNumByName(aField); + var f = this.fields[fieldNum]; + f.checkReadOnly(); + if (this.rows[this.fIndex].__oldValues.length == 0) + this.rows[this.fIndex].__oldValues = this.rows[this.fIndex].__newValues.slice(); + if (this.rows[this.fIndex].state == RemObjects.DataAbstract.Enum.RowStates.rsUnchanged) + this.rows[this.fIndex].state = RemObjects.DataAbstract.Enum.RowStates.rsModified; + if (this.fRecordBuffer.length == 0) + this.fRecordBuffer = this.rows[this.fIndex].__newValues.slice(); + + this.fRecordBuffer[fieldNum] = aValue; +}; + + +RemObjects.DataAbstract.DataTable.prototype.getFieldValue = function getFieldValue(aField) { + if (this.rows.length == 0) + throw new Error("DataTable.getFieldValue: table is empty"); + var fieldNum = this.fieldNumByName(aField); + var f = this.fields[fieldNum]; + if (f instanceof RemObjects.DataAbstract.LookupField) { + if (f.lookupTable.locate(f.lookupKeyField, this.getFieldValue(f.sourceField))) { + return f.lookupTable.getFieldValue(f.lookupResultField); + } else { + return null; + }; + } else if (this.fRecordBuffer.length == 0) { + return this.rows[this.fIndex].__newValues[fieldNum]; + } else { + return this.fRecordBuffer[fieldNum]; + }; +}; + + +RemObjects.DataAbstract.DataTable.prototype.setFieldAsString = function setFieldAsString(aField, aValue) { + if (this.rows.length == 0) + throw new Error("DataTable.setFieldAsString: table is empty"); + var tempValue; + var fieldNum = this.fieldNumByName(aField); + var f = this.fields[fieldNum]; + f.checkReadOnly(); + if (this.rows[this.fIndex].__oldValues.length == 0) + this.rows[this.fIndex].__oldValues = this.rows[this.fIndex].__newValues.slice(); + if (this.rows[this.fIndex].state == RemObjects.DataAbstract.Enum.RowStates.rsUnchanged) + this.rows[this.fIndex].state = RemObjects.DataAbstract.Enum.RowStates.rsModified; + if (this.fRecordBuffer.length == 0) + this.fRecordBuffer = this.rows[this.fIndex].__newValues.slice(); + + if (aValue == "") { + if (this.rows[this.fIndex].__oldValues[fieldNum] == null) + tempValue = null; + } else { + switch (this.fields[fieldNum].type) { + //case "datBlob": return; + case "datInteger": + case "datAutoInc": + case "datSmallInt": + case "datByte": + case "datLargeInt": + case "datLargeAutoInc": + case "datLargeUInt": + case "datShortInt": + case "datWord": + case "datCardinal": + tempValue = parseInt(aValue); + break; + case "datFloat": + case "datCurrency": + case "datSingleFloat": + case "datDecimal": + tempValue = parseFloat(aValue); + break; + case "datDateTime": + tempValue = new Date(aValue); + break; + case "datBoolean": + tempValue = (aValue.toUpperCase() == "TRUE"); + default: + tempValue = aValue; + //todo + }; + }; + this.fRecordBuffer[fieldNum] = tempValue; +}; + + +RemObjects.DataAbstract.DataTable.prototype.getFieldAsString = function getFieldAsString(aField) { + var fieldNum = this.fieldNumByName(aField); + var value = this.getFieldValue(aField); + return (this.fields[fieldNum].type == "datBlob" ? "(Blob)" : ( + (value != undefined && value != null) + ? value : "").toString()); + +}; + + +RemObjects.DataAbstract.DataTable.prototype.currentRow = function currentRow() { + return (this.rows.length ? this.rows[this.fIndex] : null); +}; + +RemObjects.DataAbstract.DataTable.prototype.intGoToIndex = function intGoToIndex(anIndex) { + if (this.onBeforeScroll) this.onBeforeScroll(this.currentRow()); + this.fIndex = anIndex; + if (this.onAfterScroll) this.onAfterScroll(this.currentRow()); +}; + +RemObjects.DataAbstract.DataTable.prototype.first = function first() { + this.post(); + if (this.rows.length > 0) + this.intGoToIndex(0); + this.bofFlag = true; + this.eofFlag = false; + return this.currentRow(); +}; + +RemObjects.DataAbstract.DataTable.prototype.last = function last() { + this.post(); + if (this.rows.length > 0) + this.intGoToIndex(this.rows.length - 1); + this.eofFlag = true; + this.bofFlag = false; + return this.currentRow(); +}; + +RemObjects.DataAbstract.DataTable.prototype.next = function next() { + this.post(); + if (this.fIndex < this.rows.length - 1) { + this.intGoToIndex(this.fIndex + 1); + this.bofFlag = false; + return this.currentRow(); + } else { + this.eofFlag = true; + return null; + }; +}; + +RemObjects.DataAbstract.DataTable.prototype.prev = function prev() { + this.post(); + if (this.fIndex > 0) { + this.intGoToIndex(this.fIndex - 1); + this.eofFlag = false; + return this.currentRow(); + } else { + this.bofFlag = true; + return null; + }; +}; + +RemObjects.DataAbstract.DataTable.prototype.findId = function findId(anId) { + this.post(); + for (var i = 0; i < this.rows.length; i++) { + if (this.rows[i].recId == anId) { + this.intGoToIndex(i); + return this.currentRow(); + }; + }; + return null; +}; + +RemObjects.DataAbstract.DataTable.prototype.intFindDeleted = function intFindDeleted(anId) { + for (var i = 0; i < this.deletedRows.length; i++) { + if (this.deletedRows[i].recId == anId) { + return i; + }; + }; + return null; +}; + + +RemObjects.DataAbstract.DataTable.prototype.eof = function eof() { + return this.eofFlag; +}; + +RemObjects.DataAbstract.DataTable.prototype.bof = function bof() { + return this.bofFlag; +}; + +RemObjects.DataAbstract.DataTable.prototype.post = function post() { + var bufferNotSet = true; + for (var i = 0; i < this.fRecordBuffer.length; i++) { + if (typeof this.fRecordBuffer[i] != 'undefined') + { + bufferNotSet = false; + break; + } + } + + if (bufferNotSet) { + return; + } + + + if (this.__beforePost) { + var lRow = {}; + for (var i = 0; i < this.fields.length; i++) { + lRow[this.fields[i].name] = this.fRecordBuffer[i]; + }; + try { + this.__beforePost(lRow); + for (var i = 0; i < this.fields.length; i++) { + this.fRecordBuffer[i] = lRow[this.fields[i].name]; + }; + } catch (e) { throw e }; + }; + + this.checkRequired(); + this.rows[this.fIndex].__newValues = this.fRecordBuffer; + this.fRecordBuffer = []; +}; + +RemObjects.DataAbstract.DataTable.prototype.cancel = function cancel() { + this.fRecordBuffer = []; +}; + +RemObjects.DataAbstract.RemoteDataAdapter.prototype.getDataService = function getDataService() { + return this.fService; +}; + +RemObjects.DataAbstract.RemoteDataAdapter.prototype.getLoginService = function getLoginService() { + return this.fLoginService; +}; + + +RemObjects.DataAbstract.RemoteDataAdapter.prototype.intOnLoginNeeded = function intOnLoginNeeded(aCallback) { + if (this.onLoginNeeded) { + this.onLoginNeeded(aCallback) + } else { + this.fSavedOnLoginNeeded(aCallback); + }; +}; + + +RemObjects.DataAbstract.RemoteDataAdapter.prototype.onLoginNeeded = function onLoginNeeded(aCallback) { + RemObjects.UTIL.showMessage("Default onLoginNeeded handler: assign remoteDataAdapter.onLoginNeeded and call aCallback there after successful login"); + //example: + // this.login("John", "password", function(result) { + // if (aCallback) + // aCallback(); + // }, function(msg, e) { + // if (e) + // throw e + // else + // throw new Error(msg.getErrorMessage()); + // }); +}; + + +RemObjects.DataAbstract.RemoteDataAdapter.prototype.login = function login(aUserID, aPassword, aConnectionName, onSuccessFunction, onErrorFunction) { + + if (!this.fLoginService) + throw new Error("RemoteDataAdapter.login: login service not assigned"); + + var svc; + switch (arguments.length - 2) { + case 1: //loginString + svc = new RemObjects.DataAbstract.Server.BaseLoginService(this.fLoginService); + svc.LoginEx(arguments[0], arguments[1], arguments[2]); + break; + case 2: //userID, password + svc = new RemObjects.DataAbstract.Server.SimpleLoginService(this.fLoginService); + svc.Login(arguments[0], arguments[1], arguments[2], arguments[3]); + break; + case 3: //userID, password, connection + svc = new RemObjects.DataAbstract.Server.MultiDbLoginService(this.fLoginService); + svc.Login(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]); + break; + default: + throw new Error("RemoteDataAdapter.login: incorrect number of arguments"); + }; + +}; + +RemObjects.DataAbstract.RemoteDataAdapter.prototype.logout = function logout(onSuccessFunction, onErrorFunction) { + if (!this.fLoginService) + throw new Error("RemoteDataAdapter.logout: login service not assigned"); + + var svc = new RemObjects.DataAbstract.Server.BaseLoginService(this.fLoginService); + svc.Logout(onSuccessFunction, onErrorFunction); +}; + + +RemObjects.DataAbstract.RemoteDataAdapter.prototype.getSchema = function getSchema(aFilter, aCallback, onFailure) { + var that = this; + this.fService.GetSchema(aFilter, aCallback, onFailure || RemObjects.UTIL.showError); +}; + + +RemObjects.DataAbstract.RemoteDataAdapter.prototype.createStreamer = function createStreamer() { + return new this.fStreamerClass(); +}; + +RemObjects.DataAbstract.RemoteDataAdapter.prototype.setSendReducedDelta = function setSendReducedDelta(aValue) { + this.fSendReducedDelta = aValue; +}; + +RemObjects.DataAbstract.RemoteDataAdapter.prototype.buildDelta = function buildDelta(aTable) { + + function processRows(aRows, aDelta) { + for (var i = 0; i < aRows.length; i++) { + + var c = new RemObjects.DataAbstract.Change(); + c.status = "pending"; + c.recid = aRows[i].recId; + if (aRows[i].state == RemObjects.DataAbstract.Enum.RowStates.rsNew) { + c.old = aRows[i].__newValues.slice(); + } else { + c.old = aRows[i].__oldValues.slice(); + }; + c["new"] = aRows[i].__newValues.slice(); + excludeItems(c.old); + excludeItems(c["new"]); + + switch (aRows[i].state) { + case RemObjects.DataAbstract.Enum.RowStates.rsModified: c.changetype = "update"; break; + case RemObjects.DataAbstract.Enum.RowStates.rsNew: c.changetype = "insert"; break; + case RemObjects.DataAbstract.Enum.RowStates.rsDeleted: c.changetype = "delete"; break; + }; + + aDelta.data.push(c); + }; + }; + + function excludeItems(anArray) { + for (var i = excludedFields.length - 1; i >= 0; i--) { + anArray.splice(excludedFields[i], 1); + }; + }; + + var excludedFields = []; + for (var i = 0; i < aTable.fields.length; i++) { + if (!aTable.fields[i].logChanges) { + excludedFields.push(i); + }; + }; + var changedRows = []; + for (var i = 0; i < aTable.rows.length; i++) { + if (aTable.rows[i].state != RemObjects.DataAbstract.Enum.RowStates.rsUnchanged) changedRows.push(aTable.rows[i]); + }; + + if ((changedRows.length > 0) || (aTable.deletedRows.length > 0)) { + + d = new RemObjects.DataAbstract.Delta(); + d.name = aTable.name; + d.keyfields = aTable.keyfields.slice(); + d.loggedfields = aTable.fields.slice(); + excludeItems(d.loggedfields); + + processRows(changedRows, d); + processRows(aTable.deletedRows, d); + return d; + } else { + return null; + }; +}; + +RemObjects.DataAbstract.RemoteDataAdapter.prototype.createTableFromSchema = function createTableFromSchema(aTableName, aTable, aCallback) { + var that = this; + var tablesArray = new RemObjects.DataAbstract.Server.StringArray(); + tablesArray.items = [aTableName]; + this.fService.GetTableSchema(tablesArray, function (result) { + var xmlDoc; + if (typeof (DOMParser) != 'undefined') { + var parser = new DOMParser(); + xmlDoc = parser.parseFromString(result, "text/xml"); + } else // Internet Explorer + { + xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); + xmlDoc.async = "false"; + xmlDoc.loadXML(result); + }; + + var fieldsNode = xmlDoc.getElementsByTagName("Fields")[0]; + for (i = 0; i < fieldsNode.childElementCount; i++) { + var f = new RemObjects.DataAbstract.Field(); + f.name = fieldsNode.childNodes[i].getElementsByTagName('Name')[0].textContent; + f.type = fieldsNode.childNodes[i].getElementsByTagName('DataType')[0].textContent; + f.logChanges = (fieldsNode.childNodes[i].getElementsByTagName('LogChanges')[0].textContent == "True"); + if (fieldsNode.childNodes[i].getElementsByTagName('InPrimaryKey')[0].textContent == "True") + aTable.keyfields.push(f.name); + + aTable.fields.push(f); + + }; + if (aCallback) + aCallback(); + }, RemObjects.UTIL.showError); +}; + + +RemObjects.DataAbstract.RemoteDataAdapter.prototype.executeCommand = function executeCommand(aName, aParameters, onSuccess, onError) { + if (aParameters.constructor != Array) { + aParameters = [aParameters]; + }; + var params = new RemObjects.DataAbstract.Server.DataParameterArray(); + params.items = aParameters; + this.fService.ExecuteCommand(aName, params, onSuccess, onError) +}; + +RemObjects.DataAbstract.RemoteDataAdapter.prototype.getSQLData = function getSQLData(aTable, aSQL, onSuccess, onError) { + var ria = new RemObjects.DataAbstract.Server.TableRequestInfoArray(); + ria.elementType = "TableRequestInfoV6"; + + if (aTable.constructor != Array) { + aTable = [aTable]; + }; + + switch (aSQL.constructor) { + case RemObjects.DataAbstract.Server.TableRequestInfoV6: + ria.items.push(aSQL); + break; + case Array: + for (var i = 0; i < aTable.length; i++) { + switch (aSQL[i].constructor) { + case RemObjects.DataAbstract.Server.TableRequestInfoV6: + ria.items.push(aSQL[i]); + break; + case String: + ria.items.push(RemObjects.DataAbstract.Util.createRequestInfoV6(aSQL[i])); + break; + default: + throw new Error("rda.getSQLData: incorrect aRequestInfo array item"); + }; + }; + break; + case String: + ria.items.push(RemObjects.DataAbstract.Util.createRequestInfoV6(aSQL)); + break; + default: + throw new Error("rda.getSQLData: incorrect aSQL"); + }; + + this.getData(aTable, ria, onSuccess, onError); +}; + +RemObjects.DataAbstract.RemoteDataAdapter.prototype.getAutoGetScripts = function getAutoGetScripts() { + return this.fAutoGetScripts; +}; + +RemObjects.DataAbstract.RemoteDataAdapter.prototype.setAutoGetScripts = function setAutoGetScripts(aValue) { + this.fAutoGetScripts = aValue; +}; + +RemObjects.DataAbstract.RemoteDataAdapter.prototype.intGetScripts = function intGetScripts(aTable, onSuccess, onError) { + var tableNames = []; + if (aTable.constructor != Array) { + aTable = [aTable]; + }; + for (var i = 0; i < aTable.length; tableNames.push(aTable[i++].name)); + this.fService.GetDatasetScripts(tableNames.join(","), function (aScript) { + for (var t = 0; t < aTable.length; t++) { + var __tbl = aTable[t]; + __tbl.__onNewRow = null; + __tbl.__beforeDelete = null; + __tbl.__beforePost = null; + var r = new RegExp('<' + aTable[t].name + ' Language="(.*?)"> 0) { + var that = this; + var streamer = this.createStreamer(); + streamer.initializeWrite(); + streamer.writeDelta(__deltas, this.fSendReducedDelta); + streamer.finalizeWrite(); + + var tmp = streamer.getStream(); + + this.fService.UpdateData(tmp, function (result) { + var tmp = (that.fService.fMessage instanceof RemObjects.SDK.JSONMessage) ? RemObjects.UTIL.fromBase64(result) : result; + + var streamer = that.createStreamer(); + streamer.setStream(tmp); + streamer.initializeRead(); + var __res = streamer.readDelta(); + + for (var i = 0; i < __deltas.deltas.length; i++) { + var processedTable = null; + for (var t = 0; t < aTable.length; t++) { + if (aTable[t].name == __deltas.deltas[i].name) { + processedTable = aTable[t]; + break; + }; + }; + + var baseDelta = __deltas.deltas[i]; + var processedDelta = __res.findByName(__deltas.deltas[i].name); + if (processedDelta) { + for (var j = 0; j < processedDelta.data.length; j++) { + + if (processedTable) { + switch (processedDelta.data[j].status) { + case "failed": + that.onChangeFail(processedDelta.data[j]); + //remove from baseDelta + baseDelta.data.splice(baseDelta.intFindId(processedDelta.data[j].recid), 1); + break; + case "resolved": + if (processedTable.findId(processedDelta.data[j].recid)) { + for (var k = 0; k < processedDelta.loggedfields.length; k++) { + if (processedDelta.data[j]["new"][k] != processedDelta.data[j]["old"][k]) { + var fieldNum = processedTable.fieldNumByName(processedDelta.loggedfields[k].name); + processedTable.currentRow().__newValues[fieldNum] = processedDelta.data[j]["new"][k]; + processedTable.currentRow().__oldValues[fieldNum] = processedDelta.data[j]["new"][k]; + }; + }; + processedTable.currentRow().state = RemObjects.DataAbstract.Enum.RowStates.rsUnchanged; + processedTable.currentRow().__oldValues = processedTable.currentRow().__newValues.slice(); + } else { + var deleted = processedTable.intFindDeleted(processedDelta.data[j].recid); + if (deleted != null) { + processedTable.deletedRows.splice(deleted, 1); + } else { + RemObjects.UTIL.showMessage("Incorrect recid in resolved change:\n" + RemObjects.UTIL.toJSON(processedDelta.data[j])); + }; + }; + break; + }; + } else { + RemObjects.UTIL.showMessage("Incorrect table name in result delta:\n" + RemObjects.UTIL.toJSON(processedDelta)); + }; + }; + + + }; + + for (var j = 0; j < baseDelta.data.length; j++) { + if (processedTable.findId(baseDelta.data[j].recid)) { + processedTable.currentRow().state = RemObjects.DataAbstract.Enum.RowStates.rsUnchanged; + processedTable.currentRow().__oldValues = []; + }; + var deleted = processedTable.intFindDeleted(baseDelta.data[j].recid); + if (deleted != null) { + processedTable.deletedRows.splice(deleted, 1); + }; + + }; + }; + + if (onSuccess) onSuccess(__res); + }, onError); + }; +}; + + +RemObjects.DataAbstract.JSONDataStreamer.prototype.setStream = function setStream(aStream) { + this.fStream = aStream; +}; + +RemObjects.DataAbstract.JSONDataStreamer.prototype.getStream = function getStream() { + return this.fStream; +}; + + +RemObjects.DataAbstract.JSONDataStreamer.prototype.initializeRead = function () { +}; + +RemObjects.DataAbstract.JSONDataStreamer.prototype.initializeWrite = function () { +}; + +RemObjects.DataAbstract.JSONDataStreamer.prototype.finalizeWrite = function () { +}; + +RemObjects.DataAbstract.JSONDataStreamer.prototype.readDataset = function readDataset(dataset) { + dataset.rows = []; + dataset.fNextRecId = 0; + var rows = null; + var datasets = RemObjects.UTIL.parseJSON(this.fStream).datasets; + for (var i = 0; i < datasets.length; i++) { + if (datasets[i].schema) { + dataset.fields.length = 0; + dataset.keyfields.length = 0; + for (var j = 0; j < datasets[i].schema.fields.length; j++) { + var schemaField = datasets[i].schema.fields[j]; + var datasetField = new RemObjects.DataAbstract.Field(); + datasetField.name = schemaField.Name; + datasetField.type = schemaField.DataType; + datasetField.logChanges = schemaField.LogChanges; + + if (schemaField.InPrimaryKey == true) { + datasetField.inPrimaryKey = true; + dataset.keyfields.push(schemaField.Name); + }; + + dataset.fields.push(datasetField); + }; + }; + if (datasets[i].name.toUpperCase() == dataset.name.toUpperCase()) { + rows = datasets[i].data.rows; + break; + }; + }; + + if (!rows) throw new Error("readDataset: dataset not found - " + dataset.name); + + for (var i = 0; i < rows.length; i++) { + var r = dataset.intAppendRow(); + r.state = RemObjects.DataAbstract.Enum.RowStates.rsUnchanged; + r.__newValues = rows[i]; + }; +}; + +RemObjects.DataAbstract.JSONDataStreamer.prototype.writeDelta = function writeDelta(aDelta) { + this.fStream = RemObjects.UTIL.toJSON(aDelta); +}; + +RemObjects.DataAbstract.JSONDataStreamer.prototype.readDelta = function readDelta() { + var result = new RemObjects.DataAbstract.Deltas(); + var remoteDelta = RemObjects.UTIL.parseJSON(this.fStream); + + if (remoteDelta.deltas) { + for (var i = 0; i < remoteDelta.deltas.length; i++) { + result.deltas.push(remoteDelta.deltas[i]); + }; + }; + + return result; +}; + + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.setStream = function setStream(aStream) { + this.fStream = aStream; +}; + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.getStream = function getStream() { + return this.fStream; +}; + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.initializeRead = function initializeRead() { + if (this.fStream.substr(0, 8) != "DABIN200") + throw new Error("Bin2DataStreamer.initializeRead: incorrect stream header"); + this.fStreamPos = 8; + this.fStreamInfoPos = this.readInteger(); +}; + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.initializeWrite = function initializeWrite() { +}; + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.finalizeWrite = function finalizeWrite() { + this.fStream = "DABIN200" + this.fParser.encodeInt(this.fStreamInfoPos + 12, 32, false) + this.fStream; +}; + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.readByte = function readByte() { + var result = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 1), 8, false); + this.fStreamPos += 1; + return result; +}; + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.readInteger = function readInteger() { + var result = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 4), 32, false); + this.fStreamPos += 4; + return result; +}; + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.readAnsiStringWithLength = function readAnsiStringWithLength() { + var len = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 4), 32, false); + this.fStreamPos += 4; + var result = this.fStream.substr(this.fStreamPos, len); + this.fStreamPos += len; + return result; +}; + + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.readUtf8StringWithLength = function readUtf8StringWithLength() { + var len = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 4), 32, true); + this.fStreamPos += 4; + if (len == -1) return null; + var result = RemObjects.UTIL.byteArrayToStr(this.fStream.substr(this.fStreamPos, len)); + this.fStreamPos += len; + return result; +}; + + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.read = function read(aType) { + var value; + switch (aType) { + case "datFixedChar"://ok + case "datString"://ok + case "datMemo"://ok + var len = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 4), 32, false); + this.fStreamPos += 4; + value = this.fStream.substr(this.fStreamPos, len); + this.fStreamPos += len; + break; + + case "datBlob": + case "datCursor": + var len = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 4), 32, false); + this.fStreamPos += 4; + + value = this.fStream.substr(this.fStreamPos, len); + this.fStreamPos += len; + break; + + /* value = ""; + for (var i = this.fStreamPos; i < this.fStreamPos + len; i++) { + value += String.fromCharCode(this.fStream.charCodeAt(i) & 0xFF); + }; + this.fStreamPos += len; + break; + */ + case "datWideString"://ok + case "datFixedWideChar"://ok + case "datWideMemo"://ok + case "datXml"://ok + var len = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 4), 32, false); + this.fStreamPos += 4; + value = RemObjects.UTIL.byteArrayToUtf16(this.fStream.substr(this.fStreamPos, len)); + this.fStreamPos += len; + break; + + + case "datAutoInc"://ok + case "datInteger"://ok + value = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 4), 32, true); + this.fStreamPos += 4; + break; + + case "datSmallInt"://ok + value = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 2), 16, true); + this.fStreamPos += 2; + break; + + case "datDateTime"://ok + var utcValue = this.fParser.decodeFloat(this.fStream.substr(this.fStreamPos, 8), 52, 11); + utcValue = new Date(Math.round((utcValue - 25569.0) * 86400000)); + value = new Date(utcValue.getUTCFullYear(), utcValue.getUTCMonth(), utcValue.getUTCDate(), utcValue.getUTCHours(), utcValue.getUTCMinutes(), utcValue.getUTCSeconds()); + //value = this.fParser.decodeFloat(this.fStream.substr(this.fStreamPos, 8), 52, 11); + //value = new Date(Math.round((value - 25569.0) * 86400000)); + this.fStreamPos += 8; + break; + + case "datCurrency"://ok + value = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 6), 48, true) / 10000; + this.fStreamPos += 8; + break; + case "datFloat"://ok + value = this.fParser.decodeFloat(this.fStream.substr(this.fStreamPos, 8), 52, 11); + this.fStreamPos += 8; + break; + + case "datSingleFloat": //ok + value = this.fParser.decodeFloat(this.fStream.substr(this.fStreamPos, 4), 23, 8); + this.fStreamPos += 4; + break; + + case "datBoolean"://ok + value = !(this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 1), 8, false) == 0); + this.fStreamPos += 1; + break; + + case "datByte"://ok + value = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 1), 8, false); + this.fStreamPos += 1; + break; + + case "datLargeInt"://ok + case "datLargeAutoInc"://ok + value = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 6), 48, true); + this.fStreamPos += 8; + break; + + case "datLargeUInt"://ok + value = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 6), 48, false); + this.fStreamPos += 8; + break; + + case "datShortInt"://ok + value = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 1), 8, true); + this.fStreamPos += 1; + break; + + case "datWord"://ok + value = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 2), 16, false); + this.fStreamPos += 2; + break; + + case "datDecimal"://ok + var decimal = []; + for (var i = 0; i < 6; i++) { + decimal[i] = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 2), 16, false); + this.fStreamPos += 2; + }; + decimal[6] = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 4), 32, false); + this.fStreamPos += 4; + value = parseFloat(RemObjects.UTIL.decimalToString(decimal)); + break; + + case "datGuid"://ok + value = "{" + this.fStream.substr(this.fStreamPos, 36) + "}"; + this.fStreamPos += 36; + break; + + case "datCardinal"://ok + value = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, 4), 32, false); + this.fStreamPos += 4; + break; + + /* + datBlob: BlobToStreamAsStr(Stream, Value); + * */ + + default: + throw new Error("Bin2DataStreamer.read: unknown type " + aType); + }; + return value; +}; + + + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.readParam = function readParam(aPropCount) { + + var result = {}; + for (var i = 0; i < aPropCount; i++) { + result[this.readAnsiStringWithLength()] = this.readUtf8StringWithLength(); + }; + + return result; +}; + + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.readField = function readField(aPropCount) { + + function camelize(str) { + return str.substr(0, 1).toLowerCase() + str.substr(1); + }; + + var result = new RemObjects.DataAbstract.Field(); + + try { + for (var i = 0; i < aPropCount; i++) { + result[camelize(this.readAnsiStringWithLength())] = this.readUtf8StringWithLength(); + }; + + result.type = result.dataType; + if (result.type == "datAutoInc" || result.type == "datLargeAutoInc") { + result.fAutoIncSequence = -1; + }; + result.logChanges = (result.logChanges == "True"); + return result; + } catch (e) { + throw new Error("Bin2DataStreamer.readField: " + e.message); + }; +}; + + + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.readDataset = function readDataset(aDataset) { + if (this.readByte() != 0) {//schema present + this.readInteger(); //skip schema end position + var fieldCount = this.readInteger(); + var propCount = this.readInteger(); + aDataset.fields = []; + aDataset.keyfields = []; + for (var i = 0; i < fieldCount; i++) { + var f = this.readField(propCount); + aDataset.fields.push(f); + if (f.inPrimaryKey.toLowerCase() == "true") { + aDataset.keyfields.push(f.name); + }; + }; + + var paramCount = this.readInteger(); + propCount = this.readInteger(); + for (var i = 0; i < paramCount; i++) { + this.readParam(propCount); + }; + } else { + this.readInteger(); //skip schema end position + }; + var rowCount = this.readInteger(); + var fieldCount = this.readInteger(); + aDataset.rows = []; + aDataset.fNextRecId = 0; + + for (var i = 0; i < fieldCount; i++) { + this.readAnsiStringWithLength(); //skip field name + this.readByte(); //skip field type + this.readInteger(); //skip field size + }; + + var bitMaskSize = Math.floor((fieldCount + 7) / 8); + for (var i = 0; i < rowCount; i++) { + var r = aDataset.intAppendRow(); + r.state = RemObjects.DataAbstract.Enum.RowStates.rsUnchanged; + + var bitMask = ""; + for (var b = 0; b < bitMaskSize; b++) { + bitMask += RemObjects.UTIL.zeroPad(this.fParser.decodeInt(this.fStream.substr(this.fStreamPos + bitMaskSize - 1 - b, 1), 8, false).toString(2), 8); + }; + var bitMaskArray = bitMask.split("").reverse(); + + this.fStreamPos += bitMaskSize; + + for (var j = 0; j < fieldCount; j++) { + r.__newValues[j] = (bitMaskArray[j] == '1') ? null : this.read(aDataset.fields[j].type); + }; + }; + + +}; + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.writeInteger = function writeInteger(aValue) { + this.write("datInteger", aValue); +}; + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.writeByte = function writeByte(aValue) { + this.fStream += this.fParser.encodeInt(aValue, 8, true); +}; + + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.writeAnsiStringWithLength = function writeAnsiStringWithLength(aValue) { + this.fStream += this.fParser.encodeInt(aValue.length, 32, false) + aValue; +}; + + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.write = function write(aType, aValue) { + switch (aType) { + case "datFixedChar"://ok + case "datString"://ok + case "datMemo"://ok + case "datBlob": + case "datCursor": + this.writeAnsiStringWithLength(aValue); + break; + + case "datWideString"://ok + case "datFixedWideChar"://ok + case "datWideMemo"://ok + case "datXml"://ok + this.fStream += this.fParser.encodeInt(aValue.length * 2, 32, true); + this.fStream += RemObjects.UTIL.utf16ToByteArray(aValue); + break; + + case "datAutoInc"://ok + case "datInteger"://ok + this.fStream += this.fParser.encodeInt(aValue, 32, true); + break; + + case "datSmallInt"://ok + this.fStream += this.fParser.encodeInt(aValue, 16, true); + break; + + case "datDateTime"://todo:test + if (!(aValue instanceof Date)) { + throw new Error("Not a Date value: " + aValue); + }; + this.fStream += this.fParser.encodeFloat((aValue - aValue.getTimezoneOffset() * 60000) / 86400000 + 25569.0, 52, 11); + break; + + case "datCurrency": + var cur = this.fParser.encodeInt(aValue * 10000, 48, true); + this.fStream += cur; + if ((cur.charCodeAt(cur.length - 1) == 0) || (cur.charCodeAt(cur.length - 1) == 0xFF)) { + this.fStream += cur.substr(cur.length - 1, 1) + cur.substr(cur.length - 1, 1); + }; + break; + + case "datFloat"://ok + this.fStream += this.fParser.encodeFloat(aValue, 52, 11); + break; + + case "datSingleFloat": //ok + this.fStream += this.fParser.encodeFloat(aValue, 23, 8); + break; + + case "datBoolean"://ok + this.fStream += this.fParser.encodeInt(aValue ? 1 : 0, 8, false); + break; + + case "datByte"://ok + this.fStream += this.fParser.encodeInt(aValue, 8, false); + break; + + case "datLargeInt"://ok + case "datLargeAutoInc"://ok + var large = this.fParser.encodeInt(aValue, 48, true); + this.fStream += large; + if ((large.charCodeAt(large.length - 1) == 0) || (large.charCodeAt(large.length - 1) == 0xFF)) { + this.fStream += large.substr(large.length - 1, 1) + large.substr(large.length - 1, 1); + }; + break; + + case "datLargeUInt"://ok + var large = this.fParser.encodeInt(aValue, 48, false); + this.fStream += large; + if ((large.charCodeAt(large.length - 1) == 0) || (large.charCodeAt(large.length - 1) == 0xFF)) { + this.fStream += large.substr(large.length - 1, 1) + large.substr(large.length - 1, 1); + }; + break; + + case "datShortInt"://ok + this.fStream += this.fParser.encodeInt(aValue, 8, true); + break; + + case "datWord"://ok + this.fStream += this.fParser.encodeInt(aValue, 16, false); + break; + + case "datDecimal"://ok + var decimal = RemObjects.UTIL.stringToDecimal(aValue.toString()); + for (var i = 0; i < 6; i++) { + this.fStream += this.fParser.encodeInt(decimal[i], 16, false); + }; + this.fStream += this.fParser.encodeInt(decimal[6], 32, false); + break; + + case "datGuid"://ok + this.fStream += aValue.substr(1, 36); + break; + + case "datCardinal"://ok + this.fStream += this.fParser.encodeInt(aValue, 32, false); + break; + + /* + datBlob: BlobToStreamAsStr(Stream, Value); + * */ + + default: + throw new Error("Bin2DataStreamer.write: unknown type " + aType); + }; +}; + + + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.writeDelta = function writeDelta(aDeltas, aSendReducedDelta) { + function indexOf(anArray, aValue) { + for (var i = 0; i < anArray.length; i++) { + if (anArray[i] == aValue) return i; + }; + return -1; + }; + + var offsets = []; + for (var d = 0; d < aDeltas.deltas.length; d++) { + offsets.push(this.fStream.length); + var aDelta = aDeltas.deltas[d]; + + this.writeInteger(aDelta.data.length); //changes count + + this.writeInteger(aDelta.loggedfields.length); //fields count + for (var i = 0; i < aDelta.loggedfields.length; i++) { + this.writeAnsiStringWithLength(RemObjects.UTIL.strToByteArray(aDelta.loggedfields[i].name)); + this.writeByte(indexOf(RemObjects.DataAbstract.DADataType, aDelta.loggedfields[i].type)); + }; + + this.writeInteger(aDelta.keyfields.length); //key fields count + for (var i = 0; i < aDelta.keyfields.length; i++) { + this.writeAnsiStringWithLength(RemObjects.UTIL.strToByteArray(aDelta.keyfields[i])); + }; + + this.writeByte(aSendReducedDelta ? 1 : 0); //hasReducedDelta + + this.writeInteger(aDelta.data.length); //changes count + + var bitMaskSize = Math.floor((aDelta.loggedfields.length + 7) / 8); + + var bitMaskOld; + var bitMaskNew; + + for (var i = 0; i < aDelta.data.length; i++) { + bitMaskOld = new Array(bitMaskSize); + bitMaskNew = new Array(bitMaskSize); + + for (var j = 0; j < aDelta.loggedfields.length; j++) { + bitMaskNew[j] = (aDelta.data[i]["new"][j] == null || typeof (aDelta.data[i]["new"][j]) == 'undefined') ? "0" : "1"; + bitMaskOld[j] = (aDelta.data[i].old[j] == null || typeof (aDelta.data[i].old[j]) == 'undefined') ? "0" : "1"; + }; + + + this.writeInteger(indexOf(RemObjects.DataAbstract.Enum.ChangeTypeNames, aDelta.data[i].changetype)); + this.writeInteger(aDelta.data[i].recid); + this.writeInteger(RemObjects.DataAbstract.Enum.ChangeStatus.csPending); + this.writeAnsiStringWithLength(""); + + // this.fStream += this.fParser.encodeInt(parseInt(bitMaskOld.reverse().join(""), 2), bitMaskSize * 8, false); + // bitMaskOld.reverse(); + for (var b = 0; b < bitMaskSize; b++) { + this.fStream += this.fParser.encodeInt(parseInt(bitMaskOld.slice(b * 8, (b + 1) * 8).reverse().join(""), 2), 8, false); + }; + + for (var j = 0; j < aDelta.loggedfields.length; j++) { + if (bitMaskOld[j] == "1") { + this.write(aDelta.loggedfields[j].type, aDelta.data[i].old[j]); + }; + }; + + // this.fStream += this.fParser.encodeInt(parseInt(bitMaskNew.reverse().join(""), 2), bitMaskSize * 8, false); + // bitMaskNew.reverse(); + for (var b = 0; b < bitMaskSize; b++) { + this.fStream += this.fParser.encodeInt(parseInt(bitMaskNew.slice(b * 8, (b + 1) * 8).reverse().join(""), 2), 8, false); + }; + + for (var j = 0; j < aDelta.loggedfields.length; j++) { + if (bitMaskNew[j] == "1") { + this.write(aDelta.loggedfields[j].type, aDelta.data[i]["new"][j]); + }; + }; + }; + }; + + this.fStreamInfoPos = this.fStream.length; //will be used in finalizeWrite + + this.writeInteger(aDeltas.deltas.length); //delta count + + for (var i = 0; i < aDeltas.deltas.length; i++) { + this.writeInteger(1); //etDelta + this.writeAnsiStringWithLength(RemObjects.UTIL.strToByteArray(aDeltas.deltas[i].name)); + this.writeInteger(offsets[i] + 12); //first delta position + }; + +}; + +RemObjects.DataAbstract.Bin2DataStreamer.prototype.readDelta = function readDelta() { + + var savedPos = this.fStreamPos; + this.fStreamPos = this.fStreamInfoPos; + var deltaCount = this.readInteger(); + var result = new RemObjects.DataAbstract.Deltas(); + + for (var d = 0; d < deltaCount; d++) { + var delta = new RemObjects.DataAbstract.Delta(); + + var deltaType = this.readInteger(); + delta.name = RemObjects.UTIL.byteArrayToStr(this.readAnsiStringWithLength()); + var deltaPos = this.readInteger(); + + result.deltas.push(delta); + + }; + + this.fStreamPos = savedPos; + + for (var d = 0; d < deltaCount; d++) { + + delta = result.deltas[d]; + + var changesCount = this.readInteger(); + if (changesCount != 0) { + var fieldsCount = this.readInteger(); + + for (var i = 0; i < fieldsCount; i++) { + delta.loggedfields[i] = {}; + delta.loggedfields[i].name = RemObjects.UTIL.byteArrayToStr(this.readAnsiStringWithLength()); + delta.loggedfields[i].type = RemObjects.DataAbstract.DADataType[this.readByte()]; + }; + + var keyFieldsCount = this.readInteger(); + for (var i = 0; i < keyFieldsCount; i++) { + delta.keyfields[i] = RemObjects.UTIL.byteArrayToStr(this.readAnsiStringWithLength()); + }; + + + if (changesCount != 0) { + + this.readByte(); //reduced? + changesCount = this.readInteger(); + + var bitMaskSize = Math.floor((fieldsCount + 7) / 8); + + // var bitMaskOld; + // var bitMaskNew; + + for (var i = 0; i < changesCount; i++) { //read changes + + var change = new RemObjects.DataAbstract.Change(); + change.changetype = RemObjects.DataAbstract.Enum.ChangeTypeNames[this.readInteger()]; + change.recid = this.readInteger(); + change.status = RemObjects.DataAbstract.Enum.ChangeStatusNames[this.readInteger()]; + change.message = RemObjects.UTIL.byteArrayToStr(this.readAnsiStringWithLength()); + + // bitMaskOld = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, bitMaskSize), bitMaskSize * 8); + // this.fStreamPos += bitMaskSize; + // bitMaskOld = bitMaskOld.toString(2).split("").reverse(); + + var bitMaskOld = ""; + for (var b = 0; b < bitMaskSize; b++) { + bitMaskOld += RemObjects.UTIL.zeroPad(this.fParser.decodeInt(this.fStream.substr(this.fStreamPos + bitMaskSize - 1 - b, 1), 8, false).toString(2), 8); + }; + var bitMaskOld = bitMaskOld.split("").reverse(); + this.fStreamPos += bitMaskSize; + + for (var j = 0; j < fieldsCount; j++) { + change.old[j] = (bitMaskOld[j] == "1") ? this.read(delta.loggedfields[j].type) : null; + }; + + // bitMaskNew = this.fParser.decodeInt(this.fStream.substr(this.fStreamPos, bitMaskSize), bitMaskSize * 8); + // this.fStreamPos += bitMaskSize; + // bitMaskNew = bitMaskNew.toString(2).split("").reverse(); + + var bitMaskNew = ""; + for (var b = 0; b < bitMaskSize; b++) { + bitMaskNew += RemObjects.UTIL.zeroPad(this.fParser.decodeInt(this.fStream.substr(this.fStreamPos + bitMaskSize - 1 - b, 1), 8, false).toString(2), 8); + }; + var bitMaskNew = bitMaskNew.split("").reverse(); + this.fStreamPos += bitMaskSize; + + for (var j = 0; j < fieldsCount; j++) { + change["new"][j] = (bitMaskNew[j] == "1") ? this.read(delta.loggedfields[j].type) : null; + }; + + delta.data.push(change); + }; + + }; + }; + } + return result; +}; + +RemObjects.DataAbstract.DynamicWhere.prototype.toXML = function toXML() { + if (!this.fExpression) throw new Error("Dynamic Where: fExpression is null"); + return '' + + this.fExpression.toXML() + ''; +}; + +RemObjects.DataAbstract.ConstantExpression.prototype.toXML = function toXML() { + return '' + this.fValue + ''; +}; + +RemObjects.DataAbstract.NullExpression.prototype.toXML = function toXML() { + return ''; +}; + +RemObjects.DataAbstract.FieldExpression.prototype.toXML = function toXML() { + return '' + this.fName + ''; +}; + +RemObjects.DataAbstract.MacroExpression.prototype.toXML = function toXML() { + return '' + this.fName + ''; +}; + +RemObjects.DataAbstract.ListExpression.prototype.toXML = function toXML() { + var result = ""; + for (var i = 0; i < this.fItems.length; i++) { + result += this.fItems[i].toXML(); + }; + result += ""; + return result; +}; + + +RemObjects.DataAbstract.UnaryExpression.prototype.toXML = function toXML() { + if (!this.fNode) throw new Error("UnaryExpression: fNode is null"); + return '' + + this.fNode.toXML() + ''; +}; + +RemObjects.DataAbstract.BinaryExpression.prototype.toXML = function toXML() { + if (!(this.fNode1 || this.fNode2)) throw new Error("BinaryExpression: fNode1 or fNode2 is null"); + return '' + + this.fNode1.toXML() + this.fNode2.toXML() + ''; +}; + +RemObjects.DataAbstract.BetweenExpression.prototype.toXML = function toXML() { + if (!(this.fNode1 || this.fNode2 || this.fNode3)) throw new Error("BetweenExpression: fNode1 or fNode2 or fNode3 is null"); + return '' + + this.fNode1.toXML() + this.fNode2.toXML() + this.fNode3.toXML() + ''; +}; + + +RemObjects.DataAbstract.ParameterExpression.prototype.toXML = function toXML() { + return '' + + this.fName + ''; +}; + +RemObjects.DataAbstract.Views.HtmlTableView = function HtmlTAbleView(aTable, aHtmlTableId) { + var htmlTable = document.getElementById(aHtmlTableId); + var tRow = ""; + for (var i = 0; i < aTable.fields.length; i++) { + tRow += "" + aTable.fields[i].name + ""; + }; + tRow = '' + tRow + ""; + + var r = aTable.first(); + while (r) { + tRow += ''; + for (var i = 0; i < aTable.fields.length; i++) { + tRow += "" + (aTable.fields[i].type == "datBlob" ? "(Blob)" : r.__newValues[i]) + ""; + }; + tRow += ""; + r = aTable.next(); + }; + + htmlTable.innerHTML = "" + tRow + ""; +}; + +RemObjects.DataAbstract.Views.VerticalHtmlTableView = function VerticalHtmlTableView(aTable, aHtmlTableId) { + var htmlTable = document.getElementById(aHtmlTableId); + var tRow = ""; + var r = aTable.currentRow(); + for (var i = 0; i < aTable.fields.length; i++) { + tRow += ""; + tRow += '' + aTable.fields[i].name + ""; + tRow += "" + (aTable.fields[i].type == "datBlob" ? "(Blob)" : r.__newValues[i]) + ""; + tRow += ""; + }; + htmlTable.innerHTML = "" + tRow + ""; +}; diff --git a/demo/dataabstract/DataAbstract4_intf.js b/demo/dataabstract/DataAbstract4_intf.js new file mode 100644 index 0000000..e3b1bf4 --- /dev/null +++ b/demo/dataabstract/DataAbstract4_intf.js @@ -0,0 +1,665 @@ +//----------------------------------------------------------------------------// +// This unit was automatically generated by the RemObjects SDK after reading // +// the RODL file associated with this project . // +// // +// Do not modify this unit manually, or your changes will be lost when this // +// unit is regenerated the next time you compile the project. // +//----------------------------------------------------------------------------// + + +/* This codegen depends on RemObjectsSDK.js +* Usage: +* var Channel = new RemObjects.SDK.HTTPClientChannel("http://localhost:8099/JSON"); +* var Message = new RemObjects.SDK.JSONMessage(); +* var Service = new NewService(Channel, Message); +* Service.Sum(1, 2, +* function(result) { +* alert(result); +* }, +* function(msg) {alert(msg.getErrorMessage())} +* ); +* +*/ + +__namespace = this; +if ("RemObjects.DataAbstract.Server" != "") { + var parts = "RemObjects.DataAbstract.Server".split("."); + var current = this; + for (var i = 0; i < parts.length; i++) { + current[parts[i]] = current[parts[i]] || {}; + current = current[parts[i]]; + }; + __namespace = current; +}; + +// Enum: ColumnSortDirection +__namespace.ColumnSortDirection = function ColumnSortDirection() { + this.value = null; +}; +__namespace.ColumnSortDirection.prototype = new RemObjects.SDK.ROEnumType(); +__namespace.ColumnSortDirection.prototype.enumValues = [ + "Ascending", + "Descending" + ]; +__namespace.ColumnSortDirection.prototype.constructor = __namespace.ColumnSortDirection; +RemObjects.SDK.RTTI["ColumnSortDirection"] = __namespace.ColumnSortDirection; + +// Enum: ScriptExceptionType +__namespace.ScriptExceptionType = function ScriptExceptionType() { + this.value = null; +}; +__namespace.ScriptExceptionType.prototype = new RemObjects.SDK.ROEnumType(); +__namespace.ScriptExceptionType.prototype.enumValues = [ + "ParserError", + "RuntimeError", + "Fail", + "UnexpectedException" + ]; +__namespace.ScriptExceptionType.prototype.constructor = __namespace.ScriptExceptionType; +RemObjects.SDK.RTTI["ScriptExceptionType"] = __namespace.ScriptExceptionType; + + +// Struct: DataParameter +__namespace.DataParameter = function DataParameter() { + this.Name = {dataType : "Utf8String", value : null}; + this.Value = {dataType : "Variant", value : null}; +}; +__namespace.DataParameter.prototype = new RemObjects.SDK.ROStructType(); +__namespace.DataParameter.prototype.constructor = __namespace.DataParameter; +RemObjects.SDK.RTTI["DataParameter"] = __namespace.DataParameter; + +// Struct: TableRequestInfo +__namespace.TableRequestInfo = function TableRequestInfo() { + this.IncludeSchema = {dataType : "Boolean", value : null}; + this.MaxRecords = {dataType : "Integer", value : null}; + this.Parameters = {dataType : "DataParameterArray", value : null}; + this.UserFilter = {dataType : "Utf8String", value : null}; +}; +__namespace.TableRequestInfo.prototype = new RemObjects.SDK.ROStructType(); +__namespace.TableRequestInfo.prototype.constructor = __namespace.TableRequestInfo; +RemObjects.SDK.RTTI["TableRequestInfo"] = __namespace.TableRequestInfo; + +// Struct: TableRequestInfoV6 +__namespace.TableRequestInfoV6 = function TableRequestInfoV6() { + this.IncludeSchema = {dataType : "Boolean", value : null}; + this.MaxRecords = {dataType : "Integer", value : null}; + this.Parameters = {dataType : "DataParameterArray", value : null}; + this.Sql = {dataType : "WideString", value : null}; + this.UserFilter = {dataType : "Utf8String", value : null}; +}; +__namespace.TableRequestInfoV6.prototype = new RemObjects.SDK.ROStructType(); +__namespace.TableRequestInfoV6.prototype.constructor = __namespace.TableRequestInfoV6; +RemObjects.SDK.RTTI["TableRequestInfoV6"] = __namespace.TableRequestInfoV6; + +// Struct: TableRequestInfoV5 +__namespace.TableRequestInfoV5 = function TableRequestInfoV5() { + this.DynamicSelectFieldNames = {dataType : "StringArray", value : null}; + this.IncludeSchema = {dataType : "Boolean", value : null}; + this.MaxRecords = {dataType : "Integer", value : null}; + this.Parameters = {dataType : "DataParameterArray", value : null}; + this.Sorting = {dataType : "ColumnSorting", value : null}; + this.UserFilter = {dataType : "Utf8String", value : null}; + this.WhereClause = {dataType : "Xml", value : null}; +}; +__namespace.TableRequestInfoV5.prototype = new RemObjects.SDK.ROStructType(); +__namespace.TableRequestInfoV5.prototype.constructor = __namespace.TableRequestInfoV5; +RemObjects.SDK.RTTI["TableRequestInfoV5"] = __namespace.TableRequestInfoV5; + +// Struct: UserInfo +__namespace.UserInfo = function UserInfo() { + this.Attributes = {dataType : "VariantArray", value : null}; + this.Privileges = {dataType : "StringArray", value : null}; + this.SessionID = {dataType : "Utf8String", value : null}; + this.UserData = {dataType : "Binary", value : null}; + this.UserID = {dataType : "Utf8String", value : null}; +}; +__namespace.UserInfo.prototype = new RemObjects.SDK.ROStructType(); +__namespace.UserInfo.prototype.constructor = __namespace.UserInfo; +RemObjects.SDK.RTTI["UserInfo"] = __namespace.UserInfo; + +// Struct: ColumnSorting +__namespace.ColumnSorting = function ColumnSorting() { + this.FieldName = {dataType : "Utf8String", value : null}; + this.SortDirection = {dataType : "ColumnSortDirection", value : null}; +}; +__namespace.ColumnSorting.prototype = new RemObjects.SDK.ROStructType(); +__namespace.ColumnSorting.prototype.constructor = __namespace.ColumnSorting; +RemObjects.SDK.RTTI["ColumnSorting"] = __namespace.ColumnSorting; + + +// Array: ColumnSortingArray +__namespace.ColumnSortingArray = function ColumnSortingArray() { + RemObjects.SDK.ROArrayType.call(this); + this.elementType = "ColumnSorting"; +}; +__namespace.ColumnSortingArray.prototype = new RemObjects.SDK.ROArrayType(); +__namespace.ColumnSortingArray.prototype.constructor = __namespace.ColumnSortingArray; +RemObjects.SDK.RTTI["ColumnSortingArray"] = __namespace.ColumnSortingArray; + +// Array: DataParameterArray +__namespace.DataParameterArray = function DataParameterArray() { + RemObjects.SDK.ROArrayType.call(this); + this.elementType = "DataParameter"; +}; +__namespace.DataParameterArray.prototype = new RemObjects.SDK.ROArrayType(); +__namespace.DataParameterArray.prototype.constructor = __namespace.DataParameterArray; +RemObjects.SDK.RTTI["DataParameterArray"] = __namespace.DataParameterArray; + +// Array: StringArray +__namespace.StringArray = function StringArray() { + RemObjects.SDK.ROArrayType.call(this); + this.elementType = "Utf8String"; +}; +__namespace.StringArray.prototype = new RemObjects.SDK.ROArrayType(); +__namespace.StringArray.prototype.constructor = __namespace.StringArray; +RemObjects.SDK.RTTI["StringArray"] = __namespace.StringArray; + +// Array: TableRequestInfoArray +__namespace.TableRequestInfoArray = function TableRequestInfoArray() { + RemObjects.SDK.ROArrayType.call(this); + this.elementType = "TableRequestInfo"; +}; +__namespace.TableRequestInfoArray.prototype = new RemObjects.SDK.ROArrayType(); +__namespace.TableRequestInfoArray.prototype.constructor = __namespace.TableRequestInfoArray; +RemObjects.SDK.RTTI["TableRequestInfoArray"] = __namespace.TableRequestInfoArray; + +// Array: VariantArray +__namespace.VariantArray = function VariantArray() { + RemObjects.SDK.ROArrayType.call(this); + this.elementType = "Variant"; +}; +__namespace.VariantArray.prototype = new RemObjects.SDK.ROArrayType(); +__namespace.VariantArray.prototype.constructor = __namespace.VariantArray; +RemObjects.SDK.RTTI["VariantArray"] = __namespace.VariantArray; + + +// Exception: ScriptException +__namespace.ScriptException = function ScriptException(e) { + RemObjects.SDK.ROException.call(this, e); + this.fields.Line = {dataType : "Integer", value : null}; + this.fields.Column = {dataType : "Integer", value : null}; + this.fields.Event = {dataType : "Utf8String", value : null}; + this.fields.InnerStackTrace = {dataType : "Utf8String", value : null}; + this.fields.Type = {dataType : "ScriptExceptionType", value : null}; +}; +__namespace.ScriptException.prototype = new RemObjects.SDK.ROException(); +RemObjects.SDK.RTTI["ScriptException"] = __namespace.ScriptException; + + + +// Service: DataAbstractService +__namespace.DataAbstractService = function DataAbstractService(__channel, __message, __service_name) { + RemObjects.SDK.ROService.call(this, __channel, __message, __service_name); + this.fServiceName = this.fServiceName || __service_name || "DataAbstractService"; +}; + + +__namespace.DataAbstractService.prototype.GetSchema = function( + aFilter, + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "GetSchema"); + msg.write("aFilter", "Utf8String", aFilter); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + var __result = __message.read("Result", "Utf8String"); + __success( + __result + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + +__namespace.DataAbstractService.prototype.GetData = function( + aTableNameArray, + aTableRequestInfoArray, + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "GetData"); + msg.write("aTableNameArray", "StringArray", aTableNameArray); + msg.write("aTableRequestInfoArray", "TableRequestInfoArray", aTableRequestInfoArray); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + var __result = __message.read("Result", "Binary"); + __success( + __result + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + +__namespace.DataAbstractService.prototype.UpdateData = function( + aDelta, + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "UpdateData"); + msg.write("aDelta", "Binary", aDelta); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + var __result = __message.read("Result", "Binary"); + __success( + __result + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + +__namespace.DataAbstractService.prototype.ExecuteCommand = function( + aCommandName, + aParameterArray, + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "ExecuteCommand"); + msg.write("aCommandName", "Utf8String", aCommandName); + msg.write("aParameterArray", "DataParameterArray", aParameterArray); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + var __result = __message.read("Result", "Integer"); + __success( + __result + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + +__namespace.DataAbstractService.prototype.ExecuteCommandEx = function( + aCommandName, + aInputParameters, + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "ExecuteCommandEx"); + msg.write("aCommandName", "Utf8String", aCommandName); + msg.write("aInputParameters", "DataParameterArray", aInputParameters); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + var __result = __message.read("Result", "Integer"); + var __aOutputParameters = __message.read("aOutputParameters", "DataParameterArray"); + __success( + __result + , + __aOutputParameters + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + +__namespace.DataAbstractService.prototype.GetTableSchema = function( + aTableNameArray, + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "GetTableSchema"); + msg.write("aTableNameArray", "StringArray", aTableNameArray); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + var __result = __message.read("Result", "Utf8String"); + __success( + __result + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + +__namespace.DataAbstractService.prototype.GetCommandSchema = function( + aCommandNameArray, + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "GetCommandSchema"); + msg.write("aCommandNameArray", "StringArray", aCommandNameArray); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + var __result = __message.read("Result", "Utf8String"); + __success( + __result + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + +__namespace.DataAbstractService.prototype.SQLGetData = function( + aSQLText, + aIncludeSchema, + aMaxRecords, + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "SQLGetData"); + msg.write("aSQLText", "Utf8String", aSQLText); + msg.write("aIncludeSchema", "Boolean", aIncludeSchema); + msg.write("aMaxRecords", "Integer", aMaxRecords); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + var __result = __message.read("Result", "Binary"); + __success( + __result + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + +__namespace.DataAbstractService.prototype.SQLGetDataEx = function( + aSQLText, + aIncludeSchema, + aMaxRecords, + aDynamicWhereXML, + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "SQLGetDataEx"); + msg.write("aSQLText", "Utf8String", aSQLText); + msg.write("aIncludeSchema", "Boolean", aIncludeSchema); + msg.write("aMaxRecords", "Integer", aMaxRecords); + msg.write("aDynamicWhereXML", "WideString", aDynamicWhereXML); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + var __result = __message.read("Result", "Binary"); + __success( + __result + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + +__namespace.DataAbstractService.prototype.SQLExecuteCommand = function( + aSQLText, + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "SQLExecuteCommand"); + msg.write("aSQLText", "Utf8String", aSQLText); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + var __result = __message.read("Result", "Integer"); + __success( + __result + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + +__namespace.DataAbstractService.prototype.SQLExecuteCommandEx = function( + aSQLText, + aDynamicWhereXML, + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "SQLExecuteCommandEx"); + msg.write("aSQLText", "Utf8String", aSQLText); + msg.write("aDynamicWhereXML", "WideString", aDynamicWhereXML); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + var __result = __message.read("Result", "Integer"); + __success( + __result + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + +__namespace.DataAbstractService.prototype.GetDatasetScripts = function( + DatasetNames, + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "GetDatasetScripts"); + msg.write("DatasetNames", "Utf8String", DatasetNames); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + var __result = __message.read("Result", "Utf8String"); + __success( + __result + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + +__namespace.DataAbstractService.prototype.RegisterForDataChangeNotification = function( + aTableName, + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "RegisterForDataChangeNotification"); + msg.write("aTableName", "Utf8String", aTableName); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + __success( + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + +__namespace.DataAbstractService.prototype.UnregisterForDataChangeNotification = function( + aTableName, + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "UnregisterForDataChangeNotification"); + msg.write("aTableName", "Utf8String", aTableName); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + __success( + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + + +// Service: BaseLoginService +__namespace.BaseLoginService = function BaseLoginService(__channel, __message, __service_name) { + RemObjects.SDK.ROService.call(this, __channel, __message, __service_name); + this.fServiceName = this.fServiceName || __service_name || "BaseLoginService"; +}; + + +__namespace.BaseLoginService.prototype.LoginEx = function( + aLoginString, + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "LoginEx"); + msg.write("aLoginString", "Utf8String", aLoginString); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + var __result = __message.read("Result", "Boolean"); + __success( + __result + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + +__namespace.BaseLoginService.prototype.Logout = function( + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "Logout"); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + __success( + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + + +// Service: MultiDbLoginService +__namespace.MultiDbLoginService = function MultiDbLoginService(__channel, __message, __service_name) { + RemObjects.SDK.ROService.call(this, __channel, __message, __service_name); + this.fServiceName = this.fServiceName || __service_name || "MultiDbLoginService"; +}; + +__namespace.MultiDbLoginService.prototype = new __namespace.BaseLoginService(); + +__namespace.MultiDbLoginService.prototype.Login = function( + aUserID, + aPassword, + aConnectionName, + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "Login"); + msg.write("aUserID", "Utf8String", aUserID); + msg.write("aPassword", "Utf8String", aPassword); + msg.write("aConnectionName", "Utf8String", aConnectionName); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + var __result = __message.read("Result", "Boolean"); + var __aUserInfo = __message.read("aUserInfo", "UserInfo"); + __success( + __result + , + __aUserInfo + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + + +// Service: MultiDbLoginServiceV5 +__namespace.MultiDbLoginServiceV5 = function MultiDbLoginServiceV5(__channel, __message, __service_name) { + RemObjects.SDK.ROService.call(this, __channel, __message, __service_name); + this.fServiceName = this.fServiceName || __service_name || "MultiDbLoginServiceV5"; +}; + +__namespace.MultiDbLoginServiceV5.prototype = new __namespace.MultiDbLoginService(); + +__namespace.MultiDbLoginServiceV5.prototype.GetConnectionNames = function( + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "GetConnectionNames"); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + var __result = __message.read("Result", "StringArray"); + __success( + __result + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + +__namespace.MultiDbLoginServiceV5.prototype.GetDefaultConnectionName = function( + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "GetDefaultConnectionName"); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + var __result = __message.read("Result", "Utf8String"); + __success( + __result + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + + +// Service: SimpleLoginService +__namespace.SimpleLoginService = function SimpleLoginService(__channel, __message, __service_name) { + RemObjects.SDK.ROService.call(this, __channel, __message, __service_name); + this.fServiceName = this.fServiceName || __service_name || "SimpleLoginService"; +}; + +__namespace.SimpleLoginService.prototype = new __namespace.BaseLoginService(); + +__namespace.SimpleLoginService.prototype.Login = function( + aUserID, + aPassword, + __success, __error) { + try { + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "Login"); + msg.write("aUserID", "Utf8String", aUserID); + msg.write("aPassword", "Utf8String", aPassword); + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + var __result = __message.read("Result", "Boolean"); + var __aUserInfo = __message.read("aUserInfo", "UserInfo"); + __success( + __result + , + __aUserInfo + ); + }, __error); + + } catch (e) { + __error(msg, e); + }; +}; + + + +// Event sink: DataChangeNotification +__namespace.DataChangeNotification = function DataChangeNotification() { + this.OnDataTableChanged = { + aTableName : {dataType : "Utf8String", value : null}, + aDelta : {dataType : "Binary", value : null} + }; +}; +__namespace.DataChangeNotification.prototype = new RemObjects.SDK.ROEventSink(); +__namespace.DataChangeNotification.prototype.constructor = __namespace.DataChangeNotification; +RemObjects.SDK.RTTI["DataChangeNotification"] = __namespace.DataChangeNotification; + diff --git a/demo/dataabstract/RemObjectsSDK.js b/demo/dataabstract/RemObjectsSDK.js new file mode 100644 index 0000000..1b563d2 --- /dev/null +++ b/demo/dataabstract/RemObjectsSDK.js @@ -0,0 +1,2012 @@ +//RemObjects SDK classes +//interface + + +var RemObjects = {}; + + + +RemObjects.SDK = { + RTTI : { + }, + + Enum : {}, + + ROComplexType : function ROComplexType() { + }, + + ROEnumType : function ROEnumType() { + }, + + ROStructType : function ROStructType() { + }, + + ROArrayType : function ROArrayType() { + this.elementType = ""; + this.items = []; + }, + + ROException : function ROException(e) { + if (e) { + this.name = e.name; + this.message = e.message; + }; + this.fields = new RemObjects.SDK.ROStructType(); + }, + + ROEventSink : function ROEventSink() { + }, + + ClientChannel : function ClientChannel(aUrl) { + this.url = aUrl; + //post + }, + + HTTPClientChannel : function HTTPClientChannel(aUrl) { + RemObjects.SDK.ClientChannel.call(this, aUrl); + }, + + + Message : function Message() { + this.fClientID = RemObjects.UTIL.NewGuid(); + this.fRequestObject = {}; + this.fResponseObject = {}; + //clone + //getClientID + //setClientID + }, + + JSONMessage : function JSONMessage() { + RemObjects.SDK.Message.call(this); + //initialize + //finalize + //write + //read + //requestStream + //setResponseStream + + }, + + BinMessage : function BinMessage() { + RemObjects.SDK.Message.call(this); + //initialize + //finalize + //write + //read + //requestStream + //setResponseStream + }, + + BinHeader : function BinHeader() { + + + this.fHeader = [0x52, 0x4f, 0x31, 0x30, 0x37]; //should contain 0x1c bytes + for (var i = 5; i<0x1c; this.fHeader[i++] = 0); + //readFrom + //asStream + //isValidHeader + //getCompressed + //setCompressed + //getMessageType + //setMessageType + //setClientID + + // Header BINARY LAYOUT: 0x1C bytes + // + // Keep in sync with + // - Delphi - uROBINMessage.pas + // - C# - BinMessage.cs + // + // 52 4f 31 30 = "RO10" basic RO signature for RO 1.0 + // XX YY ZZ -- = XX: subversion (currenly "7") + // YY: option flags: 01 = compressed + // ZZ: message type as defined in uROClientIntf + // --: reserved for future use + // -- -- UU UU = UU: user data (word) + // CC CC CC CC 0x10 bytes ClientID (guid) + // CC CC CC CC + // CC CC CC CC + // CC CC CC CC + + + }, + + + RemoteService : function RemoteService(aChannel, aMessage, aServiceName) { + this.fChannel = aChannel; + this.fMessage = aMessage; + this.fServiceName = aServiceName; + }, + + + ROService : function ROService(aChannel, aMessage, aServiceName) { + if (RemObjects.UTIL.checkArgumentTypes(arguments, [RemObjects.SDK.ClientChannel, RemObjects.SDK.Message, "string"]) || + RemObjects.UTIL.checkArgumentTypes(arguments, [RemObjects.SDK.ClientChannel, RemObjects.SDK.Message, "undefined"])) { + this.fChannel = aChannel; + this.fMessage = aMessage; + this.fServiceName = aServiceName; + } else if (RemObjects.UTIL.checkArgumentTypes(arguments, [RemObjects.SDK.RemoteService, "undefined", "undefined"])) { + this.fChannel = aChannel.fChannel; + this.fMessage = aChannel.fMessage; + this.fServiceName = aChannel.fServiceName; + } else if (RemObjects.UTIL.checkArgumentTypes(arguments, ["string"])) { //URL + var m = /https?:\/\/([-\w\.]+)+(:\d+)?\/([\w/_\.]*)/i.exec(aChannel); + var path; + if (m && m.length == 4 ) { + path = m[3]; + } else { + m = /https?:\/\/\[((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})\](:\d+)\/([\w/_\.]*)$/i.exec(aChannel); + if (!m) { + throw new Error("ROService constructor: incorrect URL"); + } else { + path = m[14]; + }; + }; + if (path.toLowerCase() == "json") { + this.fMessage = new RemObjects.SDK.JSONMessage(); + } else { + this.fMessage = new RemObjects.SDK.BinMessage(); + }; + this.fChannel = new RemObjects.SDK.HTTPClientChannel(aChannel); + if (typeof(aMessage) == "string") this.fServiceName = aMessage; + } else if (!RemObjects.UTIL.checkArgumentTypes(arguments, ["undefined", "undefined", "undefined"])) { + throw new Error("ROService constructor: Incorrect arguments"); + }; + //getChannel + //getMessage + //getServiceName + }, + + EventReceiver : function EventReceiver(aChannel, aMessage, aServiceName, aTimeout) { + this.fChannel = aChannel; + this.fMessage = aMessage; + this.fServiceName = aServiceName; + this.fTimeout = aTimeout; + this.fActive = false; + this.fHandlers = {}; + this.fInterval = null; + //addHandler + //intPollServer + //setActive + //getActive + //getTimeout + //setTimeout + } + +}; + +RemObjects.UTIL = { + + testBrowser : function testBrowser() { + var result = ""; + if (typeof(JSON) == 'undefined') + result += "Browser doesn't support JSON\n"; + + var AJAX; + if (typeof(XMLHttpRequest) == 'undefined') { + try { + AJAX = new XMLHttpRequest(); + } catch (e) { + try { + AJAX = new ActiveXObject("Msxml2.XMLHTTP"); + } catch (e) { + try { + AJAX = new ActiveXObject("Microsoft.XMLHTTP"); + } catch (e) { + result += "Browser doesn't support XMLHttpRequest object\n"; + }; + }; + }; + }; + + result += RemObjects.UTIL.testBrowserBinary(); + return result; + }, + + testBrowserBinary : function testBrowserBinary() { + var result = ""; + if (!(((typeof(XMLHttpRequest) != 'undefined') && (typeof(XMLHttpRequest.prototype.sendAsBinary) != 'undefined')) || (typeof(Uint8Array) != 'undefined') )) + result += "Browser doesn't support sending binary data\n"; + return result; + }, + + browserHasBinarySupport : function browserHasBinarySupport() { + return RemObjects.UTIL.testBrowserBinary() == ""; + }, + + showMessage : function(msg) { + //for non-browser environments: + //replace alert() call with something appropriate + alert(msg); + }, + + showError : function showError(msg, e) { + var result = ""; + if (e) { + result += e.name + ": " + e.message; + } else { + result += msg.getErrorMessage() + "\n"; + }; + result += "\nCall stack:\n"; + var fn = showError; + // if (!(fn.caller)) //possibly IE +// fn = arguments.callee; +// while((fn = fn.caller) !== null) { +// var fnName = fn.toString().match(/^function\s*(\w+)\(/); +// fnName = (fnName) ? fnName[1] : 'anonymous function'; +// result += fnName; +// result += "\n"; + // } + RemObjects.UTIL.showMessage(result); + }, + + toJSON : function toJSON(aValue) { + if(typeof(JSON) != 'undefined') { + var jsonString = JSON.stringify(aValue); + jsonString = jsonString.replace(/[\u007F-\uFFFF]/g, function(chr) { + return "\\u" + ("0000" + chr.charCodeAt(0).toString(16)).substr(-4) + }); + return jsonString; + } else { + throw new Error("Your browser doesn't support JSON.stringify"); + }; + }, + + parseJSON : function parseJSON(aValue) { + if(typeof(JSON) != 'undefined') { + return JSON.parse(aValue); + } else { + throw new Error("Your browser doesn't support JSON.parse"); + }; + }, + + NewGuid : function NewGuid() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, + function(c) { + var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); + return v.toString(16); }) + }, + + GuidToArray : function GuidToArray(aGuid) { + var result = []; + aGuid = aGuid.replace(/-/g, ""); + for (var i = 3; i >= 0; result.push(parseInt(aGuid.substr(i-- * 2, 2), 16))); + for (var i = 5; i >= 4; result.push(parseInt(aGuid.substr(i-- * 2, 2), 16))); + for (var i = 7; i >= 6; result.push(parseInt(aGuid.substr(i-- * 2, 2), 16))); + for (var i = 8; i < 16; result.push(parseInt(aGuid.substr(i++ * 2, 2), 16))); +// for (var i = 0; i < 16; result.push(parseInt(aGuid.substr(i++ * 2, 2), 16))); + return result; + }, + + guidToByteArray : function guidToByteArray(aGuid) { + function readPart(str, start, end) { + var result = ""; + for (var i = start; i <= end; result += String.fromCharCode(parseInt(aGuid.substr(i++ * 2 + 1, 2), 16))); + return result; + }; + + function readPartReversed(str, start, end) { + var result = ""; + for (var i = end; i >= start; result += String.fromCharCode(parseInt(aGuid.substr(i-- * 2 + 1, 2), 16))); + return result; + }; + aGuid = aGuid.replace(/-/g, ""); + return readPartReversed(aGuid, 0, 3) + readPartReversed(aGuid, 4, 5) + + readPartReversed(aGuid, 6, 7) + readPart(aGuid, 8, 9) + readPart(aGuid, 10, 15); + }, + + zeroPad : function zeroPad(num, count) { + var numZeropad = num + ''; + while (numZeropad.length < count) { + numZeropad = "0" + numZeropad; + } + return numZeropad; + }, + + byteArrayToGuid : function byteArrayToGuid(byteArray) { + function readPartReversed(str, start, end) { + var result = ""; + for (var i = end; i >= start; i--) { + result += RemObjects.UTIL.zeroPad((str.charCodeAt(i) & 0xFF).toString(16).toUpperCase(), 2); + }; + return result; + }; + function readPart(str, start, end) { + var result = ""; + for (var i = start; i <= end; i++) { + result += RemObjects.UTIL.zeroPad((str.charCodeAt(i) & 0xFF).toString(16).toUpperCase(), 2); + }; + return result; + }; + return "{" + readPartReversed(byteArray, 0, 3) + "-" + + readPartReversed(byteArray, 4, 5) + "-" + + readPartReversed(byteArray, 6, 7) + "-" + + readPart(byteArray, 8, 9) + "-" + + readPart(byteArray, 10, 15) + + "}"; + }, + + + strToByteArray : function strToByteArray(str) { + var byteArray = []; + for (var i = 0; i < str.length; i++) + if (str.charCodeAt(i) <= 0x7F) + byteArray.push(str.substr(i, 1)); + else { + var h = encodeURIComponent(str.charAt(i)).substr(1).split('%'); + for (var j = 0; j < h.length; j++) + byteArray.push(String.fromCharCode(parseInt(h[j], 16))); + }; + return byteArray.join(""); + }, + + + + byteArrayToStr : function byteArrayToStr(byteArray) { + var str = ''; + for (var i = 0; i < byteArray.length; i++) + str += byteArray.charCodeAt(i) <= 0x7F ? + byteArray.charCodeAt(i) === 0x25 ? "%25" : // % + byteArray.substr(i, 1) : + "%" + (byteArray.charCodeAt(i) & 0xFF).toString(16).toUpperCase(); + return decodeURIComponent(str); + }, + + byteArrayToUtf16 : function byteArrayToUtf16(byteArray) { + var str = ''; + for (var i = 0; i < byteArray.length / 2; i++) + str += String.fromCharCode((byteArray.charCodeAt(i * 2) & 0xFF) + ((byteArray.charCodeAt(i * 2 + 1) & 0xFF) << 8)); + return str; + }, + + utf16ToByteArray : function utf16ToByteArray(str) { + var byteArray = ""; + for (var i = 0; i < str.length; i++) { + byteArray += String.fromCharCode(str.charCodeAt(i) & 0xFF); + byteArray += String.fromCharCode((str.charCodeAt(i) & 0xFF00) >> 8); + }; + return byteArray; + }, + + ISO8601toDateTime : function ISO8601toDateTime(str) { + var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" + + "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" + + "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?"; + var d = ("" + str).match(new RegExp(regexp)); + + if (!d) return null; + + var offset = 0; + var date = new Date(d[1], 0, 1); + + if (d[3]) { date.setMonth(d[3] - 1); } + if (d[5]) { date.setDate(d[5]); } + if (d[7]) { date.setHours(d[7]); } + if (d[8]) { date.setMinutes(d[8]); } + if (d[10]) { date.setSeconds(d[10]); } + if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); } + if (d[14]) { + offset = (Number(d[16]) * 60) + Number(d[17]); + offset *= ((d[15] == '-') ? 1 : -1); + offset -= date.getTimezoneOffset(); + var time = (Number(date) + (offset * 60 * 1000)); + date.setTime(Number(time)); + } + + return date; + }, + + dateTimeToSOAPString : function dateTimeToSOAPString(aValue) { + //'yyyy-mm-ddThh:nn:ss' + return aValue.getFullYear() + '-' + RemObjects.UTIL.zeroPad(aValue.getMonth() + 1, 2) + + '-' + RemObjects.UTIL.zeroPad(aValue.getDate(), 2) + + 'T' + RemObjects.UTIL.zeroPad(aValue.getHours(), 2) + + ':' + RemObjects.UTIL.zeroPad(aValue.getMinutes(), 2) + + ':' + RemObjects.UTIL.zeroPad(aValue.getSeconds(), 2); + }, + + decimalToString : function decimalToString(aDecimal) { //aDecimal - array [0..6] + var sign = (aDecimal[6] & 0x80000000) != 0; + var scale = (aDecimal[6] & 0xFF0000) >> 16; + var pos = 31; + var aDec = aDecimal.slice(); + var aResult = []; + var modres; + var d; + while ((aDec[0] != 0) || (aDec[1] != 0) || (aDec[2] != 0) + || (aDec[3] != 0) || (aDec[4] != 0) || (aDec[5] != 0) + || ((31 - pos) < scale)) { + modres = 0; + for (var i = 5; i >= 0; i--) { + d = (modres << 16) | aDec[i]; + modres = d % 10; + aDec[i] = Math.floor(d / 10); + }; + aResult[pos] = modres.toString(10); + pos--; + if ((31 - pos) == scale) { + aResult[pos] = "."; + pos--; + if ((aDec[0] == 0) && (aDec[1] == 0) && (aDec[2] == 0)) { + aResult[pos] = '0'; + pos--; + }; + }; + }; + if (pos == 31) + return "0"; + if (sign) { + aResult[pos] = '-'; + pos--; + }; + return aResult.join(""); + }, + + stringToDecimal : function stringToDecimal(aString) { + var mulres; + var d; + var aRes = [0, 0, 0, 0, 0, 0, 0]; + var pos = 0; + var scalepos = -1; + var c; + var n; + for (var i = 1; i <= aString.length; i++) { + mulres = 0; + c = aString.substr(i - 1, 1); + if (n = parseFloat(c)) { + mulres = n + } else if (c == "-") { + aRes[6] = 0x80000000; + continue; + } else if (c == ".") { + if (scalepos == -1) + scalepos = pos; + continue; + } else + continue; + + + for (var j = 0; j < 6; j++) { + d = aRes[j] * 10 + mulres; + mulres = d >> 16; + aRes[j] = d & 0xffff; + }; + pos++; + }; + if (scalepos != -1) { + pos = pos - scalepos; + aRes[6] = aRes[6] | (pos << 16); + }; + return aRes; + }, + + toBase64 : function toBase64(aValue) { + if (typeof(btoa) != 'undefined') { + return btoa(aValue); + } else { + throw(new Error("Base64 encoding is not supported by your browser.")); + //return $.base64Encode(aValue); + }; + }, + + fromBase64 : function fromBase64 (aValue) { + if (typeof(atob) != 'undefined') { + return atob(aValue.replace(/(\n|\r)+/g, "")); + } else { + throw(new Error("Base64 decoding is not supported by your browser.")); + // return $.base64Decode(aValue); + }; + + }, + + checkArgumentTypes : function checkArgumentTypes (args, types) { + for (var i = 0; i < types.length; i++) { + if (typeof(types[i]) == "string") { + if (typeof(args[i]) != types[i]) return false; + } else { + if (!(args[i] instanceof types[i])) return false; + }; + }; + return true; + } + +}; + + +RemObjects.SDK.Enum.MessageType = { + mtMessage : 0, + mtException : 1, + mtEvent : 2, + mtPoll : 0x80, + mtPollResponse : 0x81 +}; + + + +//RO.SDK implementation + +RemObjects.SDK.ROEventSink.prototype = new RemObjects.SDK.ROComplexType(); +RemObjects.SDK.ROEventSink.prototype.constructor = RemObjects.SDK.ROEventSink; +RemObjects.SDK.ROEventSink.prototype.readEvent = function readEvent(aMessage, aName) { + for (var prop in this[aName]) { + if ((typeof this[aName][prop]) != "function") { + this[aName][prop].value = aMessage.read(prop, this[aName][prop].dataType); + }; + }; +}; + +RemObjects.SDK.ROException.prototype = new Error(); + +RemObjects.SDK.ROEnumType.prototype = new RemObjects.SDK.ROComplexType(); +RemObjects.SDK.ROEnumType.prototype.constructor = RemObjects.SDK.ROEnumType; + + +RemObjects.SDK.ROEnumType.prototype.writeTo = function writeTo(aMessage) { + aMessage.write("", "Integer", this.enumValues.indexOf(this.value)); +}; + +RemObjects.SDK.ROEnumType.prototype.readFrom = function readFrom(aMessage) { + this.value = this.enumValues[aMessage.read("", "Integer")]; +}; + +RemObjects.SDK.ROEnumType.prototype.toObject = function toObject() { + return this.value; +}; + +RemObjects.SDK.ROEnumType.prototype.fromObject = function fromObject(aValue) { + this.value = aValue; //todo: add check +}; + + +RemObjects.SDK.ROStructType.prototype = new RemObjects.SDK.ROComplexType(); +RemObjects.SDK.ROStructType.prototype.constructor = RemObjects.SDK.ROStructType; + +RemObjects.SDK.ROStructType.prototype.writeTo = function writeTo(aMessage) { + for (var prop in this) { + if ((typeof this[prop]) != "function") { + aMessage.write(prop, this[prop].dataType, this[prop].value); + }; + }; +}; + +RemObjects.SDK.ROStructType.prototype.readFrom = function readFrom(aMessage) { + for (var prop in this) { + if ((typeof this[prop]) != "function") { + this[prop].value = aMessage.read(prop, this[prop].dataType); + }; + }; +}; + + +RemObjects.SDK.ROStructType.prototype.toObject = function toObject(aStoreType) { + var result = {}; + for (var prop in this) { + if ((typeof this[prop]) != "function") { + if (this[prop].value instanceof RemObjects.SDK.ROComplexType) { + result[prop] = this[prop].value.toObject(aStoreType); + } else + result[prop] = this[prop].value; + }; + }; + if(aStoreType) result.__type = /function\s*(.*?)\(/.exec(this.constructor.toString())[1]; + return result; +}; + +RemObjects.SDK.ROStructType.prototype.fromObject = function fromObject(aValue) { + for (var prop in this) { + if ((typeof this[prop]) != "function") { //!!! + if (RemObjects.SDK.RTTI[this[prop].dataType] && RemObjects.SDK.RTTI[this[prop].dataType].prototype instanceof RemObjects.SDK.ROComplexType) { + this[prop].value = new RemObjects.SDK.RTTI[this[prop].dataType](); + this[prop].value.fromObject(aValue[prop]); + } else { + if (this[prop].dataType == "DateTime") { + this[prop].value = RemObjects.UTIL.ISO8601toDateTime(aValue[prop]); + } else { + this[prop].value = aValue[prop]; + }; + }; + + }; + }; + return this; +}; + + +RemObjects.SDK.ROArrayType.prototype = new RemObjects.SDK.ROComplexType(); +RemObjects.SDK.ROArrayType.prototype.constructor = RemObjects.SDK.ROArrayType; + + +RemObjects.SDK.ROArrayType.prototype.writeTo = function writeTo(aMessage) { + for (var i=0; i= 0) { + result += String.fromCharCode(b); + }; + return result; +}; + +RemObjects.SDK.BinMessage.prototype.read = function read(valueName, valueType) { + var value; + + var rttiType = RemObjects.SDK.RTTI[valueType]; + if (rttiType && rttiType.prototype instanceof RemObjects.SDK.ROComplexType) { + if (rttiType.prototype instanceof RemObjects.SDK.ROEnumType) { + value = new rttiType(); + value.readFrom(this); + return value; + }; + + if (!(this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos++, 1), 8, false))) { // Not assigned + return null; + }; + + if (rttiType.prototype instanceof RemObjects.SDK.ROStructType) { + var realType = this.read("", "AnsiString"); + if (valueType !== realType) { + value = new RemObjects.SDK.RTTI[realType](); + } else { + value = new rttiType(); + }; + value.readFrom(this); + return value; + } + + value = new rttiType(); + if (value instanceof RemObjects.SDK.ROArrayType) { + value.items.length = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); + this.fStreamPos += 4; + }; + value.readFrom(this); + + return value; + } + + switch (valueType) { + case "Decimal": + var decimal = []; + for (var i = 0; i < 6; i++) { + decimal[i] = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 2), 16, false); + this.fStreamPos += 2; + }; + decimal[6] = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); + this.fStreamPos += 4; + value = parseFloat(RemObjects.UTIL.decimalToString(decimal)); + break; + + case "Double": + value = this.parser.decodeFloat(this.fResponseString.substr(this.fStreamPos, 8), 52, 11); + this.fStreamPos += 8; + this.fResponseObject[valueName] = value; + break; + + case "DateTime": + var utcValue = this.parser.decodeFloat(this.fResponseString.substr(this.fStreamPos, 8), 52, 11); + utcValue = new Date(Math.round((utcValue - 25569.0) * 86400000)); + value = new Date(utcValue.getUTCFullYear(), utcValue.getUTCMonth(), utcValue.getUTCDate(), utcValue.getUTCHours(), utcValue.getUTCMinutes(), utcValue.getUTCSeconds()); + this.fStreamPos += 8; + this.fResponseObject[valueName] = value; + break; + + case "Boolean": + value = !(this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false) == 0); + this.fStreamPos += 4; + this.fResponseObject[valueName] = value; + break; + + case "Integer": + value = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, true); + this.fStreamPos += 4; + this.fResponseObject[valueName] = value; + break; + + case "Int64": + value = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 6), 48, true); + this.fStreamPos += 8; + this.fResponseObject[valueName] = value; + break; + + case "Currency": + value = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 6), 48, true) / 10000; + this.fStreamPos += 8; + this.fResponseObject[valueName] = value; + break; + + case "Xml": + case "Utf8String": + var len = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); + this.fStreamPos += 4; + value = RemObjects.UTIL.byteArrayToStr(this.fResponseString.substr(this.fStreamPos, len)); + this.fStreamPos += len; + break; + + case "WideString": + var len = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); + this.fStreamPos += 4; + value = RemObjects.UTIL.byteArrayToUtf16(this.fResponseString.substr(this.fStreamPos, len * 2)); + this.fStreamPos += len * 2; + break; + + case "Binary": + var isAssigned = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 1), 8, false); + this.fStreamPos += 1; + if (isAssigned == 0) { + value = null; + break; + }; + var len = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); + this.fStreamPos += 4; + value = ""; + for (var i = this.fStreamPos; i < this.fStreamPos + len; i++) { + value += String.fromCharCode(this.fResponseString.charCodeAt(i) & 0xFF); + }; + this.fStreamPos += len; + break; + + case "AnsiString": + var len = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); + this.fStreamPos += 4; + value = this.fResponseString.substr(this.fStreamPos, len); + this.fStreamPos += len; + break; + + case "Guid": + value = RemObjects.UTIL.byteArrayToGuid(this.fResponseString.substr(this.fStreamPos, 16)); + this.fStreamPos += 16; + break; + + case "Variant": + value = this.readVariant(); + break; + + default: + if (RemObjects.SDK.RTTI[valueType] && (typeof(RemObjects.SDK.RTTI[valueType]) == "function") && (RemObjects.SDK.RTTI[valueType].prototype instanceof RemObjects.SDK.ROComplexType)) { + value = new RemObjects.SDK.RTTI[valueType](); + value.readFrom(this); + } else { + this.fResponseObject.error = {message : "BinMessage.read: Unknown type of " + valueName + " - " + valueType}; + throw new Error(this.fResponseObject.error.message); + }; + }; + return value; +}; + +RemObjects.SDK.BinMessage.prototype.readVariant = function readVariant() { + var code = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); + this.fStreamPos += 4; + var result; + + if ((code & 0x2000) == 0x2000) { + if (code == 0x2011) { //varBinary + var binLength = this.read("", "Integer"); + result = this.fResponseString.substr(this.fStreamPos, binLength); + this.fStreamPos += binLength; + } else {//varArray + //var itemCode = code & 0xFFF; + result = []; + var lowBound = this.read("", "Integer"); + var highBound = this.read("", "Integer"); + for (var i = lowBound; i <= highBound; i++) + result[i] = this.readVariant(); + }; + return result; + }; + + switch(code) { + case 0x000A: //varError + case 0x0000: return undefined; //varEmpty + case 0x0001: return null; //varNull + case 0x0002: //varInt16 + result = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 2), 16, true); + this.fStreamPos += 2; + return result; + case 0x0003: //varInt32 + result = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, true); + this.fStreamPos += 4; + return result; + case 0x0004: //varSingle + result = this.parser.decodeFloat(this.fResponseString.substr(this.fStreamPos, 4), 23, 8); + this.fStreamPos += 4; + return result; + case 0x0005: return this.read("", "Double");//varDouble + case 0x0006: return this.read("", "Currency");//varCurrency + case 0x0007: return this.read("", "DateTime");//varDateTime +//varDispatch = 0x0009 + case 0x000B: return this.read("", "Boolean");//varBoolean +//varVariant = 0x000C +//varUnknown = 0x000D + case 0x000E: return this.read("", "Decimal");//varDecimal + case 0x0010: //varInt8 + result = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 1), 8, true); + this.fStreamPos += 1; + return result; + case 0x0011: //varByte + result = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 1), 8, false); + this.fStreamPos += 1; + return result; + case 0x0012: //varWord + result = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 2), 16, false); + this.fStreamPos += 2; + return result; + case 0x0013: //varLongWord + result = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); + this.fStreamPos += 4; + return result; + case 0x0014: //varInt64 + result = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 8), 48, true); + this.fStreamPos += 8; + return result; + case 0x0072: return this.read("", "Guid");//varGuid + case 0x0100: return this.read("", "AnsiString");//varDelphiString + case 0x0008: //varOleStr + case 0x0102: return this.read("", "Utf8String");//varDelphiUtfString + default : throw new Error("readVariant: unknown varCode 0x" + code.toString(16)); + }; +}; + + +RemObjects.SDK.BinMessage.prototype.requestStream = function requestStream() { + return this.fRequestObject; +}; + +RemObjects.SDK.BinMessage.prototype.setResponseStream = function setResponseStream(aResponse) { + this.fResponseString = aResponse; + var header = new RemObjects.SDK.BinHeader(); + header.readFrom(this.fResponseString.substr(0, 28)); + this.fStreamPos = 28; //skip header + + if (!header.isValidHeader()) { + this.fResponseObject.error = {message : "Invalid response: unsupported binary message signature"}; + throw new Error(this.fResponseObject.error.message); + }; + if (header.getCompressed()) { + + this.fResponseString = this.readCompressed(); + this.fStreamPos = 0; + + //this.fResponseObject.error = {message : "Invalid response: compression is not supported for binary message"}; + //throw new Error(this.fResponseObject.error.message); + }; + + switch (header.getMessageType()) { + + case RemObjects.SDK.Enum.MessageType.mtMessage : + var value = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); + this.fStreamPos += 4 + value; //skip service name + value = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); + this.fStreamPos += 4 + value; //skip method name + break; + + case RemObjects.SDK.Enum.MessageType.mtException : + var value = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); + var exceptionClass = this.fResponseString.substr(this.fStreamPos + 4, value); + this.fStreamPos += 4 + value; + value = this.parser.decodeInt(this.fResponseString.substr(this.fStreamPos, 4), 32, false); + var exceptionMessage = this.fResponseString.substr(this.fStreamPos + 4, value); + this.fStreamPos += 4 + value; //skip method name + this.fResponseObject.error = {message : exceptionClass + ":\n" + exceptionMessage}; + var __e = new Error(exceptionMessage); + __e.name = exceptionClass; + throw __e; + break; + case RemObjects.SDK.Enum.MessageType.mtPollResponse : + case RemObjects.SDK.Enum.MessageType.mtEvent : + break; + + default: + throw new Error("Unsupported binary message type - 0x" + header.getMessageType().toString(16)); + }; + + +}; + + +RemObjects.SDK.JSONMessage.prototype = new RemObjects.SDK.Message(); +RemObjects.SDK.JSONMessage.prototype.constructor = RemObjects.SDK.JSONMessage; + +RemObjects.SDK.JSONMessage.prototype.initialize = function initialize(aServiceName, aMethodName, aMessageType) { + this.fRequestObject.id = "{" + this.fClientID + "}"; + this.fRequestObject.method = aServiceName + "." + aMethodName; + this.fRequestObject.params = {}; + if (aMessageType) this.fRequestObject.type = aMessageType; +}; + +RemObjects.SDK.JSONMessage.prototype.finalize = function finalize() { + +}; + +RemObjects.SDK.JSONMessage.prototype.write = function write(aName, aType, aValue) { + if (aValue instanceof RemObjects.SDK.ROComplexType) { + this.fRequestObject.params[aName] = aValue.toObject(true); + } else if (aValue instanceof Date) { + this.fRequestObject.params[aName] = RemObjects.UTIL.dateTimeToSOAPString(aValue); + } else if (aType == "Binary") { + this.fRequestObject.params[aName] = RemObjects.UTIL.toBase64(aValue); + } else { + this.fRequestObject.params[aName] = aValue; + }; +}; + + +RemObjects.SDK.JSONMessage.prototype.read = function read(aName, aType) { + if (this.fResponseObject.result == undefined) { + throw new Error("JSONMessage.read: result property is missing:\n" + RemObjects.UTIL.toJSON(this.fResponseObject)); + }; + + if (this.fResponseObject.result[aName] == undefined) { + throw new Error("JSONMessage.read error:\n" + aName + ":" + aType + " is missing."); + }; + + var result; + aType = this.fResponseObject.result[aName].__type || aType; + if (RemObjects.SDK.RTTI[aType] && RemObjects.SDK.RTTI[aType].prototype instanceof RemObjects.SDK.ROComplexType) { + result = new RemObjects.SDK.RTTI[aType](); + if (RemObjects.SDK.RTTI[aType].prototype instanceof RemObjects.SDK.ROEnumType) { + result.value = this.fResponseObject.result[aName]; + } else { + result.fromObject(this.fResponseObject.result[aName]); + }; + } else if ((aType == "DateTime") || ((aType == "Variant") && (RemObjects.UTIL.ISO8601toDateTime(this.fResponseObject.result[aName])))) { + result = RemObjects.UTIL.ISO8601toDateTime(this.fResponseObject.result[aName]); + } else { + result = this.fResponseObject.result[aName]; + }; + return result; +}; + + +RemObjects.SDK.JSONMessage.prototype.requestStream = function requestStream() { + return RemObjects.UTIL.toJSON(this.fRequestObject); +}; + +RemObjects.SDK.JSONMessage.prototype.setResponseStream = function setResponseStream(aResponse) { + try { + this.fResponseObject = RemObjects.UTIL.parseJSON(aResponse); + } catch (e) { + throw new Error("JSONMessage.setResponseStream:\n JSON parsing error: " + e.message + "\nServer response:\n" + aResponse); + }; + if (this.fResponseObject.error) { + var __e; + __e = new Error(this.fResponseObject.error.message); + if (this.fResponseObject.error.name == "ROJSONException") { + __e.name = this.fResponseObject.error.roexception.type; + } else { + __e.name = this.fResponseObject.error.name; + }; + throw __e; + }; + if (!this.fResponseObject.result) { + this.fResponseObject.result = this.fResponseObject.params; + }; +}; + +RemObjects.SDK.EventReceiver.prototype.addHandler = function addHandler(anEventName, aCallback) { + this.fHandlers[anEventName] = aCallback; +}; + +RemObjects.SDK.EventReceiver.prototype.setActive = function setActive(aValue) { + this.fActive = aValue; + if (this.fActive) { + var that = this; + this.fInterval = setInterval(function () {that.intPollServer();}, this.fTimeout); + } else { + clearInterval(this.fInterval); + }; +}; + +RemObjects.SDK.EventReceiver.prototype.getActive = function getActive() { + return this.fActive; +}; + +RemObjects.SDK.EventReceiver.prototype.getTimeout = function getTimeout() { + return this.fTimeout; +}; + +RemObjects.SDK.EventReceiver.prototype.setTimeout = function setTimeout(aValue) { + this.fTimeout = aValue; + if (this.fActive) { + this.setActive(false); + this.setActive(true); + }; +}; + +RemObjects.SDK.EventReceiver.prototype.intPollServer = function intPollServer() { + try { + var that = this; + var msg = this.fMessage.clone(); + msg.initialize(this.fServiceName, "poll", RemObjects.SDK.Enum.MessageType.mtPoll); + + msg.write("MaxMessageCount", "Integer", 10); + if (msg instanceof RemObjects.SDK.BinMessage) { + msg.write("", "Guid", msg.getClientID()); + }; + + msg.finalize(); + this.fChannel.dispatch(msg, function (__message) { + var msgCount = __message.read("MessageCount", "Integer"); + var msgLeft = __message.read("MessagesLeft", "Integer"); + for (var i = 0; i < msgCount; i++) { + var events = __message.clone(); + events.initialize("", "", RemObjects.SDK.Enum.MessageType.mtPollResponse); + var eventsStream = __message.read("Message_" + i, "Binary"); + if (__message instanceof RemObjects.SDK.JSONMessage) { + eventsStream = RemObjects.UTIL.fromBase64(eventsStream); + }; + events.setResponseStream(eventsStream); + var sinkName = events.read("InterfaceName", "AnsiString"); + var eventName = events.read("MessageName", "AnsiString"); + if (RemObjects.SDK.RTTI[sinkName] && RemObjects.SDK.RTTI[sinkName].prototype instanceof RemObjects.SDK.ROComplexType) { + var sink = new RemObjects.SDK.RTTI[sinkName](); + sink.readEvent(events, eventName); + if (that.fHandlers[eventName]) { + that.fHandlers[eventName](RemObjects.SDK.ROStructType.prototype.toObject.call(sink[eventName])); + }; + } else { + throw new Error("EventReceiver.intPollServer: unknown event sink"); + }; + }; + }, RemObjects.UTIL.showError); + + } catch (e) { + RemObjects.UTIL.showError(msg, e); + }; + +}; + + +function TitaniumAjaxWrapper(url) { + this.updating = false; + this.urlCall = url; +}; + + +TitaniumAjaxWrapper.prototype.post = function post(passData, isBinary, onSuccessFunction, onErrorFunction) { + + if (this.updating) { + return false; + }; + this.AJAX = null; + + this.AJAX = Ti.Network.createHTTPClient({ + onload: function(e) { + Ti.API.info("onload"); + if (isBinary) { + onSuccessFunction(this.responseData, 200); + } else { + onSuccessFunction(this.responseText, 200); + }; + }, + onerror: function(e) { + Ti.API.info('XHR Error ' + e.error); + }, + timeout:5000 + }); + this.updating = new Date(); + var uri = this.urlCall + '?' + this.updating.getTime(); + + Ti.API.info("TitaniumAjaxWrapper " + uri); + this.AJAX.open("POST", uri); + // if (isBinary) { + // this.AJAX.setRequestHeader('Content-Type','multipart/form-data'); + // } + this.AJAX.send(passData); +}; + +function AjaxWrapper(url) { + this.updating = false; + this.urlCall = url; +}; + + +AjaxWrapper.prototype.abort = function abort() { + if (this.updating) { + this.updating = false; + this.AJAX.abort(); + this.AJAX = null; + }; +}; + +AjaxWrapper.prototype.post = function post(passData, isBinary, onSuccessFunction, onErrorFunction) { + function isIE10Up() { + if (!navigator) + return false; + // Project Spartan is not yet supported + // This code detects only IE 10 and IE 11 + return (navigator.userAgent.indexOf("MSIE 10") != -1) + || (!!navigator.userAgent.match(/Trident\/7\./)); + }; + + if (this.updating) { + return false; + }; + this.AJAX = null; + + try { + this.AJAX = new XMLHttpRequest(); + } catch (e) { + // Internet Explorer Browsers + try { + this.AJAX = new ActiveXObject("Msxml2.XMLHTTP"); + } catch (e) { + try { + this.AJAX = new ActiveXObject("Microsoft.XMLHTTP"); + } catch (e) { + throw new Error("Your browser doesn't support XMLHttpRequest object"); + }; + }; + }; + + + if (this.AJAX == null) { + return false; + } else { + this.onSuccess = onSuccessFunction || function () { + }; + this.onError = onErrorFunction || function () { + }; + var that = this; + + this.AJAX.onreadystatechange = function onreadystatechange() { + if (that.AJAX.readyState == 4) { + that.updating = false; + if (that.AJAX.status == 200) { + if (isIE10Up() && typeof(that.AJAX.response) != "string") { + var response = ""; + var arr = new Uint8Array(that.AJAX.response); + for (var i = 0; i < arr.length; i++) response += String.fromCharCode(arr[i]); + that.onSuccess(response, that.AJAX.status/*, that.AJAX.responseXML*/); + } else { + that.onSuccess(that.AJAX.responseText, that.AJAX.status, that.AJAX.responseXML); + }; + } else { + that.onError(that.AJAX.responseText, that.AJAX.status, that.AJAX.responseXML); + }; + that.AJAX = null; + }; + }; + this.updating = new Date(); + var uri = this.urlCall + '?' + this.updating.getTime(); + this.AJAX.open("POST", uri, true); + //this.AJAX.setRequestHeader("Content-Length", passData.length); + if (isBinary == true) { + if (this.AJAX.overrideMimeType) + this.AJAX.overrideMimeType('text/plain; charset=x-user-defined'); + this.AJAX.setRequestHeader("Content-type", "application/octet-stream"); + if (this.AJAX.sendAsBinary) { + this.AJAX.sendAsBinary(passData); + } else { + var len = passData.length; + var data = new Uint8Array(len); + for (var i=0; i> 3 ) - 1; + do + for( var byteValue = b.buffer[ ++curByte ], startBit = precisionBits % 8 || 8, mask = 1 << startBit; mask >>= 1; ( byteValue & mask ) && ( significand += 1 / divisor ), divisor *= 2 ); + while( precisionBits -= startBit ); + return exponent == ( bias << 1 ) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity : ( 1 + signal * -2 ) * ( exponent || significand ? !exponent ? Math.pow( 2, -bias + 1 ) * significand : Math.pow( 2, exponent - bias ) * ( 1 + significand ) : 0 ); +}; +BinaryParser.prototype.encodeFloat = function encodeFloat( data, precisionBits, exponentBits ){ + var bias = Math.pow( 2, exponentBits - 1 ) - 1, minExp = -bias + 1, maxExp = bias, minUnnormExp = minExp - precisionBits, + status = isNaN( n = parseFloat( data ) ) || n == -Infinity || n == +Infinity ? n : 0, + exp = 0, len = 2 * bias + 1 + precisionBits + 3, bin = new Array( len ), + signal = ( n = status !== 0 ? 0 : n ) < 0, n = Math.abs( n ), intPart = Math.floor( n ), floatPart = n - intPart, + i, lastBit, rounded, j, result; + for( i = len; i; bin[--i] = 0 ); + for( i = bias + 2; intPart && i; bin[--i] = intPart % 2, intPart = Math.floor( intPart / 2 ) ); + for( i = bias + 1; floatPart > 0 && i; ( bin[++i] = ( ( floatPart *= 2 ) >= 1 ) - 0 ) && --floatPart ); + for( i = -1; ++i < len && !bin[i]; ); + if( bin[( lastBit = precisionBits - 1 + ( i = ( exp = bias + 1 - i ) >= minExp && exp <= maxExp ? i + 1 : bias + 1 - ( exp = minExp - 1 ) ) ) + 1] ){ + if( !( rounded = bin[lastBit] ) ) { + for( j = lastBit + 2; !rounded && j < len; rounded = bin[j++] ) {}; + }; + for( j = lastBit + 1; rounded && --j >= 0; ( bin[j] = !bin[j] - 0 ) && ( rounded = 0 ) ){}; + }; + for( i = i - 2 < 0 ? -1 : i - 3; ++i < len && !bin[i]; ){}; + if( ( exp = bias + 1 - i ) >= minExp && exp <= maxExp ) { + ++i; + } else if( exp < minExp ){ + exp != bias + 1 - len && exp < minUnnormExp && this.warn( "encodeFloat::float underflow" ); + i = bias + 1 - ( exp = minExp - 1 ); + }; + if( intPart || status !== 0 ){ + this.warn( intPart ? "encodeFloat::float overflow" : "encodeFloat::" + status ); + exp = maxExp + 1; + i = bias + 2; + if( status == -Infinity ) { + signal = 1; + } else if( isNaN( status ) ) + bin[i] = 1; + }; + for( n = Math.abs( exp + bias ), j = exponentBits + 1, result = ""; --j; result = ( n % 2 ) + result, n = n >>= 1 ); + for( n = 0, j = 0, i = ( result = ( signal ? "1" : "0" ) + result + bin.slice( i, i + precisionBits ).join( "" ) ).length, r = []; i; j = ( j + 1 ) % 8 ){ + n += ( 1 << j ) * result.charAt( --i ); + if( j == 7 ){ + r[r.length] = String.fromCharCode( n ); + n = 0; + }; + }; + r[r.length] = n ? String.fromCharCode( n ) : ""; + return ( this.bigEndian ? r.reverse() : r ).join( "" ); +}; + +BinaryParser.prototype.encodeInt = function encodeInt(number, bits, signed){ + var max = Math.pow(2, bits), r = []; + (number >= max || number < -Math.pow(2, bits-1)) && this.warn("encodeInt::overflow") && (number = 0); + number < 0 && (number += max); + for(; number; r[r.length] = String.fromCharCode(number % 256), number = Math.floor(number / 256)); + for(bits = -(-bits >> 3) - r.length; bits--; r[r.length] = "\0"); + return (this.bigEndian ? r.reverse() : r).join(""); + }; + +BinaryParser.prototype.decodeInt = function decodeInt(data, bits, signed){ + var b = new this.Buffer(this.bigEndian, data), x = b.readBits(0, bits), max = Math.pow(2, bits); + return signed && x >= max / 2 ? x - max : x; + }; + + + + with({p: (BinaryParser.prototype.Buffer = function Buffer(bigEndian, buffer){ + this.bigEndian = bigEndian || 0, this.buffer = [], this.setBuffer(buffer); + }).prototype}){ + p.readBits = function(start, length){ + //shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni) + function shl(a, b){ +// for(++b; --b; a = ((a %= 0x7fffffff + 1) & 0x40000000) == 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1); + for(++b; --b; a = ((a %= 0x7fffffffffff + 1) & 0x400000000000) == 0x400000000000 ? a * 2 : (a - 0x400000000000) * 2 + 0x7fffffffffff + 1); + return a; + }; + if(start < 0 || length <= 0) + return 0; + this.checkBuffer(start + length); + for(var offsetLeft, offsetRight = start % 8, curByte = this.buffer.length - (start >> 3) - 1, + lastByte = this.buffer.length + (-(start + length) >> 3), diff = curByte - lastByte, + sum = ((this.buffer[ curByte ] >> offsetRight) & ((1 << (diff ? 8 - offsetRight : length)) - 1)) + + (diff && (offsetLeft = (start + length) % 8) ? (this.buffer[ lastByte++ ] & ((1 << offsetLeft) - 1)) + << (diff-- << 3) - offsetRight : 0); diff; sum += shl(this.buffer[ lastByte++ ], (diff-- << 3) - offsetRight) + ); + return sum; + }; + p.setBuffer = function setBuffer(data){ + if(data){ + for(var l, i = l = data.length, b = this.buffer = new Array(l); i; b[l - i] = data.charCodeAt(--i) & 0xFF); +// for(var l, i = l = data.length, b = this.buffer = new Array(l); i; b[l - i] = data.charCodeAt(--i)); + this.bigEndian && b.reverse(); + }; + }; + p.hasNeededBits = function hasNeededBits(neededBits){ + return this.buffer.length >= -(-neededBits >> 3); + }; + p.checkBuffer = function checkBuffer(neededBits){ + if(!this.hasNeededBits(neededBits)) { + throw new Error("checkBuffer::missing bytes");}; + }; + }; + +/* +DEFLATE implementation based on http://www.codeproject.com/Articles/26980/Binary-Formats-in-JavaScript-Base64-Deflate-and-UT +Copyright (c) 2008 notmasteryet + +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. +*/ +RemObjects.ZLIB = { + staticCodes:null, + staticDistances:null, + encodedLengthStart:new Array(3, 4, 5, 6, 7, 8, 9, 10, + 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, + 115, 131, 163, 195, 227, 258), + encodedLengthAdditionalBits:new Array(0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0), + encodedDistanceStart:new Array(1, 2, 3, 4, 5, 7, 9, + 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, + 3073, 4097, 6145, 8193, 12289, 16385, 24577), + encodedDistanceAdditionalBits:new Array(0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, + 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13), + clenMap:new Array(16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15), + + + buildCodes:function buildCodes(lengths) { + var codes = new Array(lengths.length); + var maxBits = lengths[0]; + for (var i = 1; i < lengths.length; i++) { + if (maxBits < lengths[i]) maxBits = lengths[i]; + }; + + var bitLengthsCount = new Array(maxBits + 1); + for (var i = 0; i <= maxBits; i++) bitLengthsCount[i] = 0; + + for (var i = 0; i < lengths.length; i++) { + ++bitLengthsCount[lengths[i]]; + }; + + var nextCode = new Array(maxBits + 1); + var code = 0; + bitLengthsCount[0] = 0; + for (var bits = 1; bits <= maxBits; bits++) { + code = (code + bitLengthsCount[bits - 1]) << 1; + nextCode[bits] = code; + }; + + for (var n = 0; n < codes.length; n++) { + var len = lengths[n]; + if (len != 0) { + codes[n] = nextCode[len]; + nextCode[len]++; + }; + }; + return codes; + }, + + initializeStaticTrees:function initializeStaticTrees() { + var codes = new Array(288); + var codesLengths = new Array(288); + + for (var i = 0; i <= 143; i++) { + codes[i] = 0x0030 + i; + codesLengths[i] = 8; + }; + for (var i = 144; i <= 255; i++) { + codes[i] = 0x0190 + i - 144; + codesLengths[i] = 9; + }; + for (var i = 256; i <= 279; i++) { + codes[i] = 0x0000 + i - 256; + codesLengths[i] = 7; + }; + for (var i = 280; i <= 287; i++) { + codes[i] = 0x00C0 + i - 280; + codesLengths[i] = 8; + }; + RemObjects.ZLIB.staticCodes = RemObjects.ZLIB.buildTree(codes, codesLengths); + + var distances = new Array(32); + var distancesLengths = new Array(32); + for (var i = 0; i <= 31; i++) { + distances[i] = i; + distancesLengths[i] = 5; + }; + RemObjects.ZLIB.staticDistances = RemObjects.ZLIB.buildTree(distances, distancesLengths); + }, + + buildTree:function buildTree(codes, lengths) { + var nonEmptyCodes = new Array(0); + for (var i = 0; i < codes.length; ++i) { + if (lengths[i] > 0) { + var code = new Object(); + code.bits = codes[i]; + code.length = lengths[i]; + code.index = i; + nonEmptyCodes.push(code); + }; + }; + return RemObjects.ZLIB.buildTreeBranch(nonEmptyCodes, 0, 0); + }, + + buildTreeBranch: function buildTreeBranch(codes, prefix, prefixLength) { + if (codes.length == 0) return null; + + var zeros = new Array(0); + var ones = new Array(0); + var branch = new Object(); + branch.isLeaf = false; + for (var i = 0; i < codes.length; ++i) { + if (codes[i].length == prefixLength && codes[i].bits == prefix) { + branch.isLeaf = true; + branch.index = codes[i].index; + break; + } else { + var nextBit = ((codes[i].bits >> (codes[i].length - prefixLength - 1)) & 1) > 0; + if (nextBit) { + ones.push(codes[i]); + } else { + zeros.push(codes[i]); + }; + }; + }; + if (!branch.isLeaf) { + branch.zero = RemObjects.ZLIB.buildTreeBranch(zeros, (prefix << 1), prefixLength + 1); + branch.one = RemObjects.ZLIB.buildTreeBranch(ones, (prefix << 1) | 1, prefixLength + 1); + }; + return branch; + }, + + readDynamicTrees:function readDynamicTrees(bitReader) { + var hlit = bitReader.readLSB(5) + 257; + var hdist = bitReader.readLSB(5) + 1; + var hclen = bitReader.readLSB(4) + 4; + + var clen = new Array(19); + for (var i = 0; i < clen.length; ++i) clen[i] = 0; + for (var i = 0; i < hclen; ++i) clen[RemObjects.ZLIB.clenMap[i]] = bitReader.readLSB(3); + + var clenCodes = RemObjects.ZLIB.buildCodes(clen); + var clenTree = RemObjects.ZLIB.buildTree(clenCodes, clen); + + var lengthsSequence = new Array(0); + while (lengthsSequence.length < hlit + hdist) { + var p = clenTree; + while (!p.isLeaf) { + p = bitReader.readBit() ? p.one : p.zero; + }; + + var code = p.index; + if (code <= 15) { + lengthsSequence.push(code); + } else if (code == 16) { + var repeat = bitReader.readLSB(2) + 3; + for (var q = 0; q < repeat; ++q) + lengthsSequence.push(lengthsSequence[lengthsSequence.length - 1]); + } else if (code == 17) { + var repeat = bitReader.readLSB(3) + 3; + for (var q = 0; q < repeat; ++q) + lengthsSequence.push(0); + } else if (code == 18) { + var repeat = bitReader.readLSB(7) + 11; + for (var q = 0; q < repeat; ++q) + lengthsSequence.push(0); + }; + }; + + var codesLengths = lengthsSequence.slice(0, hlit); + var codes = RemObjects.ZLIB.buildCodes(codesLengths); + var distancesLengths = lengthsSequence.slice(hlit, hlit + hdist); + var distances = RemObjects.ZLIB.buildCodes(distancesLengths); + + var result = new Object(); + result.codesTree = RemObjects.ZLIB.buildTree(codes, codesLengths); + result.distancesTree = RemObjects.ZLIB.buildTree(distances, distancesLengths); + return result; + }, + + BitReader:function BitReader(reader) { + this.bitsLength = 0; + this.bits = 0; + this.reader = reader; + this.readBit = function () { + if (this.bitsLength == 0) { + var nextByte = this.reader.readByte(); + if (nextByte < 0) throw new "Unexpected end of stream"; + this.bits = nextByte; + this.bitsLength = 8; + }; + + var bit = (this.bits & 1) != 0; + this.bits >>= 1; + --this.bitsLength; + return bit; + }; + this.align = function () { + this.bitsLength = 0; + }; + this.readLSB = function (length) { + var data = 0; + for (var i = 0; i < length; ++i) { + if (this.readBit()) data |= 1 << i; + }; + return data; + }; + this.readMSB = function (length) { + var data = 0; + for (var i = 0; i < length; ++i) { + if (this.readBit()) data = (data << 1) | 1; else data <<= 1; + }; + return data; + }; + }, + + + Inflator:function Inflator(reader) { + this.reader = reader; + this.bitReader = new RemObjects.ZLIB.BitReader(reader); + this.buffer = new Array(0); + this.bufferPosition = 0; + this.state = 0; + this.blockFinal = false; + this.readByte = function () { + while (this.bufferPosition >= this.buffer.length) { + var item = this.decodeItem(); + if (item == null) return -1; + switch (item.itemType) { + case 0: + this.buffer = this.buffer.concat(item.array); + break; + case 2: + this.buffer.push(item.symbol); + break; + case 3: + var j = this.buffer.length - item.distance; + for (var i = 0; i < item.length; i++) { + this.buffer.push(this.buffer[j++]); + }; + break; + }; + }; + var symbol = this.buffer[this.bufferPosition++]; + if (this.bufferPosition > 0xC000) { + var shift = this.buffer.length - 0x8000; + if (shift > this.bufferPosition) shift = this.bufferPosition; + this.buffer.splice(0, shift); + this.bufferPosition -= shift; + }; + return symbol; + }; + + this.decodeItem = function () { + if (this.state == 2) return null; + + var item; + if (this.state == 0) { + this.blockFinal = this.bitReader.readBit(); + var blockType = this.bitReader.readLSB(2); + switch (blockType) { + case 0: + this.bitReader.align(); + var len = this.bitReader.readLSB(16); + var nlen = this.bitReader.readLSB(16); + if ((len & ~nlen) != len) throw "Invalid block type 0 length"; + + item = new Object(); + item.itemType = 0; + item.array = new Array(len); + for (var i = 0; i < len; ++i) { + var nextByte = this.reader.readByte(); + if (nextByte < 0) throw "Uncomplete block"; + item.array[i] = nextByte; + } + if (this.blockFinal) this.state = 2; + return item; + case 1: + this.codesTree = RemObjects.ZLIB.staticCodes; + this.distancesTree = RemObjects.ZLIB.staticDistances; + this.state = 1; + break; + case 2: + var dynamicTrees = RemObjects.ZLIB.readDynamicTrees(this.bitReader); + this.codesTree = dynamicTrees.codesTree; + this.distancesTree = dynamicTrees.distancesTree; + this.state = 1; + break; + default: + throw new "Invalid block type (3)"; + }; + }; + + item = new Object(); + var p = this.codesTree; + while (!p.isLeaf) { + p = this.bitReader.readBit() ? p.one : p.zero; + }; + if (p.index < 256) { + item.itemType = 2; + item.symbol = p.index; + } else if (p.index > 256) { + var lengthCode = p.index; + if (lengthCode > 285) throw new "Invalid length code"; + + var length = RemObjects.ZLIB.encodedLengthStart[lengthCode - 257]; + if (RemObjects.ZLIB.encodedLengthAdditionalBits[lengthCode - 257] > 0) { + length += this.bitReader.readLSB(RemObjects.ZLIB.encodedLengthAdditionalBits[lengthCode - 257]); + }; + + p = this.distancesTree; + while (!p.isLeaf) { + p = this.bitReader.readBit() ? p.one : p.zero; + }; + + var distanceCode = p.index; + var distance = RemObjects.ZLIB.encodedDistanceStart[distanceCode]; + if (RemObjects.ZLIB.encodedDistanceAdditionalBits[distanceCode] > 0) { + distance += this.bitReader.readLSB(RemObjects.ZLIB.encodedDistanceAdditionalBits[distanceCode]); + }; + + item.itemType = 3; + item.distance = distance; + item.length = length; + } else { + item.itemType = 1; + this.state = this.blockFinal ? 2 : 0; + }; + return item; + }; + } +}; + +RemObjects.ZLIB.initializeStaticTrees(); \ No newline at end of file diff --git a/demo/dataabstract/sampleda.html b/demo/dataabstract/sampleda.html new file mode 100644 index 0000000..b029eaa --- /dev/null +++ b/demo/dataabstract/sampleda.html @@ -0,0 +1,57 @@ + + + + + + + Data Abstract dataset demo + + + + + + + + + + + + + + + + + +
+ + + + + diff --git a/demo/dataabstract/sampleda.lpi b/demo/dataabstract/sampleda.lpi new file mode 100644 index 0000000..689c7a0 --- /dev/null +++ b/demo/dataabstract/sampleda.lpi @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <CustomData Count="1"> + <Item0 Name="PasJSWebBrowserProject" Value="1"/> + </CustomData> + <BuildModes Count="1"> + <Item1 Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + <UseFileFilters Value="True"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + <Modes Count="0"/> + </RunParams> + <Units Count="1"> + <Unit0> + <Filename Value="sampleda.lpr"/> + <IsPartOfProject Value="True"/> + </Unit0> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <Target FileExt=".js"> + <Filename Value="sampleda"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="js"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <AllowLabel Value="False"/> + <UseAnsiStrings Value="False"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <TargetOS Value="browser"/> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + <UseLineInfoUnit Value="False"/> + </Debugging> + </Linking> + <Other> + <CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc"/> + <CompilerPath Value="$(pas2js)"/> + </Other> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/demo/dataabstract/sampleda.lpr b/demo/dataabstract/sampleda.lpr new file mode 100644 index 0000000..7df990d --- /dev/null +++ b/demo/dataabstract/sampleda.lpr @@ -0,0 +1,119 @@ +program sampleda; + +{$mode objfpc} + +uses + JS, Classes, SysUtils, Web, DB, dasdk, dadataset; + +Type + + { TSampleForm } + + TSampleForm = Class(TComponent) + Private + divWrapper : TJSHTMLElement; + btnGetData : TJSHTMLButtonElement; + tblBody : TJSHTMLElement; + FConn : TDAConnection; + FDataset : TDADataset; + procedure AfterLoad(DataSet: TDataSet; Data: JSValue); + procedure BindElements; + procedure CreateDataset; + procedure DoClientsOpen(DataSet: TDataSet); + function DoGetDataClick(aEvent: TJSMouseEvent): boolean; + procedure DoLoginOK(result: Boolean; UserInfo: TDAUserInfo); + Public + Procedure Show; + end; + +{ TSampleForm } + +procedure TSampleForm.CreateDataset; + +begin + FConn:=TDaConnection.Create(Self); + FConn.URL:='https://sample.remobjects.com/bin'; + FConn.OnLogin:=@DoLoginOK; + FConn.StreamerType:=stBin; + FDataset:=TDaDataset.Create(Self); + FDataset.DAConnection:=FConn; + FDataset.TableName:='Clients'; + FDataset.AfterOpen:=@DoClientsOpen; +end; + +procedure TSampleForm.BindElements; + +begin + btnGetData:=TJSHTMLButtonElement(Document.getElementById('btn-fetch')); + btnGetData.onClick:=@DoGetDataClick; + tblBody:=TJSHTMLElement(Document.getElementById('tableRows')); + divWrapper:=TJSHTMLElement(Document.getElementById('wrapper')); +end; + +procedure TSampleForm.AfterLoad(DataSet: TDataSet; Data: JSValue); +begin + Writeln('Loaded'); +end; + +procedure TSampleForm.DoClientsOpen(DataSet: TDataSet); + + Function escape(S : String) : String; + + begin + Result:=StringReplace(S,'&','&',[rfReplaceAll]); + Result:=StringReplace(S,'<','<',[rfReplaceAll]); + Result:=StringReplace(S,'>','>',[rfReplaceAll]); + Result:=StringReplace(S,'"','"',[rfReplaceAll]); + Result:=StringReplace(S,'''',''',[rfReplaceAll]); + end; + +Var + FID,FName,FPhone : TField; + HTML : String; + +begin + Writeln('Clients open :',Dataset.RecordCount); + FID:=Dataset.FieldByname('ClientId'); + FName:=Dataset.FieldByname('ClientName'); + FPhone:=Dataset.FieldByname('ContactPhone'); + While not Dataset.EOF do + begin + html:=Html+'<TR><TD>'+Escape(FID.AsString)+'</TD>' + +'<TD>'+Escape(FName.AsString)+'</TD>' + +'<TD>'+Escape(FPhone.AsString)+'</TD></TR>'; + Dataset.Next; + end; + tblBody.InnerHTMl:=HTML; + divWrapper['style']:=''; +end; + +function TSampleForm.DoGetDataClick(aEvent: TJSMouseEvent): boolean; +begin + FConn.LoginEx('User=simple;Password=simple;'); + Result:=False; +end; + +procedure TSampleForm.DoLoginOK(result: Boolean; UserInfo: TDAUserInfo); +begin + Writeln('Login :',result); + if Result then + begin + divWrapper['style']:='display: none;'; + FDataset.Active:=False; + FDataset.Load([],@AfterLoad); + end + else + window.Alert('Failed to log in !') +end; + +procedure TSampleForm.Show; + +begin + CreateDataset; + BindElements; +end; + +begin + With TSampleForm.Create(Nil) do + Show; +end. diff --git a/packages/dataabstract/da.pas b/packages/dataabstract/da.pas new file mode 100644 index 0000000..5520b03 --- /dev/null +++ b/packages/dataabstract/da.pas @@ -0,0 +1,318 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2018 by Michael Van Canneyt, member of the + Free Pascal development team + + Remobjects Data Abstract external classes. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} +unit DA; + +{$mode objfpc} +{$modeswitch externalclass} + +interface + +uses Types, JS, DASDK; + +Type + // Forward classes + TDADataTable = class; + TDABIN2DataStreamer = class; + TDAJSONDataStreamer = class; + TDARemoteDataAdapter = Class; + TDAChange = class; + TDADelta = class; + TDADeltas = class; + TDAField = class; + TDALookupField = class; + TDADataTableRow = class; + TDAExpression = class; + TDADynamicWhere = class; + TDAConstantExpression = class; + TDAParameterExpression = class; + TDANullExpression = class; + TDAFieldExpression = class; + TDAMacroExpression = class; + TDAUnaryExpression = class; + TDABinaryExpression = class; + TDABetweenExpression = class; + TDAListExpression = class; + TDAUtil = Class; + TDARemoteDataAdaptor = Class; + + + TDAStream = String; + + TDADataStreamer = class external name 'RemObjects.DataAbstract.DataStreamer' (TJSObject) + Public + procedure initializeRead; + procedure initializeWrite; + procedure finalizeWrite; + function getStream : TDAStream; + procedure setStream(aStream : TDAStream); + procedure readDataset(aDataset : TDADataTable); + function readDelta : TDADelta; + procedure writeDelta(aDelta : TDADelta); + Property Stream : TDAStream Read getStream write setStream; + end; + + TDADataStreamerClass = Class of TDADataStreamer; + + TDABIN2DataStreamer = class external name 'RemObjects.DataAbstract.Bin2DataStreamer' (TDADataStreamer) + function readByte : Byte; + function readInteger : NativeInt; + function readAnsiStringWithLength : String; + function readUtf8StringWithLength : string; + function read (aType : string) : TJSObject; + function readParam (acount : Integer) : TDADataParameter; + function readField(acount : Integer) : TDAField; + Procedure writeByte(aValue : Byte); + Procedure writeInteger(aValue : NativeInt); + Procedure writeAnsiStringWithLength(aValue : String); + Procedure write(aType : string; aValue : TJSObject); + end; + + TDAJSONDataStreamer = class external name 'RemObjects.DataAbstract.JSONDataStreamer' (TDADataStreamer) + end; + + TDARemoteDataAdapter = Class external name 'RemObjects.DataAbstract.RemoteDataAdapter' (TJSObject) + Public + Constructor New(Const aURL, aDataServiceName, aLoginServiceName : String; + aStreamerClass : TDADataStreamerClass); + end; + + TDAChange = class external name 'RemObjects.DataAbstract.Change' (TJSObject) + end; + + TDAChangeArray = array of TDAChange; + + TLogField = record + name : string; + datatype : string; + end; + TLogFieldArray = array of TLogfield; + + TDADelta = class external name 'RemObjects.DataAbstract.Delta' (TJSObject) + Private + FData : TDAChangeArray; external name 'data'; + FKeyFields : TStringDynArray; external name 'keyfields'; + FLoggedFields : TLogFieldArray; external name 'loggedfields'; + FName : string; external name 'name'; + Public + Function intFindId(anId : Integer) : TDAChange; + Property data : TDAChangeArray Read FData; + Property keyFields : TStringDynArray Read FKeyFields; + Property LoggedFields : TLogFieldArray Read FLoggedFields; + Property Name : String Read FName; + end; + + TDADeltas = class external name 'RemObjects.DataAbstract.Deltas' (TJSObject) + Public + Function FindByName (Const aName : String) : TDADelta; + end; + + TDATableRowNotifyEvent = reference to procedure(row : TDADataTableRow); + TDADataTableRowArray = array of TDADataTableRow; + TDAFieldArray = Array of TDAField; + + TDADataTable = class external name 'RemObjects.DataAbstract.DataTable' (TJSObject) + Public + name : string; + rows : TDADataTableRowArray; + fields : TDAFieldArray; + deletedrows : TDADataTableRowArray; + frecordbuffer : TJSArray; + fNextRecID : Integer; + fIndex : Integer; + bofFlag : Boolean; + eofFlag : Boolean; + dynamicWhere : TJSObject; + onNewRecord : TDATableRowNotifyEvent; + onBeforeDelete: TDATableRowNotifyEvent; + onAfterDelete: TDATableRowNotifyEvent; + onBeforeScroll: TDATableRowNotifyEvent; + onAfterScroll: TDATableRowNotifyEvent; + Procedure checkRequired; + Procedure locate(aName : String; aValue : JSValue); + procedure addLookupField(const aName,aSourceField : String; aLookupTable : TDADataTable; + const aLookupKeyField, aLookupResultField : String); + procedure getNextId; + function appendRow : TDADataTableRow; + procedure deleteRow; + procedure markDeleted; + function fieldNumByName(Const aName : string) : Integer; + function fieldByName(Const aName : string) : TDAField; + procedure setFieldValue(Const aName : string; aValue : JSValue); + function getFieldValue(Const aName : string) : JSValue; + procedure setFieldAsString(Const aName, aValue : String); + function getFieldAsString(Const aName : string) : String; + function currentRow : TDADataTableRow; + procedure first; + procedure last; + procedure next; + procedure prev; + Function findId(anID: Integer) : TDADataTableRow; + function eof : boolean; + function bof : boolean; + procedure post; + procedure cancel; + end; + + TDAField = class external name 'RemObjects.DataAbstract.Field' (TJSObject) + Public + alignment : string; + blobtype: string; + businessClassID : String; + calculated : string; + customAttributes : string; + dataType : string; + name: string; + type_ : string external name 'type'; + logChanges : boolean; + readOnly : boolean; + serverAutoRefresh : Boolean; + serverCalculated : Boolean; + description : string; + decimalPrecision : Integer; + decimalScale : integer; + defaultValue : string; + dictionaryEntry : String; + displayLabel : String; + displayWidth : integer; + inPrimaryKey : Boolean; + visible : boolean; + required : boolean; + size : integer; + Procedure checkReadOnly; + end; + + TDALookupField = class external name 'RemObjects.DataAbstract.LookupField' (TJSObject) + Public + sourceField : string; + lookupTable : TDADataTable; + lookupKeyField: String; + lookupResultField : string; + end; + + TDADataTableRow = class external name 'RemObjects.DataAbstract.DataTableRow' (TJSObject) + Public + recID : Integer; + state : string; + __oldValues : array of JSValue; + __newValues : array of JSValue; + end; + + TDAExpression = class external name 'RemObjects.DataAbstract.Expression' (TJSObject); + + TDADynamicWhere = class external name 'RemObjects.DataAbstract.DynamicWhere' (TJSObject) + Public + constructor New(anExpression : TDAExpression); + function toXML : String; + end; + + TDAConstantExpression = class external name 'RemObjects.DataAbstract.ConstantExpression' (TDAExpression) + Public + constructor new (aType : String; aValue : JSValue; ANull : Byte); + end; + + TDAParameterExpression = class external name 'RemObjects.DataAbstract.ParameterExpression' (TDAExpression) + Public + constructor new (const aName, aType : String; aSize : Integer); + end; + + TDANullExpression = class external name 'RemObjects.DataAbstract.NullExpression' (TDAExpression) + public + constructor new; + end; + + + TDAFieldExpression = class external name 'RemObjects.DataAbstract.FieldExpression' (TDAExpression) + public + constructor new(aName : string); + end; + + TDAMacroExpression = class external name 'RemObjects.DataAbstract.MacroExpression' (TDAExpression) + public + constructor new(aName : string); + end; + + + TDAUnaryExpression = class external name 'RemObjects.DataAbstract.UnaryExpression' (TDAExpression) + public + constructor new(aNode : TDAExpression; aOperator : string); + end; + + TDABinaryExpression = class external name 'RemObjects.DataAbstract.BinaryExpression' (TDAExpression) + public + constructor new(aNode1,aNode2 : TDAExpression; aOperator : string); + end; + + TDABetweenExpression = class external name 'RemObjects.DataAbstract.BetweenExpression' (TDAExpression) + public + constructor new(aNode1,aNode2,aNode3 : TDAExpression); + end; + + TDAListExpression = class external name 'RemObjects.DataAbstract.ListExpression' (TDAExpression) + public + constructor new(aList : array of TDAExpression); + end; + + + TDAUtil = Class external name 'RemObjects.DataAbstract.Util' (TJSObject) + Public + function createDataParameter(aName : String;aValue : JSValue) : TJSObject; + function createRequestInfo(IncludeSchema : Boolean; MaxRecords : Integer; UserFilter : String; Parameters : Array of JSValue) : TJSObject; + function createRequestInfoV5(IncludeSchema : Boolean; MaxRecords : Integer; UserFilter : String; Parameters : Array of JSValue) : TJSOBject; + function createRequestInfoV6(SQL : String; MaxRecords : Integer; UserFilter : String; Parameters : Array of JSValue) : TJSObject; + procedure setupScriptingCallBacks; + end; + + TDACallBack = procedure; + TDALoginNeededCallBack = reference to procedure(aCallBack : TDACallBack); + TDAChangeFailHandler = reference to procedure (aData : TDAChange); + + TDARemoteDataAdaptor = Class external name 'RemObjects.DataAbstract.RemoteDataAdapter' (TJSObject) + Private + FSendReducedDelta : boolean; external name 'sendReducedDelta'; + Public + onLoginNeeded : TDALoginNeededCallBack; + onChangeFail : TDAChangeFailHandler; + function getDataService() : TDADataAbstractService; + function getLoginService() : TDASimpleLoginService; + procedure login(aUserID,aPassword,aConnectionName : String; OnSuccess : TDASuccessEvent; OnFailed : TDAFailedEvent); + procedure logout(OnSuccess : TDASuccessEvent; OnFailed : TDAFailedEvent); + function createStreaer: TDAJSONDatastreamer; + procedure setSendReducedDelta (aValue : Boolean); + procedure getSchema(aFilter : String;OnSuccess : TDASuccessEvent; OnFailed : TDAFailedEvent); + function buildDelta(aTable : TDADataTable) : TDADelta; + procedure createTableFromSchema(const aTableName : String; aTable : TDADataTable; CallBack: TDACallBack); + procedure executeCommand(const aName : String; Parameters: TDADataParameterArray; OnSuccess : TDASuccessEvent; OnFailed : TDAFailedEvent); + function getAutoGetScripts : Boolean; + procedure setAutoGetScripts(aValue : boolean); + Procedure getSQLData(aTable : TDADataTable; const SQL : String;OnSuccess : TDASuccessEvent; OnFailed : TDAFailedEvent); + Procedure getData(aTable : TDADataTable; aRequest : TDATableRequestInfo;OnSuccess : TDASuccessEvent; OnFailed : TDAFailedEvent); + procedure applyUpdates(aTable : TDADataTable; OnSuccess : TDASuccessEvent; OnFailed : TDAFailedEvent); + property sendReducedDelta : Boolean Read FSendReducedDelta Write setSendReducedDelta; + property AutoGetScripts : boolean Read getAutoGetScripts write setAutoGetScripts; + end; + + TDAHTMLTableView = class external name 'RemObjects.DataAbstract.Views.HtmlTableView' + Public + constructor new(aTable : TDADataTable; aHTMLTableID : String); + end; + + TDAVerticalHTMLTableView = class external name 'RemObjects.DataAbstract.Views.VerticalHtmlTableView' + Public + constructor new(aTable : TDADataTable; aHTMLTableID : String); + end; +Implementation + +end. diff --git a/packages/dataabstract/dadataset.pas b/packages/dataabstract/dadataset.pas new file mode 100644 index 0000000..7cfe7a4 --- /dev/null +++ b/packages/dataabstract/dadataset.pas @@ -0,0 +1,511 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2018 by Michael Van Canneyt, member of the + Free Pascal development team + + Dataset which talks to Remobjects Data Abstract server. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} +unit dadataset; + +interface + +uses Types, Classes, DB, jsonDataset, JS, rosdk, da, dasdk; + +Type + EDADataset = Class(EDatabaseError); + TDAConnection = Class; + + { TDADataset } + + TDADataset = class(TBaseJSONDataset) + private + FParams: TParams; + FTableName: String; + FDAConnection: TDAConnection; + FWhereClause: String; + function DataTypeToFieldType(s: String): TFieldType; + procedure SetParams(AValue: TParams); + Protected + Procedure MetaDataToFieldDefs; override; + Public + constructor create(aOwner : TComponent); override; + Destructor Destroy; override; + function DoGetDataProxy: TDataProxy; override; + // DA is index based. So create array field mapper. + function CreateFieldMapper : TJSONFieldMapper; override; + Procedure CreateFieldDefs(a : TJSArray); + Property TableName : String Read FTableName Write FTableName; + Property DAConnection : TDAConnection Read FDAConnection Write FDAConnection; + Property Params : TParams Read FParams Write SetParams; + Property WhereClause : String Read FWhereClause Write FWhereClause; + end; + + TDADataRequest = Class(TDataRequest) + Public + Procedure doSuccess(res : JSValue) ; + Procedure DoFail(response : TJSOBject; fail : String) ; + End; + + { TDADataProxy } + + TDADataProxy = class(TDataProxy) + private + FConnection: TDAConnection; + function ConvertParams(DADS: TDADataset): TDADataParameterDataArray; + Protected + Function GetDataRequestClass : TDataRequestClass; override; + Public + Function DoGetData(aRequest : TDataRequest) : Boolean; override; + Function ProcessUpdateBatch(aBatch : TRecordUpdateBatch): Boolean; override; + Property Connection : TDAConnection Read FConnection Write FConnection; + end; + + TDAMessageType = (mtAuto, // autodetect from URL + mtBin, // use BinMessage + mtJSON); // Use JSONMessage. + TDAStreamerType = (stJSON,stBin); + + { TDAConnection } + + TDAConnection = class(TComponent) + private + FDataService: TDADataAbstractService; + FDataserviceName: String; + FLoginService: TDASimpleLoginService; + FLoginServiceName: String; + FMessageType: TDAMessageType; + FMessage : TROmessage; + FChannel : TROHTTPClientChannel; + FOnLoginFailed: TDAFailedEvent; + FOnLogin: TDALoginSuccessEvent; + FStreamerType: TDAStreamerType; + FURL: String; + procedure ClearConnection; + Function GetDataService : TDADataAbstractService; + function GetLoginService: TDASimpleLoginService; + procedure SetDataserviceName(AValue: String); + procedure SetLoginServiceName(AValue: String); + procedure SetMessageType(AValue: TDAMessageType); + procedure SetURL(AValue: String); + Protected + Procedure CreateChannelAndMessage; virtual; + function DetectMessageType(Const aURL: String): TDAMessageType; virtual; + Function CreateDataService : TDADataAbstractService; virtual; + Function CreateLoginService : TDASimpleLoginService; virtual; + Public + Constructor create(aOwner : TComponent); override; + Destructor Destroy; override; + // Returns a non-auto MessageType, but raises exception if it cannot be determined; + Function EnsureMessageType : TDAMessageType; + // Returns DataService, but raises exception if it is nil; + Function EnsureDataservice : TDADataAbstractService; + // Returns SimpleLoginService, but raises exception if it is nil; + Function EnsureLoginservice : TDASimpleLoginService; + // Call this to login. This is an asynchronous call, check the result using OnLoginOK and OnLoginFailed calls. + Procedure Login(aUserName, aPassword : String); + Procedure LoginEx(aLoginString : String); + // You can set this. If you didn't set this, and URL is filled, an instance will be created. + Property DataService : TDADataAbstractService Read GetDataService Write FDataService; + // You can set this. If you didn't set this, and URL is filled, an instance will be created. + Property LoginService : TDASimpleLoginService Read GetLoginService Write FLoginService; + Published + // If set, this is the message type that will be used when auto-creating the service. Setting this while dataservice is Non-Nil will remove the reference + Property MessageType : TDAMessageType Read FMessageType Write SetMessageType; + // if set, URL is used to create a DataService. Setting this while dataservice is Non-Nil will remove the reference + Property URL : String Read FURL Write SetURL; + // DataServiceName is used to create a DataService. Setting this while dataservice is Non-Nil will remove the reference + Property DataserviceName : String Read FDataserviceName Write SetDataserviceName; + // LoginServiceName is used to create a login service. Setting this while loginservice is Non-Nil will remove the reference + Property LoginServiceName : String read FLoginServiceName write SetLoginServiceName; + // Called when login call is executed. + Property OnLogin : TDALoginSuccessEvent Read FOnLogin Write FOnLogin; + // Called when login call failed. When call was executed but user is wrong OnLogin is called ! + Property OnLoginCallFailed : TDAFailedEvent Read FOnLoginFailed Write FOnLoginFailed; + // Streamertype : format of the data package in the message. + Property StreamerType : TDAStreamerType Read FStreamerType Write FStreamerType; + end; + + +implementation + +uses strutils, sysutils; + +{ TDAConnection } + + +function TDAConnection.GetDataService: TDADataAbstractService; +begin + if (FDataservice=Nil) then + FDataservice:=CreateDataService; + Result:=FDataService; +end; + +function TDAConnection.GetLoginService: TDASimpleLoginService; +begin + if (FLoginService=Nil) then + FLoginService:=CreateLoginService; + Result:=FLoginService; +end; + +procedure TDAConnection.SetDataserviceName(AValue: String); +begin + if FDataserviceName=AValue then Exit; + ClearConnection; + FDataserviceName:=AValue; +end; + +procedure TDAConnection.SetLoginServiceName(AValue: String); +begin + if FLoginServiceName=AValue then Exit; + FLoginServiceName:=AValue; +end; + +procedure TDAConnection.SetMessageType(AValue: TDAMessageType); +begin + if FMessageType=AValue then Exit; + ClearConnection; + FMessageType:=AValue; +end; + +procedure TDAConnection.ClearConnection; + +begin + FDataservice:=Nil; + FChannel:=Nil; + FMessage:=Nil; +end; + +procedure TDAConnection.SetURL(AValue: String); +begin + if FURL=AValue then Exit; + ClearConnection; + FURL:=AValue; +end; + +procedure TDAConnection.CreateChannelAndMessage; + + +begin + if (FChannel=Nil) then + FChannel:=TROHTTPClientChannel.New(URL); + if (FMessage=Nil) then + Case EnsureMessageType of + mtBin : fMessage:=TROBINMessage.New; + mtJSON : fMessage:=TROJSONMessage.New; + end; +end; + +function TDAConnection.DetectMessageType(Const aURL : String) : TDAMessageType; + +Var + S : String; + +begin + S:=aURL; + Delete(S,1,RPos('/',S)); + case lowercase(S) of + 'bin' : Result:=mtBin; + 'json' : Result:=mtJSON; + else + Raise EDADataset.Create(Name+': Could not determine message type from URL: '+aURL); + end; +end; + + +function TDAConnection.CreateDataService: TDADataAbstractService; + +begin + Result:=Nil; + if URL='' then exit; + CreateChannelAndMessage; + Result:=TDADataAbstractService.New(FChannel,FMessage,DataServiceName); +end; + +function TDAConnection.CreateLoginService: TDASimpleLoginService; +begin + Result:=Nil; + if URL='' then exit; + CreateChannelAndMessage; + Result:=TDASimpleLoginService.New(FChannel,FMessage,LoginServiceName); +end; + +constructor TDAConnection.create(aOwner: TComponent); +begin + inherited create(aOwner); + FDataServiceName:='DataService'; + FLoginServiceName:='LoginService'; +end; + +destructor TDAConnection.Destroy; +begin + ClearConnection; + inherited Destroy; +end; + +function TDAConnection.EnsureMessageType: TDAMessageType; +begin + Result:=MessageType; + if Result=mtAuto then + Result:=DetectMessageType(URL); +end; + +function TDAConnection.EnsureDataservice: TDADataAbstractService; + +begin + Result:=Dataservice; + if (Result=Nil) then + Raise EDADataset.Create('No data service available. '); +end; + +function TDAConnection.EnsureLoginservice: TDASimpleLoginService; + +begin + Result:=LoginService; + if (Result=Nil) then + Raise EDADataset.Create('No login service available. '); +end; + +procedure TDAConnection.Login(aUserName, aPassword: String); + +begin + EnsureLoginService.Login(aUserName,aPassword,FOnLogin,FOnLoginFailed); +end; + +procedure TDAConnection.LoginEx(aLoginString: String); +begin + EnsureLoginService.LoginEx(aLoginString,FOnLogin,FOnLoginFailed); +end; + +{ TDADataset } + +function TDADataset.DataTypeToFieldType(s : String) : TFieldType; + +Const + FieldStrings : Array [TFieldType] of string = ( + '','String', 'Integer', 'LargeInt', 'Boolean', 'Float', 'Date', + 'Time', 'DateTime', 'AutoInc', 'Blob', 'Memo', 'FixedChar', + 'Variant','Dataset'); + + +begin + if (Copy(S,1,3)='dat') then + system.Delete(S,1,3); + Result:=High(TFieldType); + While (Result>ftUnknown) and Not SameText(FieldStrings[Result],S) do + Result:=Pred(Result); + if Result=ftUnknown then + case LowerCase(s) of + 'widestring' : result:=ftString; + 'currency' : result:=ftFloat; + end; +end; + +procedure TDADataset.SetParams(AValue: TParams); +begin + if FParams=AValue then Exit; + FParams.Assign(AValue); +end; + +procedure TDADataset.MetaDataToFieldDefs; + +begin + if Not isArray(Metadata['fields']) then + exit; + CreateFieldDefs(TJSArray(Metadata['fields'])); +end; + +function TDADataset.DoGetDataProxy: TDataProxy; +begin + Result:=TDADataProxy.Create(Self); + TDADataProxy(Result).Connection:=DAConnection; +end; + +constructor TDADataset.create(aOwner: TComponent); +begin + inherited; + DataProxy:=nil; + FParams:=TParams.Create(Self); +end; + +destructor TDADataset.Destroy; +begin + FreeAndNil(FParams); + Inherited; +end; + +procedure TDADataset.CreateFieldDefs(a: TJSArray); + +Var + I : Integer; + F : TDAField; + fn,dt : string; + fs : Integer; + FT : TFieldType; + req : boolean; + +begin + FieldDefs.Clear; + For I:=0 to A.length-1 do + begin + F:=TDAField(A.Elements[i]); + fn:=F.Name; + fs:=F.Size; + dt:=F.type_; + req:=F.Required; + Ft:=DataTypeToFieldType(dT); + if (ft=ftBlob) and (fs=0) then + fs:=1; + FieldDefs.Add(fn,ft,fs,Req); + end; +end; + +function TDADataset.CreateFieldMapper: TJSONFieldMapper; +begin + Result := TJSONArrayFieldMapper.Create; +end; + +{ TDADataProxy } + +function TDADataProxy.ConvertParams(DADS : TDADataset) : TDADataParameterDataArray; + +Var + I : integer; +begin + Result:=Nil; + Writeln('Converting ',DADS.Params.Count,' parameters.'); + if DADS.Params.Count=0 then + Exit; + SetLength(Result,DADS.Params.Count); + for I:=0 to DADS.Params.Count-1 do + begin + Result[i].Name:=DADS.Params[i].Name; + Result[i].Value:=DADS.Params[i].Value; + end; +end; + +function TDADataProxy.DoGetData(aRequest: TDataRequest): Boolean; + +Var + TN : TDAStringArray; + TIA : TDATableRequestInfoArray; + TID : TDATableRequestInfoV5Data; + TI : TDATableRequestInfoV5; + Srt : TDAColumnSortingData; + R : TDADataRequest; + DADS : TDADataset; + PA : TDADataParameterDataArray; + DS : TDADataAbstractService; +begin + // DA does not support this option... + if loAtEOF in aRequest.LoadOptions then + exit(False); + DADS:=aRequest.Dataset as TDADataset; + R:=aRequest as TDADatarequest; + if (Connection=Nil) then + Raise EDADataset.Create(Name+': Cannot get data without connection'); + DS:=Connection.EnsureDataservice; + TN:=TDAStringArray.New; + TN.fromObject([DADS.TableName]); + TID.maxRecords:=-1; + TID.IncludeSchema:=True; + Srt.FieldName:=''; + Srt.SortDirection:='Ascending'; + TID.Sorting:=Srt; + TID.UserFilter:=''; + if DADS.WhereClause<>'' then + TID.WhereClause:=DADS.WhereClause; + PA:=ConvertParams(DADS); + if Length(PA)>0 then + TID.Parameters:=Pa; + TIA:=TDATableRequestInfoArray.new; + // We need to manually fill the array + TI:=TDATableRequestInfoV5.New; + TI.FromObject(TID); + TJSArray(TIA.items).push(TI); + DS.GetData(TN,TIA,@R.doSuccess,@R.doFail); + Result:=True; +end; + +function TDADataProxy.GetDataRequestClass: TDataRequestClass; +begin + Result:=TDADataRequest; +end; + +function TDADataProxy.ProcessUpdateBatch(aBatch: TRecordUpdateBatch): Boolean; +begin + Result:=False; +end; + +{ TDADataRequest } + +procedure TDADataRequest.DoFail(response: TJSOBject; fail: String); + +Var + O : TJSOBject; + S : TStringDynArray; + Msg : String; + I : Integer; + +begin + if isObject(fail) then + begin + O:=TJSOBject(JSValue(fail)); + S:=TJSObject.getOwnPropertyNames(O); + for I:=0 to Length(S)-1 do + begin + msg:=Msg+sLineBreak+S[i]; + Msg:=Msg+' : '+String(O[S[i]]); + end; + end + else + Msg:=Fail; + + writeln('Data request or processing failed: ',Msg); + Success:=rrFail; +end; + +procedure TDADataRequest.doSuccess(res: JSValue); + +Var + S : String; + Rows : TJSArray; + DADS : TDADataset; + DStr : TDADataStreamer; + DT : TDADatatable; + I : Integer; + +begin +// Writeln('Data loaded, dataset active: ',Dataset.Active); + DADS:=Dataset as TDADataset; + if not Assigned(DADS.DAConnection) then + Raise EDADataset.Create(DADS.Name+': Cannot process response, connection not available'); + S:=String(Res); + if (DADS.DAConnection.EnsureMessageType=mtJSON) then + S:=TROUtil.Frombase64(S); + Case DADS.DAConnection.StreamerType of + stJSON : DStr:=TDABIN2DataStreamer.new; + stBIN: DStr:=TDABIN2DataStreamer.new; + end; + DStr.Stream:=S; + DStr.initializeRead; + DT:=TDADataTable.New; + DStr.ReadDataset(DT); + Rows:=TJSArray.New; + for I:=0 to length(DT.rows)-1 do + Rows.Push(DT.Rows[i].__newValues); + (Dataset as TDADataset).Metadata:=New(['fields',TJSArray(DT.Fields)]); + // Data:=aJSON['data']; + (Dataset as TDADataset).Rows:=Rows; + Success:=rrOK; + DoAfterRequest; +end; + +end. diff --git a/packages/dataabstract/dasdk.pas b/packages/dataabstract/dasdk.pas new file mode 100644 index 0000000..b532194 --- /dev/null +++ b/packages/dataabstract/dasdk.pas @@ -0,0 +1,217 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2018 by Michael Van Canneyt, member of the + Free Pascal development team + + Remobjects Data Abstract external classes definitions + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} +unit dasdk; + +{$mode objfpc} +{$modeswitch externalclass} + +interface + +uses JS, ROSDK; + +Type + TDAUserInfo = Class; + TDASuccessEvent = Procedure (res : JSValue) of object; + TDAFailedEvent = Procedure (response : TJSOBject; fail : String) of object; + + TDALoginSuccessEvent = Reference to Procedure (result : Boolean; UserInfo : TDAUserInfo); + + TDABaseLoginService = class external name 'RemObjects.DataAbstract.Server.SimpleLoginService' (TJSObject) + Public + Constructor new(ch : TROHTTPClientChannel; msg : TROMessage; aServiceName : string); + Procedure LoginEx(aLoginString :String; aSuccess : TDALoginSuccessEvent; aFailure : TDAFailedEvent); + Procedure Logout(aSuccess : TDASuccessEvent; aFailure : TDAFailedEvent); + end; + + TDASimpleLoginService = class external name 'RemObjects.DataAbstract.Server.SimpleLoginService' (TDABaseLoginService) + Public + Procedure Login(aUserId,aPassword :String; aSuccess : TDALoginSuccessEvent; aFailure : TDAFailedEvent); + end; + + TDAStringArray = class external name 'RemObjects.DataAbstract.Server.StringArray' + Public + constructor new; + procedure fromObject(aItems : array of string); overload; + end; + + TDADataParameterData = Record + Name: string; + Value : JSValue; + End; + TDADataParameterDataArray = array of TDADataParameterData; + + TDADataParameter = class external name 'RemObjects.DataAbstract.Server.DataParameter' (TROStructType) + Public + constructor new; + Procedure fromObject(aItem : TDADataParameterData); overload; + Public + Name : TROValue; + Value : TROValue; + end; + + TDADataParameterArray = class external name 'RemObjects.DataAbstract.Server.DataParameterArray' (TROArrayType) + Public + constructor new; + Procedure fromObject(aItems : Array of TDADataParameterData); overload; + function toObject : TDADataParameterDataArray; reintroduce; + Public + items : Array of TDADataParameter; + end; + + TDAColumnSortingData = record + FieldName : String; + SortDirection : String; + end; + TDAColumnSortingDataArray = Array of TDAColumnSortingData; + + TDAColumnSorting = class external name 'RemObjects.DataAbstract.Server.ColumnSorting' (TROStructType) + Public + FieldName : TROValue; + Direction : TROValue; + end; + + TDAColumnSortingArray = class external name 'RemObjects.DataAbstract.Server.ColumnSortingArray' (TROArrayType) + Public + constructor new; + Procedure fromObject(aItems : Array of TDAColumnSortingData); overload; + function toObject : TDAColumnSortingDataArray; reintroduce; + Public + items : Array of TDAColumnSorting; + end; + + TDATableRequestInfoData = record + IncludeSchema : boolean; + MaxRecords : Integer; + Parameters : TDADataParameterDataArray; + UserFilter : String; + end; + TDATableRequestInfoDataArray = array of TDATableRequestInfoData; + + TDATableRequestInfo = class external name 'RemObjects.DataAbstract.Server.TableRequestInfo' (TROStructType) + Public + constructor new; + procedure fromObject(aItem : TDATableRequestInfoData);reintroduce; overload; + procedure fromObject(aItem : TJSObject);reintroduce; overload; + Function toObject : TDATableRequestInfoData; reintroduce; + Public + IncludeSchema : TROValue; + MaxRecords : TROValue; + Parameters : TROValue; + UserFilter : TROValue; + end; + + TDATableRequestInfoV5Data = record + DynamicSelectFieldNames : Array of string; + IncludeSchema : boolean; + MaxRecords : Integer; + Parameters : Array of TDADataParameterData; + UserFilter : String; + Sorting : TDAColumnSortingData; + WhereClause : String; + end; + + TDATableRequestInfoV5 = class external name 'RemObjects.DataAbstract.Server.TableRequestInfoV5' (TROStructType) + Public + constructor new; + procedure fromObject(aItem : TDATableRequestInfoV5Data);reintroduce;overload; + procedure fromObject(aItem : TJSObject);reintroduce;overload; + function toObject : TDATableRequestInfoV5Data;reintroduce; + Public + DynamicSelectFieldNames : TROValue; + IncludeSchema : TROValue; + MaxRecords : TROValue; + Parameters : TROValue; + UserFilter : TROValue; + Sorting : TROValue; + WhereClause : TROValue; + end; + + TDATableRequestInfoV6Data = record + IncludeSchema : boolean; + MaxRecords : Integer; + Parameters : Array of TDADataParameterData; + SQL : String; + UserFilter : String; + end; + + TDATableRequestInfoV6 = class external name 'RemObjects.DataAbstract.Server.TableRequestInfoV6' (TROStructType) + Public + constructor new; + procedure fromObject(aItem : TDATableRequestInfoData);reintroduce;overload; + procedure fromObject(aItem : TJSObject);reintroduce;overload; + function toObject : TDATableRequestInfoV6Data;reintroduce; + Public + IncludeSchema : TROValue; + MaxRecords : TROValue; + Parameters : TDADataParameterArray; + Sql : TROValue; + UserFilter : TROValue; + end; + + TDAUserInfoData = record + Attributes : array of JSValue; + Privileges : Array of string; + SessionID : String; + UserData : JSValue; + UserID : String; + end; + + TDAUserInfo = class external name 'RemObjects.DataAbstract.Server.UserInfo' (TROStructType) + constructor new; + procedure fromObject(aItem : TDAUserInfo);reintroduce; overload; + procedure fromObject(aItem : TJSObject);reintroduce; overload; + function toObject : TDAUserInfoData;reintroduce; + Public + Attributes : TROValue; + Privileges : TROValue; + SessionID : TROValue; + UserData : TROValue; + UserID : TROValue; + end; + + TDATableRequestInfoArray = class external name 'RemObjects.DataAbstract.Server.TableRequestInfoArray' (TROArrayType) + Public + constructor new; + procedure fromObject(aItems : Array of TDATableRequestInfoData);overload; + procedure fromObject(aItems : Array of TDATableRequestInfoV5Data);overload; + procedure fromObject(aItems : Array of TDATableRequestInfoV6Data);overload; + procedure fromObject(aItems : array of TJSObject);overload; + Public + items : array of TDATableRequestInfo; + end; + + TDADataAbstractService = class external name 'RemObjects.DataAbstract.Server.DataAbstractService' + Public + Constructor new(ch : TROHTTPClientChannel; msg : TROMessage; aServiceName : string); + Procedure GetSchema(aFilter : String; aSuccess : TDASuccessEvent; aFailure : TDAFailedEvent); + Procedure GetData(aTables : TDAStringArray; info : TDATableRequestInfoArray; aSuccess : TDASuccessEvent; aFailure : TDAFailedEvent); + Procedure UpdateData(aDelta : String; aSuccess : TDASuccessEvent; aFailure : TDAFailedEvent); + Procedure ExecuteCommand(aCommandName : String; params : TDADataParameterArray; aSuccess : TDASuccessEvent; aFailure : TDAFailedEvent); + Procedure ExecuteCommandEx(aCommandName : String; params : TDADataParameterArray; aSuccess : TDASuccessEvent; aFailure : TDAFailedEvent); + Procedure GetTableSchema(aTableNameArray : TDAStringArray;aSuccess : TDASuccessEvent; aFailure : TDAFailedEvent); + Procedure GetCommandSchema(aCommandNameArray : TDAStringArray;aSuccess : TDASuccessEvent; aFailure : TDAFailedEvent); + Procedure GetSQLData(aSQLText : String; aIncludeSchema : Boolean; aMaxRecords : Integer; aSuccess : TDASuccessEvent; aFailure : TDAFailedEvent); + Procedure GetSQLDataEx(aSQLText : String; aIncludeSchema : Boolean; aMaxRecords : Integer; aDynamicWhereXML : String; aSuccess : TDASuccessEvent; aFailure : TDAFailedEvent); + Procedure SQLExecuteCommand(aSQLText : String; aSuccess : TDASuccessEvent; aFailure : TDAFailedEvent); + Procedure SQLExecuteCommandEx(aSQLText,aDynamicWhereXML : String; aSuccess : TDASuccessEvent; aFailure : TDAFailedEvent); + Procedure getDatasetScripts(DatasetNames : String; aSuccess : TDASuccessEvent; aFailure : TDAFailedEvent); + Procedure RegisterForDataChangeNotification(aTableName : String; aSuccess : TDASuccessEvent; aFailure : TDAFailedEvent); + Procedure UnregisterForDataChangeNotification(aTableName : String; aSuccess : TDASuccessEvent; aFailure : TDAFailedEvent); + end; + +implementation + +end. diff --git a/packages/dataabstract/rosdk.pas b/packages/dataabstract/rosdk.pas new file mode 100644 index 0000000..9cf875e --- /dev/null +++ b/packages/dataabstract/rosdk.pas @@ -0,0 +1,211 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2018 by Michael Van Canneyt, member of the + Free Pascal development team + + Remobjects SDK external classes definitions + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} +unit ROSDK; + +{$mode objfpc} +{$modeswitch externalclass} + +interface + +uses + Types, JS; + +Type + TROValue = record + dataType : string; + value : JSValue; + end; + TROComplexType = class; + TROEnumType = class; + TROStructType = class; + TROArrayType = class; + TROException = class; + TROEventSink = class; + TROClientChannel = class; + TROHTTPClientChannel = class; + TROMessage = class; + TROJSONMessage = class; + TROBinMessage = class; + TROBinHeader = class; + TRORemoteService = class; + TROService = class; + TROEventReceiver = class; + + TROUtil = class external name 'RemObjects.UTIL' (TJSObject) + Public + class function toBase64 (Const aValue : String) : String; + class function fromBase64 (Const aValue : String) : String; + class procedure showMessage (Const msg : string); + class procedure showError(Const msg : string; e : JSValue); + class function toJSON(aValue : jsValue) : String; + class function parseJSON (Const aValue : string) : JSValue; + class function NewGuid() : string; + class function GuidToArray(Const aGuid : string) : TIntegerDynArray; + class function guidToByteArray(Const aGuid : string): String; + class function zeroPad(const num : string; count : integer) : String; + class function byteArrayToGuid(const byteArray : string) : String; + class function strToByteArray (const str : string) : string; + class function byteArrayToStr(const byteArray : string) : string; + class function byteArrayToUtf16(const byteArray : string) : string; + class function utf16ToByteArray(const str : string) : string; + class function ISO8601toDateTime(const str: String) : TJSDate; + class function dateTimeToSOAPString(aValue: TJSDate) : string; + class function decimalToString(aDecimal : array of integer ) : string; + class function stringToDecimal(const aString : String) : TIntegerDynArray; + class Function checkArgumentTypes (args : Array of JSValue; types : array of string) : Boolean; + end; + + + TROException = class external name 'RemObjects.SDK.ROException' (TJSError); + + TROComplexType = class external name 'RemObjects.SDK.ROComplexType' (TJSObject) + Public + Procedure readFrom(aMessage : TROMessage); + Procedure writeTo(aMessage : TROMessage); + end; + + TROEnumType = class external name 'RemObjects.SDK.ROEnumType' (TROComplexType) + Public + Procedure fromObject(aObject : TJSObject); overload; + Function toObject(aStoreType : Boolean) : TJSObject;overload; + end; + + TROStructType = class external name 'RemObjects.SDK.ROStructType' (TROComplexType) + Public + Procedure fromObject(aObject : TJSObject);overload; + Function toObject(aStoreType : Boolean) : TJSObject;overload; + end; + + TROArrayType = class external name 'RemObjects.SDK.ROArrayType' (TROComplexType) + Public + Procedure fromObject(aObject : Array of TJSObject);overload; + Function toObject(aStoreType : Boolean) : TJSObjectDynArray;overload; + end; + + TRODispatchSuccessEvent = reference to Procedure (msg : TROMessage); + TRODispatchFailedEvent = reference to Procedure (msg : TROMessage; aError : TJSError); + TROCallBack = Procedure; + TROOnLoginNeeded = reference to procedure(aCallBack : TROCallBack); + + TROClientChannel = class external name 'RemObjects.SDK.ClientChannel' (TJSObject) + Public + onLoginNeeded : TROOnLoginNeeded; + Public + Constructor new(aURL : String); + Procedure dispatch(aMessage : TROMessage; onSuccess : TRODispatchSuccessEvent; OnError : TRODispatchFailedEvent); + end; + + + TROHTTPCallback = reference to procedure (aResponse : String; aStatus : Integer); + TROHTTPClientChannel = class external name 'RemObjects.SDK.HTTPClientChannel' (TROClientChannel) + Public + Procedure post(aMessage : TROMessage; isBinary : Boolean; OnSuccess,OnError : TROHTTPCallback); + end; + + TROEventSink = class external name 'RemObjects.SDK.ROEventSink' (TJSObject) + Public + Procedure readEvent(aMessage : TROMessage; aName : string); + end; + + + TROMessage = class external name 'RemObjects.SDK.Message' (TJSObject) + Public + constructor new; + Function Clone : TROMessage; + function getClientID : String; + procedure setClientID(const aValue : String); + function getErrorMessage : String; + procedure setErrorResponse (Const aResponse : String); + Procedure initialize (Const aServiceName,aMethodName : string; aMessageType : Integer); + Procedure finalize; + function requestStream : String; // Dummy + procedure setResponseStream(const aValue : String); + function read (const aName,aType : String) : TROValue; + Procedure write (const aName,aType : String; aValue : JSValue); + Property ClientID : String Read getClientID Write setClientID; + end; + + TROJSONMessage = class external name 'RemObjects.SDK.JSONMessage' (TROMessage) + end; + + TROBinHeader = class external name 'RemObjects.SDK.BinHeader' (TJSObject) + Public + function asStream: String; + Procedure ReadFrom(aStream : String); + function isValidHeader : Boolean; + function getCompressed : Boolean; + Procedure setCompressed(aValue : Boolean); + function getMessageType : integer; + Procedure setMessageType(aValue : integer); + procedure setClientID(aValue : String); + Property Compressed : Boolean Read getCompressed Write setCompressed; + Property MessageType : Integer Read getMessageType write SetMessageType; + end; + + TROBinMessage = class external name 'RemObjects.SDK.BinMessage' (TROMessage) + public + constructor new; + Procedure writeVariant(aValue : JSValue); + Procedure writeinteger(aValue : Integer); + Procedure writeStrWithLength(aValue : string); + function readByte : Byte; + function readCompressed : String; + function readVariant : JSValue; + end; + + TROEventCallback = reference to procedure (event : TJSObject); // Or TROComplexType ? + + TROEventReceiver = class external name 'RemObjects.SDK.ROEventReceiver' (TJSObject) + Public + Constructor new(aChannel : TROClientChannel; aMessage : TROMessage; aServiceName : string; aTimeOut : Integer); + Procedure addHandler(anEventName : String; aCallback : TROEventCallback); + Procedure setActive(aValue : boolean); + function getActive : Boolean; + function getTimeout : integer; + procedure setTimeout(aValue : Integer); + Procedure intPollServer; + Property Active : Boolean Read GetActive Write SetActive; + Property TimeOut : Integer read GetTimeOut Write SetTimeout; + end; + + TRORemoteService = Class external name 'RemObjects.SDK.RemoteService' (TJSObject) + Constructor new(aChannel : TROClientChannel; aMessage : TROMessage; aServiceName : string); + end; + + TROService = Class external name 'RemObjects.SDK.ROService' (TJSObject) + Public + Constructor new(aService : TRORemoteService); + Constructor new(aChannel : TROClientChannel; aMessage : TROMessage; aServiceName : string); + function getMessage : TROMessage; + function getChannel : TROClientChannel; + function getServiceName : String; + Property Message : TROMessage Read getMessage; + Property Channel : TROClientChannel Read getChannel; + Property ServiceName : String Read getServiceName; + end; + + TROBinaryParser = Class external name 'BinaryParser' (TJSObject) + procedure warn; + function decodeFloat(data : JSValue; precisionbits,exponentbits :Integer) : double; + function encodeFloat(value: double; precisionbits,exponentbits :Integer) : string; + function decodeInt(data : JSValue; bits : Integer; Signed : boolean) : NativeInt; + function encodeInt(data : NativeInt; bits : Integer; Signed : boolean) : String; + end; + +implementation + +end. +