1 | package de.uka.ipd.sdq.dsexplore.launch; |
2 | |
3 | import java.io.File; |
4 | import java.net.URL; |
5 | import java.util.ArrayList; |
6 | import java.util.Collections; |
7 | import java.util.HashSet; |
8 | import java.util.Iterator; |
9 | import java.util.List; |
10 | import java.util.Set; |
11 | |
12 | import org.eclipse.core.runtime.CoreException; |
13 | import org.eclipse.core.runtime.FileLocator; |
14 | import org.eclipse.core.runtime.IConfigurationElement; |
15 | import org.eclipse.core.runtime.IExtension; |
16 | import org.eclipse.emf.common.util.URI; |
17 | import org.eclipse.emf.ecore.resource.Resource; |
18 | import org.eclipse.emf.ecore.resource.ResourceSet; |
19 | import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; |
20 | |
21 | import de.uka.ipd.sdq.dsexplore.analysis.IAnalysisQualityAttributeDeclaration; |
22 | import de.uka.ipd.sdq.dsexplore.helper.ExtensionHelper; |
23 | import de.uka.ipd.sdq.dsexplore.launch.DSEConstantsContainer.QualityAttribute; |
24 | import de.uka.ipd.sdq.dsexplore.qml.handling.QMLConstantsContainer; |
25 | import de.uka.ipd.sdq.dsexplore.qml.pcm.datastructures.EvaluationAspectWithContext; |
26 | import de.uka.ipd.sdq.dsexplore.qml.pcm.reader.PCMDeclarationsReader; |
27 | import de.uka.ipd.sdq.dsexplore.qml.reader.QMLDimensionReader; |
28 | import de.uka.ipd.sdq.pcm.usagemodel.UsageModel; |
29 | |
30 | /** |
31 | * The QMLManager component can be queried for getting the currently activated QML criteria. |
32 | * Based on the activated criteria, it de-/activates evaluators in the launch configuration |
33 | * tabs. |
34 | * |
35 | * @author martens, noorshams |
36 | * |
37 | */ |
38 | /* |
39 | * Probably it will be useful to create a default contract (not only contract |
40 | * type and declaration) that optimises performance, reliability and costs that |
41 | * can be referenced as a default. Put that one in PCMMODELS |
42 | * (cf. glassfish.repository, it is in |
43 | * https://sdqweb.ipd.uka.de/svn/code/Palladio.EMFComponentModel/trunk/de.uka.ipd.sdq.pcm.resources/defaultModels) |
44 | * -> |
45 | * noorshams: Not possible since you need one profile for *every* UsageModel. See |
46 | * https://sdqweb.ipd.uka.de/svn/code/Palladio.DesignSpaceExploration/trunk/de.uka.ipd.sdq.dsexplore.constrainthandling.qmldeclarations |
47 | * for examples and default declarations |
48 | */ |
49 | |
50 | public class QMLManager { |
51 | |
52 | protected List<DSEAnalysisMethodTab> tabs = new ArrayList<DSEAnalysisMethodTab>(); |
53 | |
54 | /** |
55 | * Indicates if {@code processQMLFile(String, String)} was successful. |
56 | */ |
57 | protected boolean qmlLoaded = false; |
58 | protected String diagnosis = null; |
59 | protected PCMDeclarationsReader pcmReader; |
60 | protected QMLDimensionReader dimensionReader = new QMLDimensionReader(); |
61 | protected String currentQMLPath = ""; |
62 | protected String currentUsageModelPath = ""; |
63 | |
64 | |
65 | protected DSEAnalysisMethodTab costTab = null; |
66 | protected DSEAnalysisMethodTab pofodTab = null; |
67 | protected DSEAnalysisMethodTab performanceTab = null; |
68 | |
69 | //Set to ensure uniqueness of entries |
70 | protected Set<EvaluationAspectWithContext> objectives = Collections.synchronizedSet(new HashSet<EvaluationAspectWithContext>(4)); |
71 | |
72 | public List<EvaluationAspectWithContext> getActivatedObjectives(){ |
73 | List<EvaluationAspectWithContext> returnList = new ArrayList<EvaluationAspectWithContext>(this.objectives); |
74 | return returnList; |
75 | } |
76 | |
77 | public boolean hasActivatedObjectives(){ |
78 | return (this.objectives.size() > 0); |
79 | } |
80 | |
81 | /** |
82 | * Add tabs to be de-/activates here. |
83 | * |
84 | * @param tabs |
85 | */ |
86 | public void addTabs(DSEAnalysisMethodTab... tabs) { |
87 | for(DSEAnalysisMethodTab tab : tabs) { |
88 | this.tabs.add(tab); |
89 | if(tab.getId().equals(QualityAttribute.PERFORMANCE_QUALITY.getName())) { |
90 | performanceTab = tab; |
91 | } else if(tab.getId().equals(QualityAttribute.COST_QUALITY.getName())) { |
92 | costTab = tab; |
93 | } else if(tab.getId().equals(QualityAttribute.RELIABILITY_QUALITY.getName())) { |
94 | pofodTab = tab; |
95 | } |
96 | } |
97 | } |
98 | |
99 | /** |
100 | * Reads QML definitions and activates or deactivates extensions in the tabs |
101 | * based on the definitions. If processing is successful, |
102 | * {@code isQMLLoaded()} returns {@code true}. |
103 | * |
104 | * @param qmlFilePath |
105 | * @param usageModelFilePath |
106 | */ |
107 | public void processQMLFile(String qmlFilePath, String usageModelFilePath){ |
108 | |
109 | if(currentQMLPath.equals(qmlFilePath) && currentUsageModelPath.equals(usageModelFilePath)) { |
110 | return; |
111 | } |
112 | |
113 | currentQMLPath = qmlFilePath; |
114 | currentUsageModelPath = usageModelFilePath; |
115 | |
116 | qmlLoaded = false; |
117 | objectives.clear(); |
118 | deactivateAllTabs(); |
119 | |
120 | ResourceSet rs = new ResourceSetImpl(); |
121 | if(!fileExists(usageModelFilePath)) { |
122 | diagnosis = "Could not load usage model! Please check the path!"; |
123 | return; |
124 | } |
125 | URI uri; |
126 | if (URI.createURI(usageModelFilePath).isPlatform() || usageModelFilePath.indexOf("://") >= 0) { |
127 | uri = URI.createURI(usageModelFilePath); |
128 | } else { |
129 | uri = URI.createFileURI(usageModelFilePath); |
130 | } |
131 | Resource r = (Resource) rs.getResource(uri, true); |
132 | List<?> contents = r.getContents(); |
133 | UsageModel usageModel = null; |
134 | //Supposed to be exactly one element |
135 | for (Iterator<?> iterator = contents.iterator(); iterator.hasNext();) { |
136 | Object object = (Object) iterator.next(); |
137 | if(object instanceof UsageModel) { |
138 | usageModel = (UsageModel) object; |
139 | break; |
140 | } |
141 | } |
142 | if(usageModel == null){ |
143 | diagnosis = "Could not load usage model! Please check the UsageModel file!"; |
144 | |
145 | return; |
146 | } |
147 | |
148 | if(!fileExists(qmlFilePath) || |
149 | !qmlFilePath.endsWith(DSEConstantsContainer.QML_DEFINITION_EXTENSION.substring( |
150 | DSEConstantsContainer.QML_DEFINITION_EXTENSION.lastIndexOf('.'), |
151 | DSEConstantsContainer.QML_DEFINITION_EXTENSION.length()))) { |
152 | diagnosis = "Could not load qml definition model! Please check the path!"; |
153 | return; |
154 | } |
155 | |
156 | pcmReader = new PCMDeclarationsReader(qmlFilePath); |
157 | List<IExtension> exts = new ArrayList<IExtension>(); |
158 | int init; |
159 | |
160 | //Activate or deactivate Evalutators depending on the qml definitions |
161 | //COST |
162 | { |
163 | List<EvaluationAspectWithContext> costObjectives = pcmReader.getDimensionObjectiveContextsForUsageModel(usageModel, dimensionReader.getDimension(QMLConstantsContainer.QUALITY_ATTRIBUTE_DIMENSION_COST_DEFINITION_PATH).getId()); |
164 | List<EvaluationAspectWithContext> costConstraints = pcmReader.getDimensionConstraintContextsForUsageModel(usageModel, dimensionReader.getDimension(QMLConstantsContainer.QUALITY_ATTRIBUTE_DIMENSION_COST_DEFINITION_PATH).getId()); |
165 | List<EvaluationAspectWithContext> costCriteria = new ArrayList<EvaluationAspectWithContext>(); |
166 | costCriteria.addAll(costObjectives); |
167 | costCriteria.addAll(costConstraints); |
168 | exts.clear(); |
169 | init = 0; |
170 | //Get evaluators that can evaluate every aspect |
171 | for(EvaluationAspectWithContext aspect : costCriteria) { |
172 | List<IExtension> tmp_exts = getExtensionsThatEvaluateAspect(aspect); |
173 | if(init == 0) { |
174 | //initialize |
175 | exts.addAll(tmp_exts); |
176 | init++; |
177 | } else { |
178 | //calculate intersection |
179 | List<IExtension> removeList = new ArrayList<IExtension>(); |
180 | for(IExtension e : exts) { |
181 | if(!tmp_exts.contains(e)){ |
182 | removeList.add(e); |
183 | } |
184 | } |
185 | exts.removeAll(removeList); |
186 | } |
187 | } |
188 | if(costTab != null) { |
189 | if(exts.size() == 0) { |
190 | costTab.deactivate(); |
191 | } else { |
192 | costTab.activate(exts); |
193 | this.objectives.addAll(costObjectives); |
194 | } |
195 | } |
196 | } |
197 | //POFOD |
198 | { |
199 | List<EvaluationAspectWithContext> pofodObjectives = pcmReader.getDimensionObjectiveContextsForUsageModel(usageModel, dimensionReader.getDimension(QMLConstantsContainer.QUALITY_ATTRIBUTE_DIMENSION_POFOD_DEFINITION_PATH).getId()); |
200 | List<EvaluationAspectWithContext> pofodConstraints = pcmReader.getDimensionConstraintContextsForUsageModel(usageModel, dimensionReader.getDimension(QMLConstantsContainer.QUALITY_ATTRIBUTE_DIMENSION_POFOD_DEFINITION_PATH).getId()); |
201 | List<EvaluationAspectWithContext> pofodCriteria = new ArrayList<EvaluationAspectWithContext>(); |
202 | pofodCriteria.addAll(pofodObjectives); |
203 | pofodCriteria.addAll(pofodConstraints); |
204 | exts.clear(); |
205 | init = 0; |
206 | //Get evaluators that can evaluate every aspect |
207 | for(EvaluationAspectWithContext aspect : pofodCriteria) { |
208 | List<IExtension> tmp_exts = getExtensionsThatEvaluateAspect(aspect); |
209 | if(init == 0) { |
210 | //initialize |
211 | exts.addAll(tmp_exts); |
212 | init++; |
213 | } else { |
214 | //calculate intersection |
215 | List<IExtension> removeList = new ArrayList<IExtension>(); |
216 | for(IExtension e : exts) { |
217 | if(!tmp_exts.contains(e)){ |
218 | removeList.add(e); |
219 | } |
220 | } |
221 | exts.removeAll(removeList); |
222 | } |
223 | } |
224 | if(pofodTab != null) { |
225 | if(exts.size() == 0) { |
226 | pofodTab.deactivate(); |
227 | } else { |
228 | pofodTab.activate(exts); |
229 | this.objectives.addAll(pofodObjectives); |
230 | } |
231 | } |
232 | } |
233 | //RESPONSE TIME bzw. Performance in general |
234 | { |
235 | List<EvaluationAspectWithContext> performanceObjectives = |
236 | pcmReader.getDimensionObjectiveContextsForUsageModel(usageModel, dimensionReader.getDimension(QMLConstantsContainer.QUALITY_ATTRIBUTE_DIMENSION_RESPONSETIME_DEFINITION_PATH).getId()); |
237 | performanceObjectives.addAll( |
238 | pcmReader.getDimensionObjectiveContextsForUsageModel(usageModel, dimensionReader.getDimension(QMLConstantsContainer.QUALITY_ATTRIBUTE_DIMENSION_THROUGHPUT_DEFINITION_PATH).getId())); |
239 | |
240 | List<EvaluationAspectWithContext> performanceConstraints = |
241 | pcmReader.getDimensionConstraintContextsForUsageModel(usageModel, dimensionReader.getDimension(QMLConstantsContainer.QUALITY_ATTRIBUTE_DIMENSION_RESPONSETIME_DEFINITION_PATH).getId()); |
242 | performanceConstraints.addAll( |
243 | pcmReader.getDimensionObjectiveContextsForUsageModel(usageModel, dimensionReader.getDimension(QMLConstantsContainer.QUALITY_ATTRIBUTE_DIMENSION_THROUGHPUT_DEFINITION_PATH).getId())); |
244 | |
245 | List<EvaluationAspectWithContext> performanceCriteria = new ArrayList<EvaluationAspectWithContext>(); |
246 | performanceCriteria.addAll(performanceObjectives); |
247 | performanceCriteria.addAll(performanceConstraints); |
248 | exts.clear(); |
249 | init = 0; |
250 | //Get evaluators that can evaluate every aspect |
251 | for(EvaluationAspectWithContext aspect : performanceCriteria) { |
252 | List<IExtension> tmp_exts = getExtensionsThatEvaluateAspect(aspect); |
253 | if(init == 0) { |
254 | //initialize |
255 | exts.addAll(tmp_exts); |
256 | init++; |
257 | } else { |
258 | //calculate intersection |
259 | List<IExtension> removeList = new ArrayList<IExtension>(); |
260 | for(IExtension e : exts) { |
261 | if(!tmp_exts.contains(e)){ |
262 | removeList.add(e); |
263 | } |
264 | } |
265 | exts.removeAll(removeList); |
266 | } |
267 | } |
268 | if(performanceTab != null) { |
269 | if(exts.size() == 0) { |
270 | performanceTab.deactivate(); |
271 | } else { |
272 | performanceTab.activate(exts); |
273 | this.objectives.addAll(performanceObjectives); |
274 | } |
275 | } |
276 | } |
277 | |
278 | qmlLoaded = true; |
279 | } |
280 | |
281 | protected void deactivateAllTabs(){ |
282 | for(DSEAnalysisMethodTab tab : tabs) { |
283 | tab.deactivate(); |
284 | } |
285 | } |
286 | |
287 | protected boolean fileExists(String path) { |
288 | // if this is a platform URL, first resolve it to an absolute path |
289 | if (path.startsWith("platform:")){ |
290 | try { |
291 | URL solvedURL = FileLocator.resolve(new URL(path)); |
292 | path = solvedURL.getPath(); |
293 | } catch (Exception e) { |
294 | e.printStackTrace(); |
295 | return false; |
296 | } |
297 | } |
298 | File f = new File(path); |
299 | return f.exists(); |
300 | } |
301 | |
302 | protected List<IExtension> getExtensionsThatEvaluateAspect(EvaluationAspectWithContext aspect) { |
303 | List<IExtension> exts = ExtensionHelper.loadAnalysisExtensions(aspect.getDimension().getId()); |
304 | List<IExtension> return_list = new ArrayList<IExtension>(exts); |
305 | for(IExtension ex : exts) { |
306 | IConfigurationElement[] elements = ex.getConfigurationElements(); |
307 | for(IConfigurationElement e : elements) { |
308 | IAnalysisQualityAttributeDeclaration attribute; |
309 | try { |
310 | attribute = (IAnalysisQualityAttributeDeclaration)ExtensionHelper.loadExecutableAttribute(e, "qualityAttributeHandler"); |
311 | } catch (CoreException e1) { |
312 | return_list.clear(); |
313 | return return_list; |
314 | } |
315 | if(!attribute.canEvaluateAspectForDimension(aspect.getEvaluationAspect(), aspect.getDimension())){ |
316 | return_list.remove(ex); |
317 | } |
318 | } |
319 | } |
320 | return return_list; |
321 | } |
322 | |
323 | /** |
324 | * Indicates if {@code processQMLFile(String, String)} was successful. |
325 | * |
326 | * @return the QMLLoaded |
327 | */ |
328 | public boolean isQMLLoaded() { |
329 | return qmlLoaded; |
330 | } |
331 | |
332 | /** |
333 | * @return the diagnosis |
334 | */ |
335 | public String getDiagnosis() { |
336 | return diagnosis; |
337 | } |
338 | |
339 | |
340 | } |
341 | |
342 | |