cloudeebus js library: get properties only when org.freedesktop.DBus.Properties inter...
[contrib/cloudeebus.git] / cloudeebus / cloudeebus.js
1 /******************************************************************************
2  * Copyright 2012 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 var cloudeebus = window.cloudeebus = {};
22
23 cloudeebus.reset = function() {
24         cloudeebus.sessionBus = null;
25         cloudeebus.systemBus = null;
26         cloudeebus.wampSession = null;
27         cloudeebus.uri = null;
28 };
29
30
31 cloudeebus.log = function(msg) {
32 };
33
34
35 cloudeebus.connect = function(uri, successCB, errorCB) {
36         cloudeebus.reset();
37         cloudeebus.uri = uri;
38         
39         function onWAMPSessionConnectedCB(session) {
40                 cloudeebus.wampSession = session;
41                 cloudeebus.sessionBus = new cloudeebus.BusConnection("session", cloudeebus.wampSession);
42                 cloudeebus.systemBus = new cloudeebus.BusConnection("system", cloudeebus.wampSession);
43                 cloudeebus.log("Connected to " + cloudeebus.uri);
44                 if (successCB)
45                         successCB();
46         }
47
48         function onWAMPSessionErrorCB(code, reason) {
49                 if (code == ab.CONNECTION_UNSUPPORTED) {
50                         cloudeebus.log("Browser is not supported");
51                 }
52                 else {
53                         cloudeebus.log("Failed to open session, code = " + code + ", reason = " + reason);
54                 }
55                 if (errorCB)
56                         errorCB(reason);
57         }
58
59         return ab.connect(cloudeebus.uri, onWAMPSessionConnectedCB, onWAMPSessionErrorCB);
60 };
61
62
63 cloudeebus.SessionBus = function() {
64         return cloudeebus.sessionBus;
65 };
66
67
68 cloudeebus.SystemBus = function() {
69         return cloudeebus.systemBus;
70 };
71
72
73
74 /*****************************************************************************/
75
76 cloudeebus.BusConnection = function(name, session) {
77         this.name = name;
78         this.wampSession = session;
79         return this;
80 };
81
82
83 cloudeebus.BusConnection.prototype.listNames = function(successCB, errorCB) {
84         
85         var self = this; 
86
87         function listNamesSuccessCB(str) {
88                 if (successCB)
89                         successCB(JSON.parse(str));
90         }
91
92         function listNamesErrorCB(error) {
93                 cloudeebus.log("Failed to list names for bus: " + self.name);
94                 cloudeebus.log(error.desc);
95                 if (errorCB)
96                         errorCB(error.desc);
97         }
98
99     // call listNames with bus name
100         self.wampSession.call("listNames", [self.name]).then(listNamesSuccessCB, listNamesErrorCB);
101 };
102
103
104 cloudeebus.BusConnection.prototype.getObject = function(busName, objectPath, introspectCB, errorCB) {
105         var proxy = new cloudeebus.ProxyObject(this.wampSession, this, busName, objectPath);
106         if (introspectCB)
107                 proxy._introspect(introspectCB, errorCB);
108         return proxy;
109 };
110
111
112
113 /*****************************************************************************/
114
115 cloudeebus.ProxyObject = function(session, busConnection, busName, objectPath) {
116         this.wampSession = session; 
117         this.busConnection = busConnection; 
118         this.busName = busName; 
119         this.objectPath = objectPath; 
120         return this;
121 };
122
123
124 cloudeebus.ProxyObject.prototype._introspect = function(successCB, errorCB) {
125         
126         var self = this; 
127
128         function getAllPropertiesSuccessCB(props) {
129                 for (var prop in props)
130                         self[prop] = props[prop];
131                 if (self.propInterfaces.length > 0) 
132                     self.callMethod("org.freedesktop.DBus.Properties", 
133                                 "GetAll", 
134                                 [self.propInterfaces.pop()], 
135                                 getAllPropertiesSuccessCB, 
136                                 errorCB);
137                 else {
138                         self.propInterfaces = null;
139                         if (successCB)
140                                 successCB(self);
141                 }
142         }
143         
144         function introspectSuccessCB(str) {
145                 var parser = new DOMParser();
146                 var xmlDoc = parser.parseFromString(str, "text/xml");
147                 var interfaces = xmlDoc.getElementsByTagName("interface");
148                 self.propInterfaces = [];
149                 var supportDBusProperties = false;
150                 for (var i=0; i < interfaces.length; i++) {
151                         var ifName = interfaces[i].attributes.getNamedItem("name").value;
152                         if (ifName == "org.freedesktop.DBus.Properties")
153                                 supportDBusProperties = true;
154                         var hasProperties = false;
155                         var ifChild = interfaces[i].firstChild;
156                         while (ifChild) {
157                                 if (ifChild.nodeName == "method") {
158                                         var nArgs = 0;
159                                         var metChild = ifChild.firstChild;
160                                         while (metChild) {
161                                                 if (metChild.nodeName == "arg" &&
162                                                         metChild.attributes.getNamedItem("direction").value == "in")
163                                                                 nArgs++;
164                                                 metChild = metChild.nextSibling;
165                                         }
166                                         self._addMethod(ifName, 
167                                                         ifChild.attributes.getNamedItem("name").value, 
168                                                         nArgs);
169                                 }
170                                 else if (ifChild.nodeName == "property") {
171                                         if (!hasProperties)
172                                                 self.propInterfaces.push(ifName);
173                                         hasProperties = true;
174                                 }
175                                 ifChild = ifChild.nextSibling;
176                         }
177                 }
178                 if (supportDBusProperties && self.propInterfaces.length > 0) {
179                     self.callMethod("org.freedesktop.DBus.Properties", 
180                                 "GetAll", 
181                                 [self.propInterfaces.pop()], 
182                                 getAllPropertiesSuccessCB, 
183                                 errorCB);
184                 }
185                 else {
186                         self.propInterfaces = null;
187                         if (successCB)
188                                 successCB(self);
189                 }
190         }
191
192     // call Introspect on self
193     self.callMethod("org.freedesktop.DBus.Introspectable", "Introspect", [], introspectSuccessCB, errorCB);
194 };
195
196
197 cloudeebus.ProxyObject.prototype._addMethod = function(ifName, method, nArgs) {
198
199         var self = this;
200         
201         self[method] = function() {
202                 if (arguments.length < nArgs || arguments.length > nArgs + 2)
203                         throw "Error: method " + method + " takes " + nArgs + " parameters, got " + arguments.length + ".";
204                 var args = [];
205                 var successCB = null;
206                 var errorCB = null;
207                 for (var i=0; i < nArgs; i++ )
208                         args.push(arguments[i]);
209                 if (arguments.length > nArgs)
210                         successCB = arguments[nArgs];
211                 if (arguments.length > nArgs + 1)
212                         errorCB = arguments[nArgs + 1];
213                 self.callMethod(ifName, method, args, successCB, errorCB);
214         };
215         
216 };
217
218
219 cloudeebus.ProxyObject.prototype.callMethod = function(ifName, method, args, successCB, errorCB) {
220         
221         var self = this; 
222
223         function callMethodSuccessCB(str) {
224                 if (successCB)
225                         successCB.apply(self, JSON.parse(str));
226         }
227
228         function callMethodErrorCB(error) {
229                 cloudeebus.log("Error calling method: " + method + " on object: " + self.objectPath);
230                 cloudeebus.log(error.desc);
231                 if (errorCB)
232                         errorCB(error.desc);
233         }
234
235     var arglist = [
236                 self.busConnection.name,
237                 self.busName,
238                 self.objectPath,
239                 ifName,
240                 method,
241                 JSON.stringify(args)
242         ];
243
244     // call dbusSend with bus type, destination, object, message and arguments
245     self.wampSession.call("dbusSend", arglist).then(callMethodSuccessCB, callMethodErrorCB);
246 };
247
248
249 cloudeebus.ProxyObject.prototype.connectToSignal = function(ifName, signal, successCB, errorCB) {
250         
251         var self = this; 
252
253         function signalHandler(id, data) {
254                 cloudeebus.log("Object: " + self.objectPath + " received signal: " + signal + " id: " + id);
255                 if (successCB)
256                         successCB.apply(self, JSON.parse(data));                
257         }
258         
259         function connectToSignalSuccessCB(str) {
260                 cloudeebus.log("Object: " + self.objectPath + " subscribing to signal: " + str);
261                 self.wampSession.subscribe(str, signalHandler);
262         }
263
264         function connectToSignalErrorCB(error) {
265                 cloudeebus.log("Error connecting to signal: " + signal + " on object: " + self.objectPath);
266                 cloudeebus.log(error.desc);
267                 if (errorCB)
268                         errorCB(error.desc);
269         }
270
271     var arglist = [
272                 self.busConnection.name,
273                 self.busName,
274                 self.objectPath,
275                 ifName,
276                 signal
277         ];
278
279     // call dbusSend with bus type, destination, object, message and arguments
280     self.wampSession.call("dbusRegister", arglist).then(connectToSignalSuccessCB, connectToSignalErrorCB);
281 };