split JS components
[contrib/cloudeebus.git] / src / js / cloudeebus-proxy.js
1 /******************************************************************************
2  * Copyright 2012 - 2013 Intel Corporation.
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  * http://www.apache.org/licenses/LICENSE-2.0
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *****************************************************************************/
16
17
18
19 /*****************************************************************************/
20
21 cloudeebus.ProxyObject = function(session, busConnection, busName, objectPath) {
22         this.wampSession = session; 
23         this.busConnection = busConnection; 
24         this.busName = busName; 
25         this.objectPath = objectPath; 
26         this.interfaceProxies = {};
27         this.childNodeNames = [];
28         return this;
29 };
30
31
32 cloudeebus.ProxyObject.prototype.getInterface = function(ifName) {
33         return this.interfaceProxies[ifName];
34 };
35
36
37 cloudeebus.ProxyObject.prototype._introspect = function(successCB, errorCB) {
38         
39         var self = this; 
40
41         function getAllPropertiesSuccessCB(props) {
42                 var ifProxy = self.interfaceProxies[self.propInterfaces[self.propInterfaces.length-1]];
43                 for (var prop in props)
44                         ifProxy[prop] = self[prop] = props[prop];
45                 getAllPropertiesNextInterfaceCB();
46         }
47         
48         function getAllPropertiesNextInterfaceCB() {
49                 self.propInterfaces.pop();
50                 if (self.propInterfaces.length > 0) 
51                         self.callMethod("org.freedesktop.DBus.Properties", 
52                                 "GetAll", 
53                                 [self.propInterfaces[self.propInterfaces.length-1]]).then(getAllPropertiesSuccessCB, 
54                                 errorCB ? errorCB : getAllPropertiesNextInterfaceCB);
55                 else {
56                         self.propInterfaces = null;
57                         if (successCB)
58                                 successCB(self);
59                 }
60         }
61         
62         function introspectSuccessCB(str) {
63                 var parser = new DOMParser();
64                 var xmlDoc = parser.parseFromString(str, "text/xml");
65                 var nodes = xmlDoc.getElementsByTagName("node");
66                 // first node is the parent/head node
67                 for(var i=1; i < nodes.length; i++)
68                         self.childNodeNames.push(nodes[i].getAttribute("name"));
69                 var interfaces = xmlDoc.getElementsByTagName("interface");
70                 self.propInterfaces = [];
71                 var supportDBusProperties = false;
72                 for (var i=0; i < interfaces.length; i++) {
73                         var ifName = interfaces[i].attributes.getNamedItem("name").value;
74                         self.interfaceProxies[ifName] = new cloudeebus.ProxyObject(self.wampSession, self.busConnection, self.busName, self.objectPath);
75                         if (ifName == "org.freedesktop.DBus.Properties")
76                                 supportDBusProperties = true;
77                         var hasProperties = false;
78                         var ifChild = interfaces[i].firstChild;
79                         while (ifChild) {
80                                 if (ifChild.nodeName == "method") {
81                                         var nArgs = 0;
82                                         var signature = "";
83                                         var metChild = ifChild.firstChild;
84                                         while (metChild) {
85                                                 if (metChild.nodeName == "arg" &&
86                                                         metChild.attributes.getNamedItem("direction").value == "in") {
87                                                                 signature += metChild.attributes.getNamedItem("type").value;
88                                                                 nArgs++;
89                                                 }
90                                                 metChild = metChild.nextSibling;
91                                         }
92                                         var metName = ifChild.attributes.getNamedItem("name").value;
93                                         if (!self[metName])
94                                                 self._addMethod(ifName, metName, nArgs, signature);
95                                         self.interfaceProxies[ifName]._addMethod(ifName, metName, nArgs, signature);
96                                 }
97                                 else if (ifChild.nodeName == "property") {
98                                         if (!hasProperties)
99                                                 self.propInterfaces.push(ifName);
100                                         hasProperties = true;
101                                 }
102                                 ifChild = ifChild.nextSibling;
103                         }
104                 }
105                 if (supportDBusProperties && self.propInterfaces.length > 0) {
106                         self.callMethod("org.freedesktop.DBus.Properties", 
107                                 "GetAll", 
108                                 [self.propInterfaces[self.propInterfaces.length-1]]).then(getAllPropertiesSuccessCB, 
109                                 errorCB ? errorCB : getAllPropertiesNextInterfaceCB);
110                 }
111                 else {
112                         self.propInterfaces = null;
113                         if (successCB)
114                                 successCB(self);
115                 }
116         }
117
118         // call Introspect on self
119         self.callMethod("org.freedesktop.DBus.Introspectable", "Introspect", []).then(introspectSuccessCB, errorCB);
120 };
121
122
123 cloudeebus.ProxyObject.prototype._addMethod = function(ifName, method, nArgs, signature) {
124
125         var self = this;
126         
127         self[method] = function() {
128                 var args = [];
129                 for (var i=0; i < nArgs; i++ )
130                         args.push(arguments[i]);
131                 return self.callMethod(ifName, method, args, signature);
132         };      
133 };
134
135
136 cloudeebus.ProxyObject.prototype.callMethod = function(ifName, method, args, signature) {
137         
138         var self = this;
139         
140         var promise = new cloudeebus.Promise(function (resolver) {
141                 function callMethodSuccessCB(str) {
142                         try { // calling dbus hook object function for un-translated types
143                                 var result = eval(str);
144                                 resolver.fulfill(result[0], true);
145                         }
146                         catch (e) {
147                                 var errorStr = cloudeebus.getError(e);
148                                 cloudeebus.log("Method callback exception: " + errorStr);
149                                 resolver.reject(errorStr, true);
150                         }
151                 }
152
153                 function callMethodErrorCB(error) {
154                         var errorStr = cloudeebus.getError(error);
155                         cloudeebus.log("Error calling method: " + method + " on object: " + self.objectPath + " : " + errorStr);
156                         resolver.reject(errorStr, true);
157                 }
158
159                 var arglist = [
160                         self.busConnection.name,
161                         self.busName,
162                         self.objectPath,
163                         ifName,
164                         method,
165                         JSON.stringify(args)
166                 ];
167
168                 // call dbusSend with bus type, destination, object, message and arguments
169                 self.wampSession.call("dbusSend", arglist).then(callMethodSuccessCB, callMethodErrorCB);
170         });
171         
172         return promise;
173 };
174
175
176 cloudeebus.ProxyObject.prototype.connectToSignal = function(ifName, signal, handlerCB, errorCB) {
177         
178         var self = this; 
179
180         function signalHandler(id, data) {
181                 if (handlerCB) {
182                         try { // calling dbus hook object function for un-translated types
183                                 handlerCB.apply(self, eval(data));
184                         }
185                         catch (e) {
186                                 var errorStr = cloudeebus.getError(e);
187                                 cloudeebus.log("Signal handler exception: " + errorStr);
188                                 if (errorCB)
189                                         errorCB(errorStr);
190                         }
191                 }
192         }
193         
194         function connectToSignalSuccessCB(str) {
195                 try {
196                         self.wampSession.subscribe(str, signalHandler);
197                 }
198                 catch (e) {
199                         cloudeebus.log("Subscribe error: " + cloudeebus.getError(e));
200                 }
201         }
202
203         function connectToSignalErrorCB(error) {
204                 var errorStr = cloudeebus.getError(error);
205                 cloudeebus.log("Error connecting to signal: " + signal + " on object: " + self.objectPath + " : " + errorStr);
206                 if (errorCB)
207                         errorCB(errorStr);
208         }
209
210         var arglist = [
211                 self.busConnection.name,
212                 self.busName,
213                 self.objectPath,
214                 ifName,
215                 signal
216         ];
217
218         // call dbusSend with bus type, destination, object, message and arguments
219         self.wampSession.call("dbusRegister", arglist).then(connectToSignalSuccessCB, connectToSignalErrorCB);
220 };
221
222
223 cloudeebus.ProxyObject.prototype.disconnectSignal = function(ifName, signal) {
224         try {
225                 this.wampSession.unsubscribe(this.busConnection.name + "#" + this.busName + "#" + this.objectPath + "#" + ifName + "#" + signal);
226         }
227         catch (e) {
228                 cloudeebus.log("Unsubscribe error: " + cloudeebus.getError(e));
229         }
230 };