split JS components
[contrib/cloudeebus.git] / src / js / cloudeebus-service.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.Agent = function(objectPath, handler, xml) {
22         this.xml = xml;
23         this.objectPath = objectPath;
24         this.handler = handler;
25         return this;
26 };
27
28
29 cloudeebus.Service = function(session, busConnection, name) {
30         this.wampSession = session;
31         this.busConnection = busConnection; 
32         this.name = name;
33         this.agents = [];
34         this.isCreated = false;
35         return this;
36 };
37
38
39 cloudeebus.Service.prototype.remove = function() {
40         var self = this;
41         
42         var promise = new cloudeebus.Promise(function (resolver) {
43                 function ServiceRemovedSuccessCB(serviceName) {
44                         resolver.fulfill(serviceName, true);
45                 }
46                 
47                 function ServiceRemovedErrorCB(error) {
48                         var errorStr = cloudeebus.getError(error);
49                         resolver.reject(errorStr, true);
50                 }
51                 
52                 var arglist = [
53                     self.name
54                     ];
55         
56                 // call dbusSend with bus type, destination, object, message and arguments
57                 self.wampSession.call("serviceRelease", arglist).then(ServiceRemovedSuccessCB, ServiceRemovedErrorCB);
58         });
59         
60         return promise;
61 };
62
63
64 cloudeebus.Service.prototype._searchMethod = function(ifName, method, objectJS) {
65
66         var funcToCall = null;
67         
68         // Check if 'objectJS' has a member 'interfaceProxies' with an interface named 'ifName' 
69         // and a method named 'method'
70         if (objectJS.interfaceProxies && objectJS.interfaceProxies[ifName] &&
71                 objectJS.interfaceProxies[ifName][method]) {
72                 funcToCall = objectJS.interfaceProxies[ifName][method];
73         } else {
74                 // retrieve the method directly from 'root' of objectJs
75                 funcToCall = objectJS[method];
76         }
77
78         return funcToCall;
79 };
80
81
82 cloudeebus.Service.prototype._addMethod = function(ifName, method, agent) {
83
84         var service = this;
85         var methodId = this.name + "#" + agent.objectPath + "#" + ifName + "#" + method;
86         var funcToCall = this._searchMethod(ifName, method, agent.handler);
87
88         if (funcToCall == null)
89                 cloudeebus.log("Method " + method + " doesn't exist in Javascript object");
90         else {
91                 agent.handler.wrapperFunc[method] = function() {
92                         var result;
93                         var methodId = arguments[0];
94                         var callDict = {};
95                         // affectation of callDict in eval, otherwise dictionary(='{}') interpreted as block of code by eval
96                         eval("callDict = " + arguments[1]);
97                         try {
98                                 result = funcToCall.apply(agent.handler, callDict.args);
99                                 service._returnMethod(methodId, callDict.callIndex, true, result);
100                         }
101                         catch (e) {
102                                 var errorStr = cloudeebus.getError(e);
103                                 cloudeebus.log("Method " + ifName + "." + method + " call on " + agent.objectPath + " exception: " + errorStr);
104                                 service._returnMethod(methodId, callDict.callIndex, false, errorStr);
105                         }
106                 };
107                 agent.handler.methodId[agent.objectPath].push(methodId);
108                 this.wampSession.subscribe(methodId, agent.handler.wrapperFunc[method]);
109         }
110 };
111
112
113 cloudeebus.Service.prototype._addSignal = function(ifName, signal, agent) {
114         var service = this;
115
116         if (agent.handler[signal])
117                 cloudeebus.log("Signal '" + signal + "' emitter already implemented");
118         else {
119                 agent.handler[signal] = function() {
120                         var args = [];
121                         for (var i=0; i < arguments.length; i++ )
122                                 args.push(arguments[i]);
123                         service._emitSignal(agent.objectPath, signal, args);
124                 };
125         }
126 };
127
128
129 cloudeebus.Service.prototype._createWrapper = function(agent) {
130         var self = this;
131         var parser = new DOMParser();
132         var xmlDoc = parser.parseFromString(agent.xml, "text/xml");
133         var ifXml = xmlDoc.getElementsByTagName("interface");
134         agent.handler.wrapperFunc = {};
135         agent.handler.methodId = {};
136         agent.handler.methodId[agent.objectPath] = [];
137         for (var i=0; i < ifXml.length; i++) {
138                 var ifName = ifXml[i].attributes.getNamedItem("name").value;
139                 var ifChild = ifXml[i].firstChild;
140                 while (ifChild) {
141                         if (ifChild.nodeName == "method") {
142                                 var metName = ifChild.attributes.getNamedItem("name").value;
143                                 self._addMethod(ifName, metName, agent);
144                         }
145                         if (ifChild.nodeName == "signal") {
146                                 var metName = ifChild.attributes.getNamedItem("name").value;
147                                 self._addSignal(ifName, metName, agent);
148                         }
149                         ifChild = ifChild.nextSibling;
150                 }
151         }
152 };
153
154
155 cloudeebus.Service.prototype.addAgent = function(agent) {
156         var self = this;
157         
158         var promise = new cloudeebus.Promise(function (resolver) {
159                 function ServiceAddAgentSuccessCB(objPath) {
160                         self.agents.push(agent);
161                         try {
162                                 self._createWrapper(agent);
163                         }
164                         catch (e) {
165                                 var errorStr = cloudeebus.getError(e);
166                                 cloudeebus.log("Exception creating agent wrapper " + agent.objectPath + " : " + errorStr);
167                                 resolver.reject(errorStr, true);
168                                 return;
169                         }               
170                         resolver.fulfill(objPath, true);
171                 }
172                 
173                 function ServiceAddAgenterrorCB(error) {
174                         var errorStr = cloudeebus.getError(error);
175                         cloudeebus.log("Error adding agent : " + agent.objectPath + ", error: " + errorStr);
176                         resolver.reject(errorStr, true);
177                 }
178                 
179                 var arglist = [
180                     self.name,
181                     agent.objectPath,
182                     agent.xml
183                     ];
184         
185                 // call dbusSend with bus type, destination, object, message and arguments
186                 self.wampSession.call("serviceAddAgent", arglist).then(ServiceAddAgentSuccessCB, ServiceAddAgenterrorCB);
187         });
188         
189         return promise;
190 };
191
192
193 cloudeebus.Service.prototype._deleteWrapper = function(agent) {
194         var objJs = agent.handler;
195         if (objJs.methodId[agent.objectPath]) {
196                 while (objJs.methodId[agent.objectPath].length) {
197                         try {
198                                 this.wampSession.unsubscribe( objJs.methodId[agent.objectPath].pop() );
199                         }
200                         catch (e) {
201                                 cloudeebus.log("Unsubscribe error: " + cloudeebus.getError(e));
202                         }
203                 }
204                 objJs.methodId[agent.objectPath] = null;
205         }
206 };
207
208
209 cloudeebus.Service.prototype.removeAgent = function(rmAgent) {
210         var self = this;
211         
212         var promise = new cloudeebus.Promise(function (resolver) {
213                 function ServiceRemoveAgentSuccessCB(objectPath) {
214                         // Searching agent in list
215                         for (var idx in self.agents)
216                                 if (self.agents[idx].objectPath == objectPath) {
217                                         agent = self.agents[idx];
218                                         break;
219                                 }
220                                         
221                         self.agents.splice(idx, 1);
222                         self._deleteWrapper(agent);
223                         resolver.fulfill(agent, true);
224                 }
225
226                 function ServiceRemoveAgentErrorCB(error) {
227                         var errorStr = cloudeebus.getError(error);
228                         cloudeebus.log("Error removing agent : " + rmAgent.objectPath + ", error: " + errorStr);
229                         resolver.reject(errorStr, true);
230                 }
231
232                 var arglist = [
233                     rmAgent.objectPath
234                     ];
235         
236                 // call dbusSend with bus type, destination, object, message and arguments
237                 self.wampSession.call("serviceDelAgent", arglist).then(ServiceRemoveAgentSuccessCB, ServiceRemoveAgentErrorCB);
238         });
239         
240         return promise;
241 };
242
243
244 cloudeebus.Service.prototype._returnMethod = function(methodId, callIndex, success, result, successCB, errorCB) {
245         var arglist = [
246             methodId,
247             callIndex,
248             success,
249             result
250             ];
251
252         this.wampSession.call("returnMethod", arglist).then(successCB, errorCB);
253 };
254
255
256 cloudeebus.Service.prototype._emitSignal = function(objectPath, signalName, args, successCB, errorCB) {
257         var arglist = [
258             objectPath,
259             signalName,
260             JSON.stringify(args)
261             ];
262
263         this.wampSession.call("emitSignal", arglist).then(successCB, errorCB);
264 };
265
266
267