exportM2Ecore.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. {
  2. 'interfaces'
  3. :
  4. [{'method': 'POST', 'url=': '/exportM2Ecore'}],
  5. 'csworker'
  6. :
  7. function (resp, method, uri, reqData, wcontext) {
  8. var actions = [__wHttpReq('GET', '/current.model?wid=' + wcontext.__aswid)];
  9. _do.chain(actions)(
  10. function (asdata) {
  11. //The generated file will be in the "exported_to_ecore" folder
  12. var writeActions = [_fspp.mkdirs('./exported_to_ecore/')];
  13. _do.chain(writeActions)(
  14. function () {
  15. //This variable will contain the lines of the generated files, i.e. the xmi code.
  16. var file_contents = '';
  17. //This variable represent the abstract syntax. It contains all the information.
  18. var as = _utils.jsonp(asdata['data']);
  19. //This variable will contain the root and all the other elements contained by the root.
  20. var root = {};
  21. var listRoots = [];
  22. var graph = [];
  23. var taken = [];
  24. var listCycle = [];
  25. /**
  26. This function removes an element of an array.
  27. **/
  28. function remove(array, elem) {
  29. var index = array.indexOf(elem);
  30. if (index !== -1) {
  31. array.splice(index, 1);
  32. }
  33. }
  34. /**
  35. This function searches if a root exists. A root is a class from which all the other
  36. classes are accessible.
  37. The process :
  38. - find all the classes;
  39. - eliminate all the classes that are the end of a link, that means they are accessible;
  40. - if there are classes that form a cycle, add them all to listNodes;
  41. - if listNodes contains only an element, that is the root. Else, there is no root.
  42. **/
  43. function hasRoot() {
  44. var listNodes = [];
  45. for (var key in as.nodes)
  46. listNodes.push(key);
  47. //removing links node
  48. for (var edge = 0; edge < as.edges.length; edge = edge + 2)
  49. remove(listNodes, as.edges[edge].dest);
  50. //removing accessible classes
  51. for (var edge = 0; edge < as.edges.length; edge = edge + 2) {
  52. if (as.edges[edge].src != as.edges[edge + 1].dest)
  53. remove(listNodes, as.edges[edge + 1].dest);
  54. }
  55. //if there are graph cycles, add the nodes in listNodes
  56. constructGraph();
  57. for (var edge = 0; edge < as.edges.length; edge = edge + 2) {
  58. var id = as.edges[edge].src;
  59. var cycle = detectCycle(id, id);
  60. if (cycle && !inside(listNodes, id)) {
  61. listNodes.push(id);
  62. listCycle.push(id);
  63. }
  64. }
  65. return listNodes;
  66. }
  67. /**
  68. This function returns the root. If none was found, it will create one.
  69. **/
  70. function setRoot() {
  71. listRoots = hasRoot();
  72. if (listRoots.length == 1)
  73. root = createNode(listRoots[0]);
  74. else
  75. root = createRootClass(listRoots);
  76. }
  77. /**
  78. This function creates a root and assigns all the possible roots as references.
  79. **/
  80. function createRootClass(list) {
  81. var node = {};
  82. node.name = reqData['root'];
  83. var contain = [];
  84. for (var i = 0; i < list.length; i++)
  85. contain.push(createNode(list[i]));
  86. node.contain = contain;
  87. return node;
  88. }
  89. /**
  90. This function change all the linkType property of each reference of
  91. the node to containment. The node is the root or a possible one.
  92. **/
  93. function createNode(identifier) {
  94. var node = {};
  95. var elem = as.nodes[identifier];
  96. var linkType = findType(identifier);
  97. if (inside(listRoots, identifier))
  98. node.linkType = linkType + 'Link';
  99. else
  100. node.linkType = linkType;
  101. node.id = identifier;
  102. var keys = Object.keys(elem);
  103. remove(keys, "$type");
  104. var attr = [];
  105. for (var i = 0; i < keys.length; i++)
  106. attr.push(findAttribute(keys[i], identifier));
  107. node.attributes = attr;
  108. node.contain = findContained(identifier);
  109. return node;
  110. }
  111. /**
  112. This function creates the appropriate indentation.
  113. **/
  114. function space(deep) {
  115. var space = '';
  116. for (var i = 0; i < deep; i++)
  117. space += ' ';
  118. return space;
  119. }
  120. /**
  121. This function finds the link's type of the attribute given the link's identifier.
  122. Input : identifier
  123. Output : type
  124. **/
  125. function findType(linkIdentifier) {
  126. var midType = as.nodes[linkIdentifier]["$type"].split("/");
  127. var attrType = midType[midType.length - 1];
  128. return attrType;
  129. }
  130. /**
  131. This function finds all the attributes of an element.
  132. **/
  133. function findAttribute(key, keyDest) {
  134. var attr = {};
  135. attr.name = key;
  136. attr.value = as.nodes[keyDest][key].value;
  137. var attrType = as.nodes[keyDest][key].type;
  138. if (attr.value.length > 0) {
  139. if (attrType.startsWith("list"))
  140. attr.list = true;
  141. else
  142. attr.list = false;
  143. }
  144. return attr;
  145. }
  146. /**
  147. This function finds all the elements contained in another one, in a recursive way.
  148. **/
  149. function findContained(nodeKey) {
  150. var listContained = [];
  151. if (inside(listCycle, nodeKey) && inside(taken, nodeKey))
  152. return [];
  153. for (var k = 0; k < as.edges.length; k++) {
  154. if (nodeKey == as.edges[k].src) {
  155. if (inside(listCycle, nodeKey))
  156. taken.push(nodeKey);
  157. var lien = as.edges[k].dest;
  158. var keyDest = as.edges[k + 1].dest;
  159. var linkType = findType(lien);
  160. var elem = {};
  161. elem.linkType = linkType;
  162. elem.attributes = [];
  163. var keys = Object.keys(as.nodes[keyDest]);
  164. remove(keys, "$type");
  165. for (var i = 0; i < keys.length; i++) {
  166. var attr = findAttribute(keys[i], keyDest);
  167. if (attr.value.length > 0)
  168. elem.attributes.push(attr);
  169. }
  170. var contain = [];
  171. if (!isInRoot(keyDest))
  172. contain = findContained(keyDest);
  173. elem.contain = contain;
  174. listContained.push(elem);
  175. }
  176. }
  177. return listContained;
  178. }
  179. /**
  180. This function returns true if the node, specified by its identifier,
  181. is directly in root.contain, not in one of the subnode.
  182. **/
  183. function isInRoot(key) {
  184. for (var i = 0; i < listCycle.length; i++) {
  185. if (listCycle[i] == key)
  186. return true;
  187. }
  188. return false;
  189. }
  190. /**
  191. This function will write the header of the file including the
  192. name of the root and the URI of the metamodel.
  193. **/
  194. function writeHeader() {
  195. var head = '<?xml version="1.0" encoding="ISO-8859-1"?> \n';
  196. head += '<' + root.name;
  197. head += ' xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns="' + reqData['uri'] + '"';
  198. if (root.attributes != null)
  199. head += writeAttributes(root, 0);
  200. else
  201. head += '> \n';
  202. return head;
  203. }
  204. /**
  205. This function writes the attributes of an element.
  206. **/
  207. function writeAttributes(node, deep) {
  208. var attribut = '';
  209. var listAttr = '';
  210. for (var i = 0; i < node.attributes.length; i++) {
  211. var attr = node.attributes[i];
  212. if (attr.list)
  213. listAttr += writeListAttribute(attr.value, attr.name, deep + 2);
  214. else
  215. attribut += ' ' + attr.name + '="' + attr.value + '"';
  216. }
  217. attribut += '> \n' + listAttr;
  218. return attribut;
  219. }
  220. /**
  221. This function writes a list attribute.
  222. **/
  223. function writeListAttribute(list, name, deep) {
  224. var liste = '';
  225. for (var i = 0; i < list.length; i++)
  226. liste += space(deep) + '<' + name + '>' + list[i] + '</' + name + '> \n';
  227. return liste;
  228. }
  229. /**
  230. This function writes all the contained nodes of the specified node
  231. **/
  232. function writeContained(listContained, deep) {
  233. var contained = '';
  234. for (var i = 0; i < listContained.length; i++) {
  235. contained += space(deep + 2) + '<' + listContained[i].linkType;
  236. var attributes = '';
  237. if (listContained[i].attributes != null) {
  238. }
  239. contained += writeAttributes(listContained[i], deep + 2);
  240. if (listContained[i].contain.length > 0)
  241. contained += writeContained(listContained[i].contain, deep + 2);
  242. contained += space(deep + 2) + '</' + listContained[i].linkType + '> \n';
  243. }
  244. return contained;
  245. }
  246. /**
  247. This function will write everything (classes, attributes, references, enumerations)
  248. in a string.
  249. **/
  250. function writeFile() {
  251. file_contents += writeHeader();
  252. file_contents += writeContained(root.contain, 0);
  253. file_contents += '</' + root.name + '>';
  254. }
  255. /**
  256. This function returns true if the element is in the array.
  257. **/
  258. function inside(array, elem) {
  259. for (var i = 0; i < array.length; i++) {
  260. if (array[i] == elem)
  261. return true;
  262. }
  263. return false;
  264. }
  265. /**
  266. This function populates graph. It takes all the classes
  267. and register them in graph. graph is a list.
  268. **/
  269. function constructGraph() {
  270. var list = [];
  271. for (var i = 0; i < as.edges.length; i += 2) {
  272. var src = as.edges[i].src;
  273. if (!inside(list, src)) {
  274. list.push(src);
  275. var srcNode = {};
  276. srcNode.id = src;
  277. var linked = findLinked(src);
  278. srcNode.linked = linked;
  279. graph.push(srcNode);
  280. }
  281. }
  282. }
  283. /**
  284. This function detects graph cycle.
  285. Input :
  286. - id : the identifier of the actual node;
  287. - initial : the identifier of the first node of the cycle.
  288. Output :
  289. - true : there is a graph cycle;
  290. - false : no graph cycle.
  291. **/
  292. function detectCycle(id, initial) {
  293. for (var i = 0; i < graph.length; i++) {
  294. if (graph[i].id == id) {
  295. if (inside(graph[i].linked, initial))
  296. return true;
  297. else {
  298. for (var j = 0; j < graph[i].linked.length; j++)
  299. return detectCycle(graph[i].linked[j], initial);
  300. }
  301. return false;
  302. }
  303. }
  304. }
  305. /**
  306. This function finds all the related class of a class.
  307. **/
  308. function findLinked(src) {
  309. var listLinked = [];
  310. for (var i = 0; i < as.edges.length; i += 2) {
  311. if (as.edges[i].src == src && as.edges[i + 1].dest != src) {
  312. listLinked.push(as.edges[i + 1].dest);
  313. }
  314. }
  315. return listLinked;
  316. }
  317. /***************************************************************************************************************************************************************
  318. The following is like the main class of this file. It will call the appropriate functions
  319. in order to create the export file.
  320. ****************************************************************************************************************************************************************/
  321. setRoot();
  322. writeFile();
  323. _fs.writeFileSync('./exported_to_ecore/' + reqData['name'] + 'Model.xmi', file_contents);
  324. __postMessage({
  325. 'statusCode': 200,
  326. 'respIndex': resp
  327. });
  328. },
  329. function (writeErr) {
  330. __postInternalErrorMsg(resp, writeErr);
  331. }
  332. );
  333. },
  334. function (err) {
  335. __postInternalErrorMsg(resp, err);
  336. }
  337. )
  338. }
  339. ,
  340. 'asworker'
  341. :
  342. function (resp, method, uri, reqData, wcontext) {
  343. __postMessage(
  344. {
  345. 'statusCode': 200,
  346. 'respIndex': resp
  347. });
  348. }
  349. }