exporttosccdxml.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /* SCCDXML exporter plugin*/
  2. {
  3. 'interfaces' : [{'method':'POST', 'url=':'/exporttosccdxml'}],
  4. 'csworker' :
  5. function(resp,method,uri,reqData,wcontext)
  6. {
  7. var self = this,
  8. actions = [__wHttpReq('GET','/current.model?wid='+wcontext.__aswid)];
  9. _do.chain(actions)(
  10. function(asdata){
  11. var writeActions = [_fspp.mkdirs('./exported_to_sccdxml/classes/')];
  12. _do.chain(writeActions) (
  13. function() {
  14. var file_contents = '',
  15. as = _utils.jsonp(asdata['data']),
  16. type_map = {},
  17. type_map_keys = {},
  18. incoming = {},
  19. outgoing = {};
  20. for (var key in as.nodes) {
  21. var node = as.nodes[key];
  22. if (!(node['$type'] in type_map)) {
  23. type_map[node['$type']] = [];
  24. type_map_keys[node['$type']] = [];
  25. }
  26. type_map[node['$type']].push(node);
  27. type_map_keys[node['$type']].push(key);
  28. node['$key'] = key;
  29. }
  30. function xml_safe(str) {
  31. return str.replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;");
  32. }
  33. function safe_add(l, el) {
  34. if (l.indexOf(el) == -1) {
  35. l.push(el);
  36. }
  37. }
  38. function find_initial(state){
  39. var substates = outgoing[state['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/contain' || as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/ocContain'}).map(function(tid) {return as.nodes[tid]});
  40. for (var sidx in substates){
  41. var substate = as.nodes[outgoing[substates[sidx]['$key']]];
  42. if(substate['isStart']['value']){
  43. return substate['name']['value'];
  44. }
  45. }
  46. }
  47. function get_full_path(state){
  48. var parent_link = incoming[state['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/contain' || as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/ocContain' || as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/containOC' || as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/includes'}).map(function(tid) {return as.nodes[tid]})[0];
  49. if (parent_link != undefined){
  50. var parent = as.nodes[incoming[parent_link['$key']][0]];
  51. return get_full_path(parent).concat([state['name']['value']]);
  52. }
  53. else{
  54. return [state['name']['value']];
  55. }
  56. }
  57. function find_path(source, destination){
  58. if(source['$key'] == destination['$key']){
  59. return ".";
  60. }
  61. // Resolve absolute path of source
  62. source_path = get_full_path(source);
  63. // Resolve absolute path of destination
  64. destination_path = get_full_path(destination);
  65. // Now make the destination path relative to the source path
  66. var common;
  67. for (var i in source_path){
  68. if(source_path[i] != destination_path[i]){
  69. common = i;
  70. break;
  71. }
  72. }
  73. source_path = source_path.slice(i, source_path.length);
  74. destination_path = destination_path.slice(i, destination_path.length);
  75. var result = ".";
  76. for (var i in source_path){
  77. result += "/..";
  78. }
  79. for (var i in destination_path){
  80. result += "/" + destination_path[i];
  81. }
  82. return result;
  83. }
  84. function write_raise(lst){
  85. contents = "";
  86. for(var ridx in lst){
  87. var r = lst[ridx];
  88. contents += '<raise event="' + r['event'] + '"';
  89. if(r['scope'].length == 0){
  90. contents += ' scope="broad">\n';
  91. }
  92. else if(r['scope'].lastIndexOf("output(", 0) === 0){
  93. contents += ' scope="output" port="' + r['scope'].slice(7, -1)+ '">\n';
  94. }
  95. else{
  96. contents += ' scope="' + r['scope'] + '">\n';
  97. }
  98. arguments = r['arguments'];
  99. for (var aidx in arguments){
  100. var arg = arguments[aidx];
  101. if(arg != ""){
  102. contents += '<parameter expr="' + xml_safe(arg) + '"/>\n';
  103. }
  104. }
  105. contents += '</raise>\n';
  106. }
  107. return contents;
  108. }
  109. function resolve_transitions(state){
  110. contents = "";
  111. if(outgoing[state['$key']] == undefined){
  112. return "";
  113. }
  114. var transitions = outgoing[state['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/transition'}).map(function(tid) {return as.nodes[tid]});
  115. for (var tidx in transitions){
  116. var transition = transitions[tidx];
  117. contents += "<transition ";
  118. if(transition['after']['value'].length > 0){
  119. contents += 'after="' + xml_safe(transition['after']['value']) + '" ';
  120. }
  121. if(transition['event']['value'].length > 0){
  122. contents += 'event="' + transition['event']['value'] + '" ';
  123. }
  124. if(transition['guard']['value'].length > 0){
  125. contents += 'cond="' + xml_safe(transition['guard']['value']) + '" ';
  126. }
  127. if(transition['port']['value'].length > 0){
  128. contents += 'port="' + transition['port']['value'] + '" ';
  129. }
  130. var target = as.nodes[outgoing[transition['$key']][0]];
  131. contents += 'target="' + find_path(state, target) + '" ';
  132. contents += '>\n';
  133. var parameters = transition['parameters']['value'];
  134. for(var pidx in parameters){
  135. var param = parameters[pidx];
  136. contents += '<parameter name="' + param + '"/>\n';
  137. }
  138. if(transition['action']['value'].length > 0){
  139. contents += "<script><![CDATA[";
  140. contents += transition['action']['value'].split("/*newline*/").join("\n");
  141. contents += "]]></script>\n";
  142. }
  143. var raise = transition['raise']['value'];
  144. contents += write_raise(raise);
  145. contents += '</transition>\n';
  146. }
  147. return contents;
  148. }
  149. function find_priority(state){
  150. state = as.nodes[state['$key']];
  151. if(state['option']['value'] == "OTF"){
  152. return "source_parent";
  153. }
  154. else if(state['option']['value'] == "ITF"){
  155. return "source_child";
  156. }
  157. else {
  158. console.log("Unknown conflict resolution selected: " + state['option']['value']);
  159. return "undefined";
  160. }
  161. }
  162. function add_actions(state){
  163. contents = "<onentry>\n";
  164. state = as.nodes[state['$key']];
  165. if(state['entryAction'] == undefined){
  166. return "";
  167. }
  168. contents += "<script><![CDATA[";
  169. if(state['entryAction']['value'].length > 0){
  170. contents += state['entryAction']['value'].split("/*newline*/").join("\n");
  171. }
  172. contents += "]]></script>\n";
  173. var raise = state['raiseEntry']['value'];
  174. contents += write_raise(raise);
  175. contents += "</onentry>\n";
  176. contents += "<onexit>\n";
  177. contents += "<script><![CDATA[";
  178. if(state['exitAction']['value'].length > 0){
  179. contents += state['exitAction']['value'].split("/*newline*/").join("\n");
  180. }
  181. contents += "]]></script>\n";
  182. var raise = state['raiseExit']['value'];
  183. contents += write_raise(raise);
  184. contents += "</onexit>\n";
  185. return contents;
  186. }
  187. function recursive(state, is_root){
  188. var contents = "";
  189. if(outgoing[state['$key']] == undefined){
  190. var containOC = [],
  191. contain = [],
  192. ocContain = [];
  193. }
  194. else{
  195. var containOC = outgoing[state['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/containOC'}).map(function(tid) {return as.nodes[tid]});
  196. var contain = outgoing[state['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/contain'}).map(function(tid) {return as.nodes[tid]});
  197. var ocContain = outgoing[state['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/ocContain'}).map(function(tid) {return as.nodes[tid]});
  198. var history = outgoing[state['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/includes'}).map(function(tid) {return as.nodes[tid]});
  199. }
  200. var s = as.nodes[state['$key']];
  201. if (is_root){
  202. contents += '<scxml initial="' + find_initial(s) + '" priority="' + find_priority(s) + '">\n';
  203. var children = containOC.concat(contain).concat(ocContain).concat(history);
  204. console.log("Children of root: " + children);
  205. for (var cidx in children){
  206. var child = as.nodes[outgoing[children[cidx]['$key']]];
  207. contents += recursive(child, false);
  208. }
  209. contents += resolve_transitions(s);
  210. contents += '</scxml>\n';
  211. }
  212. else if (containOC.length > 0){
  213. contents += '<parallel id="' + s['name']['value'] + '">\n';
  214. var children = containOC.concat(contain).concat(ocContain).concat(history);
  215. for (var cidx in children){
  216. var child = as.nodes[outgoing[children[cidx]['$key']]];
  217. contents += recursive(child, false);
  218. }
  219. contents += resolve_transitions(s);
  220. contents += add_actions(s);
  221. contents += '</parallel>\n';
  222. }
  223. else if(contain.length + ocContain.length > 0){
  224. contents += '<state id="' + s['name']['value'] + '" initial="' + find_initial(s) + '">\n';
  225. var children = containOC.concat(contain).concat(ocContain).concat(history);
  226. for (var cidx in children){
  227. var child = as.nodes[outgoing[children[cidx]['$key']]];
  228. contents += recursive(child, false);
  229. }
  230. contents += resolve_transitions(s);
  231. contents += add_actions(s);
  232. contents += '</state>\n';
  233. }
  234. else {
  235. var history = incoming[state['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/includes'}).map(function(tid) {return as.nodes[tid]});
  236. if (history.length > 0){
  237. contents += '<history id="' + s['name']['value'] + '" type="' + s['type']['value'].trim() + '"/>\n';
  238. }
  239. else{
  240. contents += '<state id="' + s['name']['value'] + '">\n';
  241. contents += resolve_transitions(s);
  242. contents += add_actions(s);
  243. contents += '</state>\n';
  244. }
  245. }
  246. return contents;
  247. }
  248. function calc_in_out_rel(rel_type) {
  249. for (var idx in type_map_keys[rel_type]) {
  250. key = type_map_keys[rel_type][idx];
  251. incoming[key] = [];
  252. outgoing[key] = [];
  253. for (var e_key in as.edges) {
  254. var e = as.edges[e_key];
  255. if (e['dest'] == key) {
  256. safe_add(incoming[key], e['src'])
  257. if (!(e['src'] in outgoing)) {
  258. outgoing[e['src']] = [];
  259. }
  260. safe_add(outgoing[e['src']], key);
  261. }
  262. if (e['src'] == key) {
  263. safe_add(outgoing[key], e['dest'])
  264. if (!(e['dest'] in incoming)) {
  265. incoming[e['dest']] = [];
  266. }
  267. safe_add(incoming[e['dest']], key);
  268. }
  269. }
  270. }
  271. }
  272. calc_in_out_rel('/Formalisms/SCCD/SCCD/transition');
  273. calc_in_out_rel('/Formalisms/SCCD/SCCD/Inheritance');
  274. calc_in_out_rel('/Formalisms/SCCD/SCCD/Association');
  275. calc_in_out_rel('/Formalisms/SCCD/SCCD/contain');
  276. calc_in_out_rel('/Formalisms/SCCD/SCCD/containOC');
  277. calc_in_out_rel('/Formalisms/SCCD/SCCD/ocContain');
  278. calc_in_out_rel('/Formalisms/SCCD/SCCD/behaviour');
  279. calc_in_out_rel('/Formalisms/SCCD/SCCD/includes');
  280. for (var key in type_map['/Formalisms/SCCD/SCCD/Class']){
  281. var node = type_map['/Formalisms/SCCD/SCCD/Class'][key],
  282. external = node['external']['value'],
  283. type = node['name']['value'];
  284. if(!external){
  285. file_contents += '<class name="' + node['name']['value'] + '" default="true">\n';
  286. file_contents += '\t<relationships>\n';
  287. inheritances = outgoing[node['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/Inheritance'}).map(function(tid) {return as.nodes[tid]});
  288. for (var iidx in inheritances){
  289. target = as.nodes[outgoing[inheritances[iidx]['$key']][0]];
  290. file_contents += '\t\t<inheritance class="' + target['name']['value'] + '"/>\n';
  291. }
  292. associations = outgoing[node['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/Association'}).map(function(tid) {return as.nodes[tid]});
  293. for (var iidx in associations){
  294. target = as.nodes[outgoing[associations[iidx]['$key']][0]];
  295. file_contents += '\t\t<association name="' + associations[iidx]['name']['value'] + '" class="' + target['name']['value'] + '"/>\n';
  296. }
  297. file_contents += '';
  298. file_contents += '\t</relationships>\n';
  299. for (var fidx in node['methods']['value']){
  300. var func = node['methods']['value'][fidx];
  301. file_contents += '\t<method name="' + func['name'] + '">\n';
  302. for (var aidx in func['args']){
  303. var arg = func['args'][aidx];
  304. if(arg['name'] == ""){
  305. continue;
  306. }
  307. file_contents += '\t\t<parameter name="' + arg['name'] + '"/>\n';
  308. }
  309. file_contents += '\t<body><![CDATA[';
  310. file_contents += func['body'].split("/*newline*/").join("\n");
  311. file_contents += "\n";
  312. file_contents += '\t]]></body>\n';
  313. file_contents += '\t</method>\n';
  314. }
  315. var behaviour = outgoing[node['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/behaviour'}).map(function(tid) {return as.nodes[tid]});
  316. var statechart = as.nodes[outgoing[behaviour[0]['$key']][0]];
  317. file_contents += recursive(statechart, true);
  318. file_contents += '</class>\n';
  319. }
  320. }
  321. _fs.writeFileSync('./exported_to_sccdxml/classes/model.xml', file_contents);
  322. __postMessage({'statusCode': 200,
  323. 'respIndex': resp});
  324. },
  325. function(writeErr) {__postInternalErrorMsg(resp, writeErr);}
  326. );
  327. },
  328. function(err) {__postInternalErrorMsg(resp, err);}
  329. )
  330. },
  331. 'asworker' :
  332. function(resp,method,uri,reqData,wcontext)
  333. {
  334. this.localcontext.counter++;
  335. __postMessage(
  336. {'statusCode':200,
  337. 'respIndex':resp});
  338. }
  339. }