summaryrefslogtreecommitdiff
path: root/js/src/Ice/Operation.js
diff options
context:
space:
mode:
authorMark Spruiell <mes@zeroc.com>2014-03-19 12:45:55 -0700
committerMark Spruiell <mes@zeroc.com>2014-03-19 12:45:55 -0700
commitcdcffbcc3c3c052afdeb772ff0167e7a90b525bb (patch)
tree4f16ee41ef7d33394c44e9db81e4d6cd89908250 /js/src/Ice/Operation.js
parentfixing testicedist.py for 5487 (diff)
downloadice-cdcffbcc3c3c052afdeb772ff0167e7a90b525bb.tar.bz2
ice-cdcffbcc3c3c052afdeb772ff0167e7a90b525bb.tar.xz
ice-cdcffbcc3c3c052afdeb772ff0167e7a90b525bb.zip
merging javascript branch
Diffstat (limited to 'js/src/Ice/Operation.js')
-rw-r--r--js/src/Ice/Operation.js773
1 files changed, 773 insertions, 0 deletions
diff --git a/js/src/Ice/Operation.js b/js/src/Ice/Operation.js
new file mode 100644
index 00000000000..11a130f542f
--- /dev/null
+++ b/js/src/Ice/Operation.js
@@ -0,0 +1,773 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+(function(global){
+ require("Ice/Class");
+ require("Ice/Current");
+ require("Ice/DispatchStatus");
+ require("Ice/Exception");
+ require("Ice/FormatType");
+ require("Ice/Object");
+ require("Ice/ObjectPrx");
+ require("Ice/OptionalFormat");
+ require("Ice/StreamHelpers");
+
+ var Ice = global.Ice || {};
+ var Slice = global.Slice || {};
+
+ /*jshint -W069 */
+
+ var Class = Ice.Class;
+
+ var builtinHelpers =
+ [
+ Ice.ByteHelper,
+ Ice.BoolHelper,
+ Ice.ShortHelper,
+ Ice.IntHelper,
+ Ice.LongHelper,
+ Ice.FloatHelper,
+ Ice.DoubleHelper,
+ Ice.StringHelper,
+ Ice.Object,
+ Ice.ObjectPrx
+ ];
+
+ function parseParam(p)
+ {
+ var type = p[0];
+ var t = typeof(type);
+ if(t === 'number')
+ {
+ type = builtinHelpers[p[0]];
+ }
+ else if(t === 'string')
+ {
+ /*jshint -W061 */
+ type = eval(type);
+ /*jshint +W061 */
+ }
+
+ return {
+ "type": type,
+ "isObject": (p[1] === true),
+ "tag": p[2] // Optional tag, which may not be present - an undefined tag means "not optional".
+ };
+ }
+
+ //
+ // Each operation descriptor is a property. The key is the "on-the-wire"
+ // name, and the value is an array consisting of the following elements:
+ //
+ // 0: native method name in case of a keyword conflict (e.g., "_while"),
+ // otherwise an empty string
+ // 1: mode (undefined == Normal or int)
+ // 2: sendMode (undefined == Normal or int)
+ // 3: amd (undefined or 1)
+ // 4: format (undefined == Default or int)
+ // 5: return type (undefined if void, or [type, tag])
+ // 6: in params (undefined if none, or array of [type, tag])
+ // 7: out params (undefined if none, or array of [type, tag])
+ // 8: exceptions (undefined if none, or array of types)
+ // 9: sends classes (true or undefined)
+ // 10: returns classes (true or undefined)
+ //
+ function parseOperation(name, arr)
+ {
+ var r = {};
+ var i;
+ var p;
+
+ r["name"] = name;
+ r["mode"] = arr[1] ? Ice.OperationMode.valueOf(arr[1]) : Ice.OperationMode.Normal;
+ r["sendMode"] = arr[2] ? Ice.OperationMode.valueOf(arr[2]) : Ice.OperationMode.Normal;
+ r["amd"] = arr[3] ? true : false;
+ r["format"] = arr[4] ? Ice.FormatType.valueOf(arr[4]) : Ice.FormatType.DefaultFormat;
+
+ if(r["amd"])
+ {
+ r["servantMethod"] = name + "_async";
+ }
+ else
+ {
+ r["servantMethod"] = arr[0] ? arr[0] : name;
+ }
+
+ var ret;
+ if(arr[5])
+ {
+ ret = parseParam(arr[5]);
+ ret["pos"] = 0;
+ }
+ r["returns"] = ret;
+
+ var inParams = [];
+ var inParamsOpt = [];
+ if(arr[6])
+ {
+ for(i = 0; i < arr[6].length; ++i)
+ {
+ p = parseParam(arr[6][i]);
+ p["pos"] = i;
+ inParams.push(p);
+ if(p.tag)
+ {
+ inParamsOpt.push(p);
+ }
+ }
+ }
+ inParamsOpt.sort(function(p1, p2) { return p1.tag - p2.tag; }); // Sort by tag.
+ r["inParams"] = inParams;
+ r["inParamsOpt"] = inParamsOpt;
+
+ var outParams = [];
+ var outParamsOpt = [];
+ if(arr[7])
+ {
+ var offs = ret ? 1 : 0;
+ for(i = 0; i < arr[7].length; ++i)
+ {
+ p = parseParam(arr[7][i]);
+ p["pos"] = i + offs;
+ outParams.push(p);
+ if(p.tag)
+ {
+ outParamsOpt.push(p);
+ }
+ }
+ }
+ if(ret && ret.tag)
+ {
+ outParamsOpt.push(ret);
+ }
+ outParamsOpt.sort(function(p1, p2) { return p1.tag - p2.tag; }); // Sort by tag.
+ r["outParams"] = outParams;
+ r["outParamsOpt"] = outParamsOpt;
+
+ var exceptions = [];
+ if(arr[8])
+ {
+ for(i = 0; i < arr[8].length; ++i)
+ {
+ exceptions.push(arr[8][i]);
+ }
+ }
+ r["exceptions"] = exceptions;
+
+ r["sendsClasses"] = arr[9] === true;
+ r["returnsClasses"] = arr[10] === true;
+
+ return r;
+ }
+
+ var OpTable = Class({
+ __init__: function(ops)
+ {
+ this.raw = ops;
+ this.parsed = {};
+ },
+ find: function(name)
+ {
+ //
+ // Check if we've already parsed the operation.
+ //
+ var op = this.parsed[name];
+ if(op === undefined && this.raw[name] !== undefined)
+ {
+ //
+ // We haven't parsed it yet, but we found a match for the name, so parse it now.
+ //
+ op = parseOperation(name, this.raw[name]);
+ this.parsed[name] = op;
+ }
+ return op;
+ }
+ });
+
+ function unmarshalParams(is, retvalInfo, allParamInfo, optParamInfo, usesClasses, params, offset)
+ {
+ var i, p, v;
+ //
+ // First read all required params.
+ //
+ for(i = 0; i < allParamInfo.length; ++i)
+ {
+ p = allParamInfo[i];
+ if(!p.tag)
+ {
+ v = p.type.read(is);
+ params[p.pos + offset] = v;
+ }
+ }
+
+ //
+ // Then read a required return value (if any).
+ //
+ if(retvalInfo)
+ {
+ v = retvalInfo.type.read(is);
+ params[retvalInfo.pos + offset] = v;
+ }
+
+ //
+ // Then read all optional params.
+ //
+ for(i = 0; i < optParamInfo.length; ++i)
+ {
+ p = optParamInfo[i];
+ v = p.type.readOpt(is, p.tag);
+ params[p.pos + offset] = v;
+ }
+
+ if(usesClasses)
+ {
+ is.readPendingObjects();
+ }
+ }
+
+ function marshalParams(os, params, retvalInfo, paramInfo, optParamInfo, usesClasses)
+ {
+ var i, p;
+
+ //
+ // Write the required params.
+ //
+ for(i = 0; i < paramInfo.length; ++i)
+ {
+ p = paramInfo[i];
+ if(!p.tag)
+ {
+ p.type.write(os, params[p.pos]);
+ }
+ }
+
+ //
+ // retvalInfo should only be provided if there is a non-void required return value.
+ //
+ if(retvalInfo)
+ {
+ retvalInfo.type.write(os, params[retvalInfo.pos]);
+ }
+
+ //
+ // Write the optional params.
+ //
+ for(i = 0; i < optParamInfo.length; ++i)
+ {
+ p = optParamInfo[i];
+ p.type.writeOpt(os, p.tag, params[p.pos]);
+ }
+
+ if(usesClasses)
+ {
+ os.writePendingObjects();
+ }
+ }
+
+ var Upcall = Class({
+ __init__: function(incomingAsync, op)
+ {
+ this.incomingAsync = incomingAsync;
+ this.op = op;
+ },
+ ice_response: function()
+ {
+ var args = arguments;
+
+ if(this.incomingAsync.__validateResponse(true))
+ {
+ try
+ {
+ this.__sendResponse(args);
+ this.incomingAsync.__response();
+ }
+ catch(ex)
+ {
+ this.incomingAsync.__exception(ex);
+ }
+ }
+ },
+ ice_exception: function(ex)
+ {
+ if(this.__checkException(ex))
+ {
+ if(this.incomingAsync.__validateResponse(false))
+ {
+ this.__sendException(ex);
+ this.incomingAsync.__response();
+ }
+ }
+ else
+ {
+ this.incomingAsync.ice_exception(ex);
+ }
+ },
+ __sendResponse: function(results)
+ {
+ if(this.op.returns === undefined && this.op.outParams.length === 0)
+ {
+ if(results && results.length > 0)
+ {
+ //
+ // No results expected.
+ //
+ throw new Error("ice_response called with invalid arguments");
+ }
+ else
+ {
+ this.incomingAsync.__writeEmptyParams();
+ }
+ }
+ else
+ {
+ var __os = this.incomingAsync.__startWriteParams(this.op.format);
+ var retvalInfo;
+ if(this.op.returns && !this.op.returns.tag)
+ {
+ retvalInfo = this.op.returns;
+ }
+ marshalParams(__os, results, retvalInfo, this.op.outParams, this.op.outParamsOpt,
+ this.op.returnsClasses);
+ this.incomingAsync.__endWriteParams(true);
+ }
+ },
+ __checkException: function(ex)
+ {
+ //
+ // Make sure the given exception is an instance of one of the declared user exceptions
+ // for this operation.
+ //
+ for(var i = 0; i < this.op.exceptions.length; ++i)
+ {
+ if(ex instanceof this.op.exceptions[i])
+ {
+ //
+ // User exception is valid.
+ //
+ return true;
+ }
+ }
+
+ return false;
+ },
+ __sendException: function(ex)
+ {
+ //
+ // User exception is valid, now marshal it.
+ //
+ this.incomingAsync.__writeUserException(ex, this.op.format);
+ }
+ });
+
+ var __dispatchImpl = function(servant, op, incomingAsync, current)
+ {
+ //
+ // Check to make sure the servant implements the operation.
+ //
+ var method = servant[op.servantMethod];
+ if(method === undefined || typeof(method) !== "function")
+ {
+ var comm = current.adapter.getCommunicator();
+ var msg = "servant for identity " + comm.identityToString(current.id) +
+ " does not define operation `" + op.servantMethod + "'";
+ console.log(msg);
+ throw new Ice.UnknownException(msg);
+ }
+
+ var up = new Upcall(incomingAsync, op);
+
+ try
+ {
+ //
+ // Unmarshal the in params (if any).
+ //
+ var params = op.amd ? [null] : [];
+ if(op.inParams.length === 0)
+ {
+ incomingAsync.readEmptyParams();
+ }
+ else
+ {
+ var __is = incomingAsync.startReadParams();
+ var offset = op.amd ? 1 : 0;
+ unmarshalParams(__is, undefined, op.inParams, op.inParamsOpt, op.sendsClasses, params, offset);
+ incomingAsync.endReadParams();
+
+ //
+ // When unmarshaling objects, the ObjectHelper returns a wrapper object
+ // and eventually stores the unmarshaled object into its "value" member.
+ // Here we scan the parameter array and replace the wrappers with the
+ // actual object references.
+ //
+ if(op.inParams.length > 0 && (op.sendsClasses || op.inParamsOpt.length > 0))
+ {
+ for(var i = 0; i < op.inParams.length; ++i)
+ {
+ var p = op.inParams[i];
+ //
+ // Optional parameters may be undefined.
+ //
+ if(p.isObject && params[p.pos + offset] !== undefined)
+ {
+ params[p.pos + offset] = params[p.pos + offset].value;
+ }
+ }
+ }
+ }
+
+ params.push(current);
+
+ if(op.amd)
+ {
+ params[0] = up; // The AMD callback object.
+ try
+ {
+ method.apply(servant, params);
+ }
+ catch(ex)
+ {
+ up.ice_exception(ex);
+ }
+ return Ice.DispatchStatus.DispatchAsync;
+ }
+ else
+ {
+ //
+ // Determine how many out parameters to expect.
+ //
+ var numExpectedResults = op.outParams.length;
+ if(op.returns)
+ {
+ ++numExpectedResults;
+ }
+
+ var results = method.apply(servant, params);
+
+ //
+ // Complain if we expect more than out parameter and the servant doesn't return an array.
+ //
+ if(numExpectedResults > 1 && !(results instanceof Array))
+ {
+ var msg = "operation `" + op.servantMethod + "' should return an array of length " + numParams;
+ console.log(msg);
+ throw new Ice.MarshalException(msg);
+ }
+ else if(numExpectedResults === 1)
+ {
+ //
+ // Wrap a single out parameter in an array.
+ //
+ results = [results];
+ }
+
+ up.__sendResponse(results);
+ return Ice.DispatchStatus.DispatchOK;
+ }
+ }
+ catch(ex)
+ {
+ if(up.__checkException(ex))
+ {
+ up.__sendException(ex);
+ return Ice.DispatchStatus.DispatchUserException;
+ }
+ else
+ {
+ throw ex;
+ }
+ }
+ };
+
+ function getServantMethodFromInterfaces(interfaces, methodName, all)
+ {
+ var method;
+ for(var i = 0; method === undefined && i < interfaces.length; ++i)
+ {
+ var intf = interfaces[i];
+ method = intf[methodName];
+ if(method === undefined)
+ {
+ if(all.indexOf(intf) === -1)
+ {
+ all.push(intf);
+ }
+ if(intf.__implements)
+ {
+ method = getServantMethodFromInterfaces(intf.__implements, methodName, all);
+ }
+ }
+ }
+ return method;
+ }
+
+ var dispatchPrefix = "__op_";
+
+ function getServantMethod(servantType, name)
+ {
+ //
+ // The dispatch method is named __op_<Slice name> and is stored in the type (not the prototype).
+ //
+ var methodName = dispatchPrefix + name;
+
+ //
+ // First check the servant type.
+ //
+ var method = servantType[methodName];
+
+ var allInterfaces;
+
+ if(method === undefined)
+ {
+ allInterfaces = [];
+
+ //
+ // Now check the prototypes of the implemented interfaces.
+ //
+ var curr = servantType;
+ while(curr && method === undefined)
+ {
+ if(curr.__implements)
+ {
+ method = getServantMethodFromInterfaces(curr.__implements, methodName, allInterfaces);
+ }
+ curr = curr.__parent;
+ }
+
+ if(method !== undefined)
+ {
+ //
+ // Add the method to the servant's type.
+ //
+ servantType[methodName] = method;
+ }
+ }
+
+ if(method === undefined)
+ {
+ //
+ // Next check the op table for the servant's type.
+ //
+ var op;
+ if(servantType.__ops)
+ {
+ op = servantType.__ops.find(name);
+ }
+
+ var source;
+ if(op === undefined)
+ {
+ //
+ // Now check the op tables of the base types.
+ //
+ var parent = servantType.__parent;
+ while(op === undefined && parent)
+ {
+ if(parent.__ops)
+ {
+ if((op = parent.__ops.find(name)) !== undefined)
+ {
+ source = parent;
+ }
+ }
+ parent = parent.__parent;
+ }
+
+ //
+ // Now check the op tables of all base interfaces.
+ //
+ for(var i = 0; op === undefined && i < allInterfaces.length; ++i)
+ {
+ var intf = allInterfaces[i];
+ if(intf.__ops)
+ {
+ if((op = intf.__ops.find(name)) !== undefined)
+ {
+ source = intf;
+ }
+ }
+ }
+ }
+
+ if(op !== undefined)
+ {
+ method = function(servant, incomingAsync, current)
+ {
+ return __dispatchImpl(servant, op, incomingAsync, current);
+ };
+
+ //
+ // Add the method to the servant type.
+ //
+ servantType[methodName] = method;
+
+ //
+ // Also add the method to the type in which the operation was found.
+ //
+ if(source)
+ {
+ source[methodName] = method;
+ }
+ }
+ }
+
+ return method;
+ }
+
+ function addProxyOperation(proxyType, name, data)
+ {
+ var method = data[0] ? data[0] : name;
+
+ var op = null;
+
+ proxyType.prototype[method] = function()
+ {
+ var args = arguments;
+
+ //
+ // Parse the operation data on the first invocation of a proxy method.
+ //
+ if(op === null)
+ {
+ op = parseOperation(name, data);
+ }
+
+ var ctx = args[op.inParams.length]; // The request context is the last argument (if present).
+
+ var marshalFn = null;
+ if(op.inParams.length > 0)
+ {
+ marshalFn = function(os, params)
+ {
+ marshalParams(os, params, undefined, op.inParams, op.inParamsOpt, op.sendsClasses);
+ };
+ }
+
+ var unmarshalFn = null;
+ if(op.returns || op.outParams.length > 0)
+ {
+ unmarshalFn = function(asyncResult)
+ {
+ //
+ // The results array holds the out parameters in the following format:
+ //
+ // [retval, out1, out2, ..., asyncResult]
+ //
+ var results = [];
+
+ var is = asyncResult.__startReadParams();
+
+ var retvalInfo;
+ if(op.returns && !op.returns.tag)
+ {
+ retvalInfo = op.returns;
+ }
+ unmarshalParams(is, retvalInfo, op.outParams, op.outParamsOpt, op.returnsClasses, results, 0);
+
+ asyncResult.__endReadParams();
+
+ //
+ // When unmarshaling objects, the ObjectHelper returns a wrapper object
+ // and eventually stores the unmarshaled object into its "value" member.
+ // Here we scan the results array and replace the wrappers with the
+ // actual object references.
+ //
+ if(op.returnsClasses || op.outParamsOpt.length > 0)
+ {
+ var offset = 0; // Skip asyncResult in results.
+ if(op.returns && op.returns.isObject && results[op.returns.pos + offset] !== undefined)
+ {
+ results[op.returns.pos + offset] = results[op.returns.pos + offset].value;
+ }
+ for(var i = 0; i < op.outParams.length; ++i)
+ {
+ var p = op.outParams[i];
+ //
+ // Optional parameters may be undefined.
+ //
+ if(p.isObject && results[p.pos + offset] !== undefined)
+ {
+ results[p.pos + offset] = results[p.pos + offset].value;
+ }
+ }
+ }
+ results.push(asyncResult);
+ return results;
+ };
+ }
+
+ return Ice.ObjectPrx.__invoke(this, op.name, op.sendMode, op.format, ctx, marshalFn, unmarshalFn,
+ op.exceptions, Array.prototype.slice.call(args));
+ };
+ }
+
+ Slice.defineOperations = function(classType, proxyType, ops)
+ {
+ if(ops)
+ {
+ classType.__ops = new OpTable(ops);
+ }
+
+ classType.prototype.__dispatch = function(incomingAsync, current)
+ {
+ //
+ // Retrieve the dispatch method for this operation.
+ //
+ var method = getServantMethod(classType, current.operation);
+
+ if(method === undefined || typeof(method) !== 'function')
+ {
+ throw new Ice.OperationNotExistException(current.id, current.facet, current.operation);
+ }
+
+ return method.call(method, this, incomingAsync, current);
+ };
+
+ if(ops)
+ {
+ for(var name in ops)
+ {
+ addProxyOperation(proxyType, name, ops[name]);
+ }
+ }
+
+ //
+ // Copy proxy methods from super-interfaces.
+ //
+ if(proxyType.__implements)
+ {
+ for(var intf in proxyType.__implements)
+ {
+ var proto = proxyType.__implements[intf].prototype;
+ for(var f in proto)
+ {
+ if(typeof proto[f] == "function" && proxyType.prototype[f] === undefined)
+ {
+ proxyType.prototype[f] = proto[f];
+ }
+ }
+ }
+ }
+ };
+
+ //
+ // Define the "built-in" operations for all Ice objects.
+ //
+ Slice.defineOperations(Ice.Object, Ice.ObjectPrx,
+ {
+ "ice_ping": [, 1, 1, , , , , , ],
+ "ice_isA": [, 1, 1, , , [1], [[7]], , ],
+ "ice_id": [, 1, 1, , , [7], , , ],
+ "ice_ids": [, 1, 1, , , ["Ice.StringSeqHelper"], , , ]
+ });
+
+ global.Slice = Slice;
+ global.Ice = Ice;
+
+ /*jshint +W069 */
+}(typeof (global) === "undefined" ? window : global));