View Javadoc
1   package org.andromda.metafacades.uml14;
2   
3   import java.util.Collection;
4   import org.andromda.metafacades.uml.ClassifierFacade;
5   import org.andromda.metafacades.uml.EnumerationFacade;
6   import org.andromda.metafacades.uml.NameMasker;
7   import org.andromda.metafacades.uml.TypeMappings;
8   import org.andromda.metafacades.uml.UMLMetafacadeProperties;
9   import org.andromda.metafacades.uml.UMLMetafacadeUtils;
10  import org.andromda.metafacades.uml.UMLProfile;
11  import org.andromda.utils.StringUtilsHelper;
12  import org.apache.commons.lang.BooleanUtils;
13  import org.apache.commons.lang.ObjectUtils;
14  import org.apache.commons.lang.StringUtils;
15  import org.omg.uml.foundation.core.Attribute;
16  import org.omg.uml.foundation.core.Classifier;
17  import org.omg.uml.foundation.datatypes.ChangeableKindEnum;
18  import org.omg.uml.foundation.datatypes.Multiplicity;
19  import org.omg.uml.foundation.datatypes.MultiplicityRange;
20  import org.omg.uml.foundation.datatypes.OrderingKind;
21  import org.omg.uml.foundation.datatypes.OrderingKindEnum;
22  import org.omg.uml.foundation.datatypes.ScopeKindEnum;
23  
24  /**
25   * Metaclass facade implementation.
26   * @author Bob Fields
27   */
28  public class AttributeFacadeLogicImpl
29      extends AttributeFacadeLogic
30  {
31      private static final long serialVersionUID = 34L;
32      /**
33       * @param metaObject
34       * @param context
35       */
36      public AttributeFacadeLogicImpl(
37          Attribute metaObject,
38          String context)
39      {
40          super(metaObject, context);
41      }
42  
43      /**
44       * @see org.andromda.core.metafacade.MetafacadeBase#getValidationOwner()
45      public ClassifierFacade getValidationOwner()
46      {
47          return this.getOwner();
48      }
49       */
50  
51      /**
52       * @see org.andromda.metafacades.uml.AttributeFacade#getGetterName()
53       */
54      @Override
55      public String handleGetGetterName()
56      {
57          return UMLMetafacadeUtils.getGetterPrefix(this.getType()) + StringUtilsHelper.capitalize(this.getName());
58      }
59  
60      /**
61       * @see org.andromda.metafacades.uml.AttributeFacade#getSetterName()
62       */
63      @Override
64      public String handleGetSetterName()
65      {
66          return "set" + StringUtils.capitalize(this.getName());
67      }
68  
69      /**
70       * @see org.andromda.metafacades.uml.AttributeFacade#getDefaultValue()
71       */
72      @Override
73      public String handleGetDefaultValue()
74      {
75          String defaultValue = null;
76          if (this.metaObject.getInitialValue() != null)
77          {
78              defaultValue = this.metaObject.getInitialValue().getBody();
79          }
80          // Put single or double quotes around default in case modeler forgot to do it. Most templates
81          // declare Type attribute = $attribute.defaultValue, requiring quotes around the value
82          if (StringUtils.isNotBlank(defaultValue) && !this.isMany() && this.metaObject.getType() != null && defaultValue != null)
83          {
84              String typeName = this.metaObject.getType().getName();
85              if ("String".equals(typeName) && defaultValue.indexOf('"')<0)
86              {
87                  defaultValue = '"' + defaultValue + '"';
88              }
89              else if (("char".equals(typeName) || "Character".equals(typeName))
90                  && defaultValue.indexOf('\'')<0)
91              {
92                  defaultValue = "'" + defaultValue.charAt(0) + '\'';
93              }
94          }
95          if (defaultValue==null) defaultValue="";
96          return defaultValue;
97      }
98  
99      /**
100      * @see org.andromda.metafacades.uml.AttributeFacade#isChangeable()
101      */
102     @Override
103     public boolean handleIsChangeable()
104     {
105         return ChangeableKindEnum.CK_CHANGEABLE.equals(metaObject.getChangeability());
106     }
107 
108     /**
109      * @see org.andromda.metafacades.uml.AttributeFacade#isAddOnly()
110      */
111     @Override
112     public boolean handleIsAddOnly()
113     {
114         return ChangeableKindEnum.CK_ADD_ONLY.equals(metaObject.getChangeability());
115     }
116 
117     /**
118      * @see org.andromda.metafacades.uml.AttributeFacade#getType()
119      */
120     @Override
121     protected Classifier handleGetType()
122     {
123         return metaObject.getType();
124     }
125 
126     /**
127      * @see org.andromda.metafacades.uml.AttributeFacade#getOwner()
128      */
129     @Override
130     public Classifier handleGetOwner()
131     {
132         return this.metaObject.getOwner();
133     }
134 
135     /**
136      * @see org.andromda.metafacades.uml.AttributeFacade#isReadOnly()
137      */
138     @Override
139     public boolean handleIsReadOnly()
140     {
141         return ChangeableKindEnum.CK_FROZEN.equals(metaObject.getChangeability());
142     }
143 
144     /**
145      * @see org.andromda.metafacades.uml.AttributeFacade#isStatic()
146      */
147     @Override
148     public boolean handleIsStatic()
149     {
150         return ScopeKindEnum.SK_CLASSIFIER.equals(this.metaObject.getOwnerScope());
151     }
152 
153     /**
154      * @see org.andromda.metafacades.uml.AttributeFacade#findTaggedValue(String, boolean)
155      */
156     @Override
157     public Object handleFindTaggedValue(
158         String name,
159         boolean follow)
160     {
161         name = StringUtils.trimToEmpty(name);
162         Object value = findTaggedValue(name);
163         if (follow)
164         {
165             ClassifierFacade type = this.getType();
166             while (value == null && type != null)
167             {
168                 value = type.findTaggedValue(name);
169                 type = (ClassifierFacade)type.getGeneralization();
170             }
171         }
172         return value;
173     }
174 
175     /**
176      * @see org.andromda.metafacades.uml.AttributeFacade#isRequired()
177      */
178     @Override
179     public boolean handleIsRequired()
180     {
181         int lower = this.getMultiplicityRangeLower();
182         return lower >= 1;
183     }
184 
185     /**
186      * @see org.andromda.metafacades.uml.AttributeFacade#isMany()
187      */
188     @Override
189     public boolean handleIsMany()
190     {
191         boolean isMany = false;
192         final Multiplicity multiplicity = this.metaObject.getMultiplicity();
193 
194         // assume no multiplicity is 1
195         if (multiplicity != null)
196         {
197             final Collection<MultiplicityRange> ranges = multiplicity.getRange();
198             if (ranges != null && !ranges.isEmpty())
199             {
200                 for (MultiplicityRange multiplicityRange : ranges)
201                 {
202                     final int upper = multiplicityRange.getUpper();
203                     isMany = upper > 1 || upper < 0;
204                 }
205             }
206         }
207         if (null!=this.getType() && !isMany)
208         {
209             // isCollectionType causes too many problems with metafacades
210             isMany = this.getType().isArrayType();
211         }
212         return isMany;
213     }
214 
215     /**
216      * Returns the lower range of the multiplicity for the passed in attribute. If not specified, default is based on
217      * primitive or wrappedPrimitive type, or the default multiplicity.
218      *
219      * @return int the lower range of the multiplicity or the default multiplicity or 1 if it isn't defined.
220      */
221     private int getMultiplicityRangeLower()
222     {
223         Integer lower = null;
224         final Multiplicity multiplicity = metaObject.getMultiplicity();
225         if (multiplicity != null)
226         {
227             final Collection<MultiplicityRange> ranges = multiplicity.getRange();
228             if (ranges != null && !ranges.isEmpty())
229             {
230                 for (MultiplicityRange multiplicityRange : ranges)
231                 {
232                     lower = Integer.valueOf(multiplicityRange.getLower());
233                 }
234             }
235         }
236         if (lower == null)
237         {
238             if (this.getType().isPrimitive())
239             {
240                 lower = Integer.valueOf(1);
241             }
242             else if (this.getType().isWrappedPrimitive())
243             {
244                 lower = Integer.valueOf(0);
245             }
246             else
247             {
248                 final String defaultMultiplicity = this.getDefaultMultiplicity();
249                 if (defaultMultiplicity.startsWith("0"))
250                 {
251                     lower = Integer.valueOf(0);
252                 }
253                 else
254                 {
255                     lower = Integer.valueOf(1);
256                 }
257             }
258         }
259         return lower.intValue();
260     }
261 
262     /**
263      * Returns the upper range of the multiplicity for the passed in attribute
264      *
265      * @return int the upper range of the multiplicity or 1 if it isn't defined.
266      */
267     private int getMultiplicityRangeUpper()
268     {
269         Integer upper = null;
270         final Multiplicity multiplicity = metaObject.getMultiplicity();
271         if (multiplicity != null)
272         {
273             final Collection<MultiplicityRange> ranges = multiplicity.getRange();
274             if (ranges != null && !ranges.isEmpty())
275             {
276                 for (MultiplicityRange multiplicityRange : ranges)
277                 {
278                     upper = Integer.valueOf(multiplicityRange.getUpper());
279                 }
280             }
281         }
282         if (upper == null)
283         {
284             upper = Integer.valueOf(1);
285         }
286         return upper.intValue();
287     }
288 
289     /**
290      * Gets the default multiplicity for this attribute (the
291      * multiplicity if none is defined).
292      *
293      * @return the default multiplicity as a String.
294      */
295     private String getDefaultMultiplicity()
296     {
297         return ObjectUtils.toString(this.getConfiguredProperty(UMLMetafacadeProperties.DEFAULT_MULTIPLICITY));
298     }
299 
300     /**
301      * @see org.andromda.metafacades.uml.AttributeFacade#getEnumeration()
302      */
303     @Override
304     protected EnumerationFacade handleGetEnumeration()
305     {
306         return (EnumerationFacade)(this.isEnumerationLiteral() ? this.getOwner() : null);
307     }
308 
309     /**
310      * @see org.andromda.metafacades.uml.AttributeFacade#isEnumerationLiteral()
311      */
312     @Override
313     protected boolean handleIsEnumerationLiteral()
314     {
315         final ClassifierFacade owner = this.getOwner();
316         return (owner != null) && owner.isEnumeration();
317     }
318 
319     /**
320      * @see org.andromda.metafacades.uml.AttributeFacade#getEnumerationValue()
321      */
322     @Override
323     protected String handleGetEnumerationValue()
324     {
325         String value = null;
326         if (this.isEnumerationLiteral())
327         {
328             value = this.getDefaultValue();
329             value = StringUtils.isEmpty(value) ? this.getName() : String.valueOf(value);
330         }
331         if (this.getType().isStringType() && value!=null && value.indexOf('"')<0)
332         {
333             value = '\"' + value + '\"';
334         }
335         return value;
336     }
337 
338     /**
339      * @see org.andromda.metafacades.uml.AttributeFacade#isEnumerationMember()
340      */
341     @Override
342     protected boolean handleIsEnumerationMember()
343     {
344         boolean isMemberVariable = false;
345         final String isMemberVariableAsString = (String)this.findTaggedValue(
346                 UMLProfile.TAGGEDVALUE_PERSISTENCE_ENUMERATION_MEMBER_VARIABLE);
347         if (StringUtils.isNotBlank(isMemberVariableAsString) && BooleanUtils.toBoolean(isMemberVariableAsString))
348         {
349             isMemberVariable = true;
350         }
351         return isMemberVariable;
352     }
353 
354     /**
355      * @see org.andromda.metafacades.uml.AttributeFacade#getEnumerationLiteralParameters()
356      */
357     @Override
358     protected String handleGetEnumerationLiteralParameters()
359     {
360         return (String)this.findTaggedValue(UMLProfile.TAGGEDVALUE_PERSISTENCE_ENUMERATION_LITERAL_PARAMETERS);
361     }
362 
363     /**
364      * @see org.andromda.metafacades.uml.AttributeFacade#isEnumerationLiteralParametersExist()
365      */
366     @Override
367     protected boolean handleIsEnumerationLiteralParametersExist()
368     {
369         boolean parametersExist = false;
370         if (StringUtils.isNotBlank(this.getEnumerationLiteralParameters()))
371         {
372             parametersExist = true;
373         }
374         return parametersExist;
375     }
376 
377     /**
378      * @see org.andromda.metafacades.uml.AttributeFacade#isDefaultValuePresent()
379      */
380     @Override
381     public boolean handleIsDefaultValuePresent()
382     {
383         return StringUtils.isNotBlank(this.getDefaultValue());
384     }
385 
386     /**
387      * Overridden to provide different handling of the name if this attribute represents a literal.
388      *
389      * @see org.andromda.metafacades.uml.ModelElementFacade#getName()
390      */
391     @Override
392     protected String handleGetName()
393     {
394         String name = null;
395         if (this.isEnumerationMember())
396         {
397             name = super.handleGetName();
398         }
399         else
400         {
401             final String mask = String.valueOf(this.getConfiguredProperty(
402                 this.getOwner() instanceof EnumerationFacade
403                     ? UMLMetafacadeProperties.ENUMERATION_LITERAL_NAME_MASK
404                     : UMLMetafacadeProperties.CLASSIFIER_PROPERTY_NAME_MASK ));
405 
406             name = NameMasker.mask(super.handleGetName(), mask);
407             final boolean templating = Boolean.parseBoolean(String.valueOf(
408                 this.getConfiguredProperty(UMLMetafacadeProperties.ENABLE_TEMPLATING)));
409             // May be null during the validation process.
410             if (this.getType() != null)
411             {
412                 final boolean arrayType = this.getType().isArrayType();
413                 if (this.isPluralizeAttributeNames() && ((this.isMany() && templating) || arrayType))
414                 {
415                     name = StringUtilsHelper.pluralize(name);
416                 }
417             }
418         }
419 
420         return name;
421     }
422 
423     /**
424      * Indicates whether or not we should pluralize association end names.
425      *
426      * @return true/false
427      */
428     private boolean isPluralizeAttributeNames()
429     {
430         final Object value = this.getConfiguredProperty(UMLMetafacadeProperties.PLURALIZE_ATTRIBUTE_NAMES);
431         return value != null && Boolean.valueOf(String.valueOf(value)).booleanValue();
432     }
433 
434     /**
435      * UML2 Only: Returns false always.
436      * @return false
437      * @see org.andromda.metafacades.uml.AttributeFacade#isLeaf()
438      */
439     @Override
440     public boolean handleIsLeaf()
441     {
442         return false;
443     }
444 
445     /**
446      * @see org.andromda.metafacades.uml.AttributeFacade#isOrdered()
447      */
448     @Override
449     public boolean handleIsOrdered()
450     {
451         boolean ordered = false;
452 
453         final OrderingKind ordering = metaObject.getOrdering();
454 
455         // no ordering is 'unordered'
456         if (ordering != null)
457         {
458             ordered = ordering.equals(OrderingKindEnum.OK_ORDERED);
459         }
460 
461         return ordered;
462     }
463 
464     /**
465      * @return hasStereotype(UMLProfile.STEREOTYPE_UNIQUE)
466      * @see org.andromda.metafacades.uml.AttributeFacade#isUnique()
467      */
468     protected boolean handleIsUnique()
469     {
470         return this.hasStereotype(UMLProfile.STEREOTYPE_UNIQUE);
471     }
472 
473     /**
474      * @see org.andromda.metafacades.uml.AttributeFacade#getGetterSetterTypeName()
475      */
476     @Override
477     public String handleGetGetterSetterTypeName()
478     {
479         String name = null;
480         // TODO: Change to check upperBound > 1, not isMany or Array/Collection types
481         if (this.isMany() && !this.getType().isArrayType() && !this.getType().isCollectionType())
482         {
483             final TypeMappings mappings = this.getLanguageMappings();
484             if (this.hasStereotype(UMLProfile.STEREOTYPE_UNIQUE))
485             {
486                 name =
487                     isOrdered() ? mappings.getTo(UMLProfile.ORDERED_SET_TYPE_NAME) : mappings.getTo(
488                         UMLProfile.SET_TYPE_NAME);
489             }
490             else
491             {
492                 name =
493                     isOrdered() ? mappings.getTo(UMLProfile.LIST_TYPE_NAME) : mappings.getTo(
494                         UMLProfile.COLLECTION_TYPE_NAME);
495             }
496 
497             // set this attribute's type as a template parameter if required
498             if (BooleanUtils.toBoolean(
499                     ObjectUtils.toString(this.getConfiguredProperty(UMLMetafacadeProperties.ENABLE_TEMPLATING)))
500                     && this.getType() != null)
501             {
502                 String type = this.getType().getFullyQualifiedName();
503                 /*Collection<GeneralizableElementFacade> specializations = this.getType().getAllSpecializations();
504                 if ((specializations != null && !specializations.isEmpty()))
505                 {
506                     name += "<? extends " + type + '>';
507                 }
508                 else
509                 {*/
510                     name += '<' + type + '>';
511                 //}
512             }
513         }
514         if (name == null && this.getType() != null)
515         {
516             name = this.getType().getFullyQualifiedName();
517         }
518         return name;
519     }
520 
521     /**
522      * Get the UML upper multiplicity
523      */
524     @Override
525     protected int handleGetUpper()
526     {
527         return this.getMultiplicityRangeUpper();
528      }
529 
530     /**
531      * Get the UML lower multiplicity
532      */
533     @Override
534     protected int handleGetLower()
535     {
536         return this.getMultiplicityRangeLower();
537     }
538 
539     /**
540      * @see org.andromda.metafacades.uml.AttributeFacade#isDerived()
541      */
542     @Override
543     protected boolean handleIsDerived()
544     {
545         // UML 1.4 does not have derived attribute.
546         return false;
547     }
548 }