1
|
/**
|
2
|
* @constructor
|
3
|
*/
|
4
|
function JavaComponentChanger() {
|
5
|
var javaClasses = {
|
6
|
boolean: 'java.lang.Boolean',
|
7
|
string: 'java.lang.String',
|
8
|
list: 'java.util.List',
|
9
|
set: 'java.util.Set',
|
10
|
};
|
11
|
|
12
|
var crceClasses = {
|
13
|
package: 'crce.api.java.package',
|
14
|
class: 'crce.api.java.class',
|
15
|
method: 'crce.api.java.method',
|
16
|
property: 'crce.api.java.property',
|
17
|
};
|
18
|
|
19
|
var ns = ''; // http://relisa.kiv.zcu.cz
|
20
|
var xsi = 'http://www.w3.org/2001/XMLSchema-instance';
|
21
|
var xsd = 'crce.xsd';
|
22
|
|
23
|
var xmlDocument;
|
24
|
var nodeCounter;
|
25
|
|
26
|
var xmlParser = new DOMParser();
|
27
|
var xmlSerializer = new XMLSerializer();
|
28
|
|
29
|
/**
|
30
|
* Sends change requirements to CRCE.
|
31
|
* @param {array} components Components to be changed.
|
32
|
* @param {boolean} includeNotFound True if not found classes should be added as change requirements, otherwise false.
|
33
|
*/
|
34
|
this.run = function(components, includeNotFound) {
|
35
|
if (components.length === 0) return;
|
36
|
|
37
|
// initialize requirements XML to be sent to CRCE
|
38
|
xmlDocument = constructXmlDocument(components, includeNotFound);
|
39
|
|
40
|
console.log('CRCE request:', xmlDocument);
|
41
|
|
42
|
// trigger change
|
43
|
return $.ajax({
|
44
|
type: 'POST', // jQuery docs tells to use "method" but it doesn't work and always sends GET -> use "type" instead
|
45
|
url: app.constants.crceApiBase + '/metadata/catalogue/',
|
46
|
data: xmlSerializer.serializeToString(xmlDocument),
|
47
|
contentType: 'application/xml',
|
48
|
timeout: 180 * 1000, // in milliseconds
|
49
|
|
50
|
}).then(function(data, textStatus, jqXHR) {
|
51
|
console.log('CRCE response:', data);
|
52
|
|
53
|
var resourcesEl = data.childNodes[0];
|
54
|
if (resourcesEl.childNodes.length === 0) {
|
55
|
return $.Deferred().reject('CRCE did not find any resources fitting your requirements.').promise();
|
56
|
}
|
57
|
|
58
|
var proposals = [];
|
59
|
|
60
|
resourcesEl.childNodes.forEach(function(resourceEl, index) {
|
61
|
var proposal = {
|
62
|
uuid: resourceEl.getAttribute('uuid'),
|
63
|
};
|
64
|
|
65
|
var capabilityEl = resourceEl.childNodes[0];
|
66
|
capabilityEl.childNodes.forEach(function(attributeEl) {
|
67
|
if (['name', 'external-id', 'version'].includes(attributeEl.getAttribute('name'))) {
|
68
|
proposal[attributeEl.getAttribute('name')] = attributeEl.getAttribute('value');
|
69
|
}
|
70
|
});
|
71
|
proposals.push(proposal);
|
72
|
});
|
73
|
|
74
|
return proposals;
|
75
|
});
|
76
|
};
|
77
|
|
78
|
function constructXmlDocument(components, includeNotFound) {
|
79
|
// initialize requirements XML to be sent to CRCE
|
80
|
xmlDocument = document.implementation.createDocument(ns, 'requirements', null);
|
81
|
//xmlDocument.documentElement.setAttributeNS(xsi, 'xsi:schemaLocation', ns + ' ' + xsd);
|
82
|
|
83
|
nodeCounter = 0;
|
84
|
|
85
|
// optimize returned results
|
86
|
var optimizeByRequirementEl = xmlDocument.createElementNS(ns, 'requirement');
|
87
|
optimizeByRequirementEl.setAttribute('namespace', 'result.optimize-by');
|
88
|
|
89
|
var optimizeByFunctionAttributeEl = xmlDocument.createElementNS(ns, 'attribute');
|
90
|
optimizeByFunctionAttributeEl.setAttribute('name', 'function-ID');
|
91
|
optimizeByFunctionAttributeEl.setAttribute('type', javaClasses.string);
|
92
|
optimizeByFunctionAttributeEl.setAttribute('value', 'cf-equal-cost');
|
93
|
|
94
|
var optimizeByMethodAttributeEl = xmlDocument.createElementNS(ns, 'attribute');
|
95
|
optimizeByMethodAttributeEl.setAttribute('name', 'method-ID');
|
96
|
optimizeByMethodAttributeEl.setAttribute('type', javaClasses.string);
|
97
|
optimizeByMethodAttributeEl.setAttribute('value', 'ro-ilp-direct-dependencies');
|
98
|
|
99
|
optimizeByRequirementEl.appendChild(optimizeByFunctionAttributeEl);
|
100
|
optimizeByRequirementEl.appendChild(optimizeByMethodAttributeEl);
|
101
|
|
102
|
xmlDocument.documentElement.appendChild(optimizeByRequirementEl);
|
103
|
|
104
|
// component does not have to fulfill all requirements
|
105
|
var directiveEl = xmlDocument.createElementNS(ns, 'directive');
|
106
|
directiveEl.setAttribute('name', 'operator');
|
107
|
directiveEl.setAttribute('value', 'or');
|
108
|
|
109
|
xmlDocument.documentElement.appendChild(directiveEl);
|
110
|
|
111
|
// component requirements
|
112
|
components.forEach(function(component) {
|
113
|
var inEdgeList = component.getInEdgeList();
|
114
|
if (!includeNotFound) {
|
115
|
inEdgeList = inEdgeList.filter(function(edge) {
|
116
|
return edge.getFrom().name !== app.constants.notFoundVertexName;
|
117
|
});
|
118
|
}
|
119
|
|
120
|
if (inEdgeList.length === 0) return;
|
121
|
|
122
|
// construct functionality requirements tree
|
123
|
inEdgeList.forEach(function(edge) {
|
124
|
var compatibilityInfoList = edge.getCompatibilityInfo();
|
125
|
|
126
|
compatibilityInfoList.forEach(function(compatibilityInfo) {
|
127
|
compatibilityInfo.incomps.forEach(function(incompatibility) {
|
128
|
appendRequirementTree(xmlDocument.documentElement, incompatibility);
|
129
|
});
|
130
|
});
|
131
|
});
|
132
|
});
|
133
|
|
134
|
return xmlDocument;
|
135
|
}
|
136
|
|
137
|
function appendRequirementTree(element, incompatibility) {
|
138
|
var type = incompatibility.desc.type;
|
139
|
|
140
|
if (app.utils.isUndefined(type)) {
|
141
|
incompatibility.subtree.forEach(function(incompatibility) {
|
142
|
appendRequirementTree(element, incompatibility);
|
143
|
});
|
144
|
|
145
|
} else {
|
146
|
// add package for classes
|
147
|
if (type === 'class') {
|
148
|
var packageRequirementEl = xmlDocument.createElementNS(ns, 'requirement');
|
149
|
packageRequirementEl.setAttribute('uuid', nodeCounter++);
|
150
|
packageRequirementEl.setAttribute('namespace', crceClasses['package']);
|
151
|
|
152
|
var packageAttributeEl = xmlDocument.createElementNS(ns, 'attribute');
|
153
|
packageAttributeEl.setAttribute('name', 'name');
|
154
|
packageAttributeEl.setAttribute('type', javaClasses.string);
|
155
|
packageAttributeEl.setAttribute('value', incompatibility.desc.details.package);
|
156
|
|
157
|
packageRequirementEl.appendChild(packageAttributeEl);
|
158
|
}
|
159
|
|
160
|
var requirementEl = xmlDocument.createElementNS(ns, 'requirement');
|
161
|
requirementEl.setAttribute('uuid', nodeCounter++);
|
162
|
requirementEl.setAttribute('namespace', crceClasses[type]);
|
163
|
|
164
|
// attributes
|
165
|
var details = incompatibility.desc.details;
|
166
|
for (var key in details) {
|
167
|
if (!details.hasOwnProperty(key)) continue;
|
168
|
if (key === 'package') continue;
|
169
|
|
170
|
var value = details[key];
|
171
|
|
172
|
// TODO: fix for JaCC not returning correct values for abstract classes and interfaces
|
173
|
if (key === 'abstract' || key === 'interface') continue;
|
174
|
|
175
|
var attributeType;
|
176
|
switch (typeof value) {
|
177
|
case 'boolean':
|
178
|
attributeType = javaClasses.boolean;
|
179
|
break;
|
180
|
case 'object':
|
181
|
if (value.constructor.name === 'Array') {
|
182
|
attributeType = javaClasses.list;
|
183
|
break;
|
184
|
}
|
185
|
default:
|
186
|
attributeType = javaClasses.string;
|
187
|
}
|
188
|
|
189
|
var attributeEl = xmlDocument.createElementNS(ns, 'attribute');
|
190
|
attributeEl.setAttribute('name', key);
|
191
|
attributeEl.setAttribute('type', attributeType);
|
192
|
attributeEl.setAttribute('value', value);
|
193
|
|
194
|
requirementEl.appendChild(attributeEl);
|
195
|
}
|
196
|
|
197
|
// children
|
198
|
incompatibility.subtree.forEach(function(incompatibility) {
|
199
|
appendRequirementTree(requirementEl, incompatibility);
|
200
|
});
|
201
|
|
202
|
// add package for classes
|
203
|
if (type === 'class') {
|
204
|
packageRequirementEl.appendChild(requirementEl);
|
205
|
element.appendChild(packageRequirementEl);
|
206
|
} else {
|
207
|
element.appendChild(requirementEl);
|
208
|
}
|
209
|
}
|
210
|
}
|
211
|
}
|