source: trunk/modelicaml/org.openmodelica.modelicaml.traceability/src/org/openmodelica/modelicaml/traceability/views/helper/ModelComposer.java @ 1251

Last change on this file since 1251 was 1251, checked in by wschamai, 12 years ago

Enhancements and bug fixes

File size: 14.5 KB
Line 
1package org.openmodelica.modelicaml.traceability.views.helper;
2
3import java.util.ArrayList;
4import java.util.HashMap;
5import java.util.HashSet;
6import java.util.List;
7
8import org.eclipse.uml2.uml.Class;
9import org.eclipse.uml2.uml.Classifier;
10import org.eclipse.uml2.uml.Element;
11import org.eclipse.uml2.uml.NamedElement;
12import org.eclipse.uml2.uml.Package;
13import org.eclipse.uml2.uml.TypedElement;
14import org.openmodelica.modelicaml.common.constants.Constants;
15import org.openmodelica.modelicaml.common.instantiation.ClassInstantiation;
16import org.openmodelica.modelicaml.common.instantiation.TreeObject;
17import org.openmodelica.modelicaml.common.instantiation.TreeParent;
18import org.openmodelica.modelicaml.helper.impl.ValueBindingCreator;
19import org.openmodelica.modelicaml.helper.impl.VerificationScenariosDataCollector;
20
21public class ModelComposer {
22   
23    // The selected system design model
24    private Element systemModel;
25   
26    // Any models, e.g. requirements, that should be instantiated with the system model
27    private List<Element> modelsToBeInstantiated = new ArrayList<Element>();
28
29    // Only the requirements (sub set of models to be instantiated)
30    private List<Element> requirementsToBeInstantiated = new ArrayList<Element>();
31
32    //Any model that was considered for the required models search
33    private HashSet<Element> alreadyConsideredForAdditionalModelsSearch = new HashSet<Element>();
34
35    // all models that were found in the defined root model/package that have models that are required in addition
36    private HashMap<Element, HashSet<Element>> allModelsAndTheirRequiredModelsFound = new HashMap<Element, HashSet<Element>>();
37
38    //Set of models that constitutes the combination to be analyzed
39    private HashSet<Element> initialSetOfModels = new HashSet<Element>();
40
41    // Package within the models should be created
42    private Package valueBindingsPackage;
43
44    // All models that was found by required additional models search
45    private HashSet<Element> allCollectedAdditionalModels = new HashSet<Element>();
46
47    // Models that are found by the additional models search and that should always be instantiated.
48    private HashSet<Element> alwaysInclude = new HashSet<Element>();
49   
50    // All models that were found in the defined root model/package that should always be instantiated
51    private HashSet<Element> allAlwaysIncludeFound = new HashSet<Element>();
52   
53    private VerificationScenariosDataCollector ec;
54
55    // All instantiated models
56    private HashSet<TreeParent> allModelInstantiations = new HashSet<TreeParent>();
57
58    // All instantiated models
59    private HashMap<Element, TreeParent> modelToItsInstantiation = new HashMap<Element, TreeParent>();
60
61    public HashMap<Element, TreeParent> getModelToItsInstantiation() {
62        return modelToItsInstantiation;
63    }
64
65    // Virtual instantiation root. Its direct children are the instantiation roots of all models provided and collected.
66    private TreeParent virtualInstantiationTreeRoot;
67   
68    public TreeParent getVirtualInstantiationTreeRoot() {
69        return virtualInstantiationTreeRoot;
70    }
71
72    // contains tree objects (instantiation roots of models) with all mandatory clients that are NOT satisfied.
73    private HashMap<TreeParent, HashSet<TreeObject>> requiredClients_unsatisfied = new HashMap<TreeParent, HashSet<TreeObject>>();
74
75   
76    // internal log
77    private String log;
78   
79   
80    public ModelComposer(
81            NamedElement sourceModel,
82            List<Element> modelsToBeInstantiated, 
83            Package valueBindingsPackage,
84            Element umlRoolModel){
85       
86        this.systemModel = sourceModel;
87        if (this.systemModel instanceof Class) {
88            findAdditionModels((Class) this.systemModel);
89        }
90       
91        this.valueBindingsPackage = valueBindingsPackage;
92       
93        this.modelsToBeInstantiated.addAll(modelsToBeInstantiated);
94        // TODO: what to do if there are not only requirements?
95        for (Element element : modelsToBeInstantiated) {
96            if (element instanceof Class && element.getAppliedStereotype(Constants.stereotypeQName_Requirement) != null) {
97                this.requirementsToBeInstantiated.add(element);
98                findAdditionModels((Class) element);
99            }
100        }
101       
102        this.initialSetOfModels.addAll(this.modelsToBeInstantiated); 
103        this.initialSetOfModels.add(systemModel);
104       
105        this.ec = new VerificationScenariosDataCollector(umlRoolModel);
106       
107        // virtual instantiation root
108        virtualInstantiationTreeRoot = new TreeParent("Virtual Instantiation", null, null, "", false, true, null, null, true);
109       
110        // instantiate all models in order to enable checks
111        HashSet<Element> allModels = new HashSet<Element>();
112        allModels.addAll(initialSetOfModels);
113        allModels.addAll(allCollectedAdditionalModels);
114       
115        instantiateAll(allModels);
116       
117        // internal log
118        initializeLog();
119    }
120
121   
122    private void instantiateAll(HashSet<Element> models){
123
124        // remove all instantiations from the root
125        for (TreeParent instantiatedModel : allModelInstantiations) {
126            virtualInstantiationTreeRoot.removeChild(instantiatedModel);
127        }
128
129        // clear the list
130        allModelInstantiations.clear();
131        modelToItsInstantiation.clear();
132       
133        // new instantiations
134        for (Element model : models) {
135            if (model instanceof Class) {
136
137                // instantiate model
138                ClassInstantiation ci_model = new ClassInstantiation((Class) model, true);
139                ci_model.createTree();
140               
141                // add the instantiated model to the root
142                virtualInstantiationTreeRoot.addChild(ci_model.getTreeRoot());
143               
144                // add  the instantiation object to the map.
145                allModelInstantiations.add(ci_model.getTreeRoot());
146               
147                // add to model -> its instantiation map
148                modelToItsInstantiation.put(model, ci_model.getTreeRoot());
149            }
150        }
151    }
152   
153    private void addToLog(String msg){
154        this.log = this.log + msg + "\n";
155    }
156   
157    public HashSet<Element> getAdditionallModels(Element model, boolean prune){
158        if (!prune) {
159            return ec.getModelToItsRequiredModels().get(model);
160        }
161        HashSet<Element> additionalModels = new HashSet<Element>();
162        if (ec.getModelToItsRequiredModels().get(model) != null) {
163            for (Element additionalModel : ec.getModelToItsRequiredModels().get(model)) {
164                TreeParent additionalModelInstantiation = this.modelToItsInstantiation.get(additionalModel);
165                if (additionalModelInstantiation != null) {
166                    if (alwaysInclude.contains(additionalModel) 
167                            || isAtLeastOneProviderUsed(virtualInstantiationTreeRoot, additionalModelInstantiation)) {
168                        additionalModels.add(additionalModel);
169                    }
170                    else { // -> prune this model
171                        String message = "REMOVED(07): Additional Model '" + ((NamedElement)additionalModel).getQualifiedName() + "'" +
172                        "\nwas removed because none of its providers is used.";
173                        addToLog(message);
174                    }
175                }
176            }
177        }
178       
179        return additionalModels;
180    }
181   
182   
183    private HashSet<Element> getAllTreeItemsClasses(TreeParent treeParent){
184        HashSet<Element> allTreeItems = new HashSet<Element>();
185       
186        // If it is the root then add the root class
187        if (treeParent.isRoot() && treeParent.getSelectedClass() != null) {
188            allTreeItems.add(treeParent.getSelectedClass());
189        }
190       
191        // add all classes used in children
192        TreeObject[] children = treeParent.getChildren();
193        for (int i = 0; i < children.length; i++) {
194            if (children[i].getUmlElement() instanceof TypedElement && ((TypedElement)children[i].getUmlElement()).getType() instanceof Classifier) {
195                allTreeItems.add(((TypedElement)children[i].getUmlElement()).getType());
196            }
197            if (children[i] instanceof TreeParent) {
198                allTreeItems.addAll(getAllTreeItemsClasses((TreeParent)children[i]));
199            }
200        }
201        return allTreeItems;
202    }
203   
204   
205    public HashSet<TreeObject> getClients(TreeParent treeParent){
206        HashSet<TreeObject> clients = new HashSet<TreeObject>();
207        for (TreeObject treeObject : getAllTreeItems(treeParent)) {
208            if (treeObject.isValueClient()) {
209                clients.add(treeObject);
210            }
211        } 
212        return clients;
213    }
214
215    private boolean treeContainsOneOf(HashSet<TreeObject> treeItems, TreeParent treeParent){
216        HashSet<TreeObject> allTreeItems = getAllTreeItems(treeParent);
217       
218        for (TreeObject treeObject : treeItems) {
219            if (allTreeItems.contains(treeObject)) {
220                return true;
221            }
222        }
223        return false;
224    }
225   
226    private HashSet<TreeObject> getAllTreeItems(TreeParent treeParent){
227        HashSet<TreeObject> allTreeItems = new HashSet<TreeObject>();
228        allTreeItems.add(treeParent);
229       
230        TreeObject[] children = treeParent.getChildren();
231        for (int i = 0; i < children.length; i++) {
232            allTreeItems.add(children[i]);
233            if (children[i] instanceof TreeParent) {
234                allTreeItems.addAll(getAllTreeItems((TreeParent)children[i]));
235            }
236        }
237       
238        return allTreeItems;
239    }
240   
241    private boolean isAtLeastOneProviderUsed(TreeParent virtualInstantiationTreeRoot, TreeParent treeParentToStartTheCheckOn){
242       
243        boolean atLeastOneProviderIsUsed = false;
244        TreeObject[] children = virtualInstantiationTreeRoot.getChildren();
245       
246        for (int i = 0; i < children.length; i++) {
247            TreeObject modelInstnatiationTreeRootItem = children[i];
248
249            // discard itself
250            if (modelInstnatiationTreeRootItem != treeParentToStartTheCheckOn && modelInstnatiationTreeRootItem instanceof TreeParent) {
251                ValueBindingCreator vbc = new ValueBindingCreator();
252           
253                /* Note, the updateAllBindings() is called with the last argument simulateOnly = true 
254                 * so that no modifications are created in components because we only want to analyze possible bindings.
255                 */
256                vbc.updateAllBindings(valueBindingsPackage, (TreeParent) modelInstnatiationTreeRootItem, virtualInstantiationTreeRoot, false, true, false, true);
257                atLeastOneProviderIsUsed = treeContainsOneOf(vbc.getUsedProviders(),treeParentToStartTheCheckOn);
258
259                // stop the check as soon as at least one used provider was found.
260                if (atLeastOneProviderIsUsed) {
261                    return true;
262                }
263            }
264        }
265       
266        return atLeastOneProviderIsUsed;
267    }
268   
269   
270    public boolean areAllRequiredClientsSatisfied(TreeParent virtualInstantiationTreeRoot, TreeParent treeParentToStartTheCheckOn){
271       
272        /*
273         * Get the list of clients for which the code could be derived (even if a user interaction would be necessary)
274        */
275        ValueBindingCreator vbc = new ValueBindingCreator();
276       
277        /* Note, the updateAllBindings() is called with the last argument simulateOnly = true 
278         * so that no modifications are created in components because we only want to analyze possible bindings.
279         */
280        boolean allRequiredClientsAreSatisfied = true;
281       
282        vbc.updateAllBindings(valueBindingsPackage, treeParentToStartTheCheckOn, virtualInstantiationTreeRoot, false, true, false, true);
283       
284        if ( vbc.getAllRequiredClientsFound().size() > 0 
285                && !vbc.getAllClientsWithPossibleBindingCodeDerivation().containsAll(vbc.getAllRequiredClientsFound())) {
286            allRequiredClientsAreSatisfied = false;
287        }
288       
289        // Collect all mandatory clients that are not satisfied.
290        HashSet<TreeObject> unsatisfiedRequiredClients = new HashSet<TreeObject>();
291        unsatisfiedRequiredClients.addAll(vbc.getAllRequiredClientsFound());
292        unsatisfiedRequiredClients.removeAll(vbc.getAllClientsWithPossibleBindingCodeDerivation());
293
294        if (unsatisfiedRequiredClients.size() > 0 ) {
295            requiredClients_unsatisfied.put(treeParentToStartTheCheckOn, unsatisfiedRequiredClients);
296        }
297       
298        return allRequiredClientsAreSatisfied;
299    }
300   
301   
302   
303   
304    private HashSet<Element> findAdditionModels(Class sourceElement){
305       
306        HashSet<Element> collectedAdditionalModels = new HashSet<Element>();
307       
308        // if this model was not yet considered
309        if (!alreadyConsideredForAdditionalModelsSearch.contains(sourceElement)) {
310           
311            //Instantiate the source model in order to collect all classes that are used in its instance tree
312            ClassInstantiation ci_sourceModel = new ClassInstantiation(sourceElement, true);   
313            HashSet<Element> allModelsInInstantiationTree = new HashSet<Element>();
314            ci_sourceModel.createTree();
315           
316            allModelsInInstantiationTree.addAll(getAllTreeItemsClasses(ci_sourceModel.getTreeRoot()));
317           
318            // mark all classes collected from the instantiation tree in order to avoid dead lock search
319            alreadyConsideredForAdditionalModelsSearch.addAll(allModelsInInstantiationTree);
320           
321            // find additional models that are referenced directly by one of the class found in the instantiation tree
322            for (Element element : allModelsInInstantiationTree) {
323                if (element instanceof NamedElement) {
324
325                    HashSet<Element> requiredModels = this.allModelsAndTheirRequiredModelsFound.get(element);
326                    if (requiredModels != null) {
327                        for (Element requiredModelFound : requiredModels) {
328                           
329                            // check if this model should be discarded.
330                            if (initialSetOfModels.contains(requiredModelFound)) {
331                                    if (requiredModelFound instanceof NamedElement) {
332                                   
333                                    String message = "DISCARDED (01): " +
334                                            "The additional model search found '"+((NamedElement)requiredModelFound).getQualifiedName()
335                                            + "'\n referenced by '"+((NamedElement)element).getQualifiedName()+"'.\n"
336                                            + "This model was already found once. This reference is discarded.";
337                                   
338                                    addToLog(message);
339                                }
340                            }
341                            else {
342                                // add to the collected additional models
343                                collectedAdditionalModels.add( requiredModelFound );
344                               
345                                // add to the overall list of collected additional models
346                                allCollectedAdditionalModels.add( requiredModelFound );
347                               
348                                if (allAlwaysIncludeFound.contains( requiredModelFound )) {
349                                    alwaysInclude.add( requiredModelFound );
350                                }
351                            }
352                        }
353                    }
354                }
355            }
356           
357            // recursive call -> iterate over all collected models and find other models that are required in addition
358            for (Element newSourceModel : collectedAdditionalModels) {
359                if (newSourceModel instanceof Class) {
360                    collectedAdditionalModels.addAll(findAdditionModels((Class) newSourceModel));   
361                }
362            }
363        }
364       
365        return collectedAdditionalModels;
366    }
367   
368   
369    public HashSet<TreeObject> getUnsatisfiedRequiredClients(Element model){
370        if (model != null) {
371            TreeParent modelInstantiation = modelToItsInstantiation.get(model);
372           
373            if (modelInstantiation != null) {
374                HashSet<TreeObject> unsatisfiedClients = requiredClients_unsatisfied.get(modelInstantiation);
375
376                if (unsatisfiedClients != null && unsatisfiedClients.size() > 0 ) {
377                    return unsatisfiedClients;
378                }
379            }
380        }
381        return null;
382    }
383   
384    private void initializeLog(){
385        this.log = "\n----------------------------------------------" +
386        "---------------------------------------------------" +
387        "--------------------------------------------------- \n" +
388        "Log for:" +
389            "\n   - System Model '" + ((NamedElement)this.systemModel).getQualifiedName() + "'" +
390            "\n";
391    }
392}
Note: See TracBrowser for help on using the repository browser.