View Javadoc

1   /*
2    * UML2MMBase module.
3    *
4    * The contents of this file are subject to the Mozilla Public License
5    * Version 1.0 (the "License"); you may not use this file except in
6    * compliance with the License. You may obtain a copy of the License at
7    * http://www.mozilla.org/MPL/
8    *
9    * Software distributed under the License is distributed on an "AS IS"
10   * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
11   * License for the specific language governing rights and limitations
12   * under the License.
13   */
14  
15  package com.finalist.mmbase.uml;
16  
17  import java.util.Collection;
18  import java.util.HashMap;
19  import java.util.Iterator;
20  import java.util.LinkedHashMap;
21  
22  import org.andromda.core.simpleuml.UMLAssociationEnd;
23  import org.andromda.core.simpleuml.UMLClassifier;
24  import org.andromda.core.simpleuml.UMLDependency;
25  import org.andromda.core.uml14.DirectionalAssociationEnd;
26  import org.omg.uml.foundation.core.AssociationEnd;
27  import org.omg.uml.foundation.core.Dependency;
28  import org.omg.uml.foundation.core.ModelElement;
29  import org.omg.uml.foundation.core.Classifier;
30  import com.finalist.mmbase.umlprofile.MMBaseUMLProfile;
31  
32  /***
33   *
34   * Helper classes to get access to relation specific uml model elements.
35   *
36   * @author Kors van Beem - Finalist IT Group
37   * @version $Revision: 1.4 $, $Date: 2004/12/08 23:27:32 $
38   *
39   */
40  public class MMBaseRelationHelper {
41  
42     private MMBaseHelper model = null;
43  
44     /***  Default constructor. */
45     public MMBaseRelationHelper(MMBaseHelper model) {
46        this.model = model;
47     }
48  
49     public MMBaseHelper getModel() {
50        return model;
51     }
52  
53     /***
54      * Get a collection of MMBaseRelationVo's which contains information
55      * about the relations associated with the given object.
56      *
57      * @param object The ModelElement to find the relations of.
58      * @return A collection of MMBaseRelationVo's
59      */
60     public Collection getRelations(Object object) {
61        if ((object == null) || !(object instanceof ModelElement)) {
62           return null;
63        }
64  
65        HashMap relations = new HashMap();
66  
67        UMLClassifier umlClassifier = (UMLClassifier) object;
68        ModelElement sourceElement = (ModelElement) object;
69  
70        Collection links = umlClassifier.getAssociationLinks();
71        for (Iterator iterator = links.iterator(); iterator.hasNext();) {
72           DirectionalAssociationEnd dirAssocEnd = model.getAssociationData(iterator.next());
73           UMLAssociationEnd umlTarget = (UMLAssociationEnd) dirAssocEnd.getTarget();
74           UMLAssociationEnd umlSource = (UMLAssociationEnd) dirAssocEnd.getSource();
75           String associationType = parseRelationName(dirAssocEnd.getName());
76  
77           AssociationEnd source = dirAssocEnd.getSource();
78           AssociationEnd target = dirAssocEnd.getTarget();
79           String sourceName = getAssociationEndName(dirAssocEnd.getSource());
80           String targetName = getAssociationEndName(dirAssocEnd.getTarget());
81           String cardSourceLower = MMBaseAssociationHelper.getCardinalityLower(dirAssocEnd.getSource());
82           String cardSourceUpper = MMBaseAssociationHelper.getCardinalityUpper(dirAssocEnd.getSource());
83           String cardTargetLower = MMBaseAssociationHelper.getCardinalityLower(dirAssocEnd.getTarget());
84           String cardTargetUpper = MMBaseAssociationHelper.getCardinalityUpper(dirAssocEnd.getTarget());
85           // If no rolename was given, xmi sets the rolenameto "The{targetName}".
86           // If so, set the rolename to the "{targetName}".
87           String roleName = umlTarget.getRoleName();
88           if (roleName.equals(new String("The" + (umlTarget.getType()).getName()))) {
89              roleName = (umlTarget.getType()).getName();
90           }
91  
92           String key = sourceName + ":" + targetName + ":" + associationType;
93           boolean addRelation = false;
94           if (!targetName.equals(sourceName) || (cardTargetUpper.equals("1") && cardSourceUpper.equals("1"))
95                                                                                    || (cardTargetUpper.equals("-1") && cardSourceUpper.equals("-1"))) {
96              // Normal relation.
97              if (cardTargetUpper.equals("1") && cardSourceUpper.equals("1")) {
98                 cardSourceLower = "0";
99                 cardTargetLower = "0";
100             }
101 
102             if (umlTarget.getNavigable().equals("true")) {
103                addRelation = true;
104             }
105          }
106          else {
107             cardSourceLower = "0";
108             cardTargetLower = "0";
109             associationType = "unidirectional" + associationType;
110 
111             if (target.isNavigable() && !source.isNavigable()) {
112                addRelation = true;
113             }
114             else if (cardSourceUpper.equals("1") && (Integer.parseInt(cardTargetUpper) > 1 || cardTargetUpper.equals("-1"))) {
115                addRelation = true;
116             }
117             else if ((!"".equals(umlTarget.getRoleName()) && umlTarget.getRoleName() != null)
118                     && ("".equals(umlSource.getRoleName()) || umlSource.getRoleName() == null)) {
119                addRelation = true;
120             }
121             else {
122                MMBaseRelationVo relDefVo = (MMBaseRelationVo) relations.get(key);
123                if (relDefVo == null) {
124                   // This relation doesn't exist yet, add it.
125                   addRelation = true;
126                }
127             }
128          }
129          // The STEREOTYPE != OPTIONLIST checks are hacks for Together since Together
130          // automatically creates a relation to a class when the type of an
131          // attribute is set to this class.
132          if (addRelation
133                  && !MMBaseUMLProfile.STEREOTYPE_CLASS_OPTIONLIST.equalsIgnoreCase(model.getStereotype(umlTarget.getType()))
134                  && !MMBaseUMLProfile.STEREOTYPE_CLASS_OPTIONLIST.equalsIgnoreCase(model.getStereotype(umlSource.getType()))) {
135             //isOptionList(targetName);
136             relations.remove(key);
137             relations.put(key, new MMBaseRelationVo(associationType, sourceName, targetName, cardSourceLower, cardSourceUpper,
138                                            cardTargetLower, cardTargetUpper, umlTarget.getNavigable(), roleName, umlTarget.getType()));
139          }
140       }
141       Collection deps = umlClassifier.getDependencies();
142       for (Iterator iterator = deps.iterator(); iterator.hasNext();) {
143          UMLDependency umlDependency = (UMLDependency) iterator.next();
144          Dependency dependency = (Dependency) umlDependency.getId();
145          String dependencyType = MMBaseUMLProfile.DEFAULT_RELATION_TYPE;
146          String depName = dependency.getName();
147          if (depName != null && !depName.equals("")) {
148             dependencyType = depName.toLowerCase();
149          }
150 
151          Collection c = dependency.getStereotype();
152          String targetCardinalityLower = "0";
153          for (Iterator i = c.iterator(); i.hasNext();) {
154             ModelElement me = (ModelElement) i.next();
155             if (me.getName().equalsIgnoreCase("required")) {
156                targetCardinalityLower = "1";
157             }
158          }
159          ModelElement targetElement = umlDependency.getTargetType();
160 
161          String key = sourceElement.getName() + ":" + targetElement.getName() + ":" + dependencyType;
162          relations.put(key, new MMBaseRelationVo(dependencyType, sourceElement.getName(), targetElement.getName(), "0",
163                                                  "0", targetCardinalityLower, "-1", "true", targetElement.getName(), targetElement));
164       }
165       return model.sortValuesByKeys(relations);
166    }
167 
168     /***
169      * Get name of the related relation for the specified object.
170      * The object should have the RelDef stereotype.
171      *
172      * @param object The ModelElement to find the relations of.
173      * @return String with the builder name for which a reldef has to be created.
174      */
175     public String getRelDef(Object object) {
176        if ((object == null) || !(object instanceof ModelElement)) {
177           return null;
178        }
179        String relDef = null;
180        UMLClassifier umlClassifier = (UMLClassifier) object;
181        ModelElement sourceElement = (ModelElement) object;
182        if ((model.getStereotype(object) == null) || !model.getStereotype(object).equalsIgnoreCase(MMBaseUMLProfile.STEREOTYPE_CLASS_RELDEF)) {
183            // Alleen objecten met het RelDef stereotype kunnen als reldef worden gebruikt.
184            return null;
185        }
186        Collection deps = umlClassifier.getDependencies();
187        for (Iterator iterator = deps.iterator(); iterator.hasNext();) {
188           UMLDependency umlDependency = (UMLDependency) iterator.next();
189           ModelElement targetElement = umlDependency.getTargetType();
190           relDef  = targetElement.getName();
191           // We'll take the first dependency...
192           break;
193        }
194        return relDef;
195     }
196 
197    /***
198     * Add a relation name to the static hashmap.
199     *
200     * @param elements Collection of ModelElements.
201     * @return A collection of RelationVo's containing the information of relations.
202     */
203    public Collection getRelationReferences(Collection elements) {
204 
205       LinkedHashMap relationReferences = new LinkedHashMap();
206       for (Iterator it = elements.iterator(); it.hasNext();) {
207          Object object = it.next();
208          if (object instanceof ModelElement) {
209             ModelElement modelElement = (ModelElement) object;
210             Collection stereoTypeNames = model.getStereotypeNames(modelElement);
211             if (stereoTypeNames.contains(MMBaseUMLProfile.STEREOTYPE_CLASS_MMBASE)) {
212                Collection c = getRelations(modelElement);
213                for (Iterator it2 = c.iterator(); it2.hasNext();) {
214                   Object relationObject = it2.next();
215                   if (relationObject instanceof MMBaseRelationVo) {
216                      MMBaseRelationVo relationVo = (MMBaseRelationVo) relationObject;
217 
218                      String theSourceObject = relationVo.getSourceName();
219                      String theTargetObject = relationVo.getTargetName();
220                      String theRelationType = relationVo.getType();
221                      // Ignore the relations in opposit direction of the same type:
222                      if (relationReferences.get(theTargetObject + ":" + theSourceObject + ":" + theRelationType) == null) {
223                         relationReferences.put(theSourceObject + ":" + theTargetObject + ":" + theRelationType, relationVo);
224                      }
225                   }
226                }
227             }
228          }
229       }
230       return model.sortValuesByKeys(relationReferences);
231    }
232 
233    /***
234     * Return the static HashMap which contains all the relationDefinitions.
235     *
236     * @param elements The Collection of elements to check werther they are AssociationEnds.
237     * @return Collection of MMBaseRelationDefinitions.
238     */
239    public Collection getRelationDefinitions(Collection elements) {
240       HashMap relationDefinitions = new HashMap();
241       for (Iterator it = elements.iterator(); it.hasNext();) {
242          boolean classType = false; // User defined a class for the type
243          Object object = it.next();
244 
245          String relationType = MMBaseUMLProfile.DEFAULT_RELATION_TYPE;
246          String direction = MMBaseUMLProfile.DEFAULT_RELATION_DIRECTION;
247          String builder = MMBaseUMLProfile.DEFAULT_RELATION_BUILDER;
248 
249          if (object instanceof AssociationEnd) {
250             AssociationEnd assocEnd = (AssociationEnd) object;
251             DirectionalAssociationEnd dirAssocEnd = model.getAssociationData(assocEnd);
252 
253             relationType = parseRelationName(dirAssocEnd.getName());
254 
255             // Check if direction should be unidirectional.
256 
257             String sourceName = getAssociationEndName(dirAssocEnd.getSource());
258             String targetName = getAssociationEndName(dirAssocEnd.getTarget());
259             String cardSourceUpper = MMBaseAssociationHelper.getCardinalityUpper(dirAssocEnd.getSource());
260             String cardTargetUpper = MMBaseAssociationHelper.getCardinalityUpper(dirAssocEnd.getTarget());
261 
262             if (sourceName.equals(targetName) && !(cardSourceUpper.equals("1") && cardTargetUpper.equals("1"))) {
263                direction = "unidirectional";
264                relationType = "unidirectional" + relationType;
265             }
266          }
267          if (object instanceof Dependency) {
268             Dependency dep = (Dependency) object;
269             relationType = parseRelationName(dep.getName());
270          }
271 
272          if (relationType.equals("posrel") || relationType.equals("unidirectionalposrel")) {
273             builder = "posrel";
274          }
275          // Check if the relationType is a user defined relation. This means there should be a
276          // class with the stereotype <<Relation>> that has the name of the relationType.
277          if (object instanceof Classifier) {
278             String relationStereoType = model.getStereotype(object);
279             if (relationStereoType != null && MMBaseUMLProfile.STEREOTYPE_CLASS_RELATION.equals(relationStereoType)) {
280                relationType = model.getName(object);
281                builder = relationType; // In this case, the builder will be generated for this type.
282                classType = true; // Mark this clas as a user define class.
283                 System.out.println("Custom relation: " + builder);
284             }
285              if (relationStereoType != null && MMBaseUMLProfile.STEREOTYPE_CLASS_RELDEF.equals(relationStereoType)) {
286                 // In this case we reuse the builder and just specifiy a reldef.
287                 relationType = model.getName(object);
288                 builder = getRelDef(object);
289                 classType = true; // Mark this clas as a user define class.
290              }
291          }
292 
293          String keyValue = relationType + ":" + direction;
294          MMBaseRelationDefinitionVo relDefVo = new MMBaseRelationDefinitionVo(relationType, direction, builder);
295          if (!relationDefinitions.containsKey(keyValue)) {
296             relationDefinitions.put(keyValue, relDefVo);
297          }
298          else if (classType) {
299             // Only overwrite for user defined relations.
300             relationDefinitions.put(keyValue, relDefVo);
301          }
302 
303       }
304       return model.sortValuesByKeys(relationDefinitions);
305    }
306 
307    /***
308     * Function to determine the type of a relation. This type
309     * depends on the name of the relation.
310     *
311     * @return String containing the type of a relation.
312     */
313    private String parseRelationName(String relationName) {
314       String returnString = MMBaseUMLProfile.DEFAULT_RELATION_TYPE;
315       if (relationName == null) {
316          relationName = returnString;
317       }
318       if (!(relationName).startsWith("{") && !relationName.equals("") && !(relationName).endsWith("}")) {
319          returnString = relationName.toLowerCase();
320       }
321       return returnString;
322    }
323 
324    /***
325     * Function to retrieve the name of a modelElement.
326     *
327     * @return String containing the name of the AssociationEnd.
328     */
329    private String getAssociationEndName(AssociationEnd assocEnd) {
330       String name = "";
331       if (assocEnd instanceof UMLAssociationEnd) {
332          UMLAssociationEnd umlAssocEnd = (UMLAssociationEnd) assocEnd;
333          name = umlAssocEnd.getType().getName();
334       }
335       return name;
336    }
337 }