001package org.andromda.metafacades.uml14; 002 003import java.util.Collection; 004import org.andromda.metafacades.uml.ClassifierFacade; 005import org.andromda.metafacades.uml.NameMasker; 006import org.andromda.metafacades.uml.TypeMappings; 007import org.andromda.metafacades.uml.UMLMetafacadeProperties; 008import org.andromda.metafacades.uml.UMLMetafacadeUtils; 009import org.andromda.metafacades.uml.UMLProfile; 010import org.andromda.utils.StringUtilsHelper; 011import org.apache.commons.lang.BooleanUtils; 012import org.apache.commons.lang.ObjectUtils; 013import org.apache.commons.lang.StringUtils; 014import org.omg.uml.foundation.core.AssociationEnd; 015import org.omg.uml.foundation.core.Classifier; 016import org.omg.uml.foundation.core.UmlAssociation; 017import org.omg.uml.foundation.datatypes.AggregationKindEnum; 018import org.omg.uml.foundation.datatypes.ChangeableKindEnum; 019import org.omg.uml.foundation.datatypes.Multiplicity; 020import org.omg.uml.foundation.datatypes.MultiplicityRange; 021import org.omg.uml.foundation.datatypes.OrderingKind; 022import org.omg.uml.foundation.datatypes.OrderingKindEnum; 023 024/** 025 * Metaclass facade implementation. 026 * @author Bob Fields 027 */ 028public class AssociationEndFacadeLogicImpl 029 extends AssociationEndFacadeLogic 030{ 031 private static final long serialVersionUID = 34L; 032 /** 033 * @param metaObject 034 * @param context 035 */ 036 public AssociationEndFacadeLogicImpl( 037 org.omg.uml.foundation.core.AssociationEnd metaObject, 038 String context) 039 { 040 super(metaObject, context); 041 } 042 043 /** 044 * @see org.andromda.core.metafacade.MetafacadeBase#getValidationOwner() 045 */ 046 public ClassifierFacade getValidationOwner() 047 { 048 return this.getType(); 049 } 050 051 /** 052 * @see org.andromda.metafacades.uml.AssociationEndFacade#getOtherEnd() 053 */ 054 @Override 055 protected AssociationEnd handleGetOtherEnd() 056 { 057 final Collection<AssociationEnd> ends = metaObject.getAssociation().getConnection(); 058 for (final AssociationEnd end : ends) 059 { 060 if (!metaObject.equals(end)) 061 { 062 return end; 063 } 064 } 065 return null; 066 } 067 068 /** 069 * @see org.andromda.metafacades.uml14.ModelElementFacadeLogic#handleGetName() 070 */ 071 protected String handleGetName() 072 { 073 String name = super.handleGetName(); 074 075 // if name is empty, then get the name from the type 076 if (StringUtils.isEmpty(name)) 077 { 078 final ClassifierFacade type = this.getType(); 079 if (type != null) 080 { 081 name = StringUtils.uncapitalize(StringUtils.trimToEmpty(type.getName())); 082 } 083 } 084 if (this.isMany() && this.isPluralizeAssociationEndNames()) 085 { 086 name = StringUtilsHelper.pluralize(name); 087 } 088 final String nameMask = 089 String.valueOf(this.getConfiguredProperty(UMLMetafacadeProperties.CLASSIFIER_PROPERTY_NAME_MASK)); 090 return NameMasker.mask( 091 name, 092 nameMask); 093 } 094 095 /** 096 * Indicates whether or not we should pluralize association end names. 097 * 098 * @return true/false 099 */ 100 private boolean isPluralizeAssociationEndNames() 101 { 102 final Object value = this.getConfiguredProperty(UMLMetafacadeProperties.PLURALIZE_ASSOCIATION_END_NAMES); 103 return value != null && Boolean.valueOf(String.valueOf(value)); 104 } 105 106 /** 107 * @return metaObject.getAggregation().toString() 108 * @see org.andromda.metafacades.uml.AssociationEndFacade#getAggregationKind() 109 */ 110 protected String handleGetAggregationKind() 111 { 112 return metaObject.getAggregation().toString(); 113 } 114 115 /** 116 * NOT IMPLEMENTED - UML2 only 117 * @return "" always 118 * @see org.andromda.metafacades.uml.AssociationEndFacade#getDefault() 119 */ 120 protected String handleGetDefault() 121 { 122 return ""; 123 } 124 125 /** 126 * @see org.andromda.metafacades.uml.AssociationEndFacade#getType() 127 */ 128 @Override 129 protected Classifier handleGetType() 130 { 131 return metaObject.getParticipant(); 132 } 133 134 /** 135 * @see org.andromda.metafacades.uml.AssociationEndFacade#isOne2Many() 136 */ 137 @Override 138 protected boolean handleIsOne2Many() 139 { 140 return !this.isMany() && this.getOtherEnd().isMany(); 141 } 142 143 /** 144 * @see org.andromda.metafacades.uml.AssociationEndFacade#isMany2Many() 145 */ 146 @Override 147 protected boolean handleIsMany2Many() 148 { 149 return this.isMany() && this.getOtherEnd().isMany(); 150 } 151 152 /** 153 * @see org.andromda.metafacades.uml.AssociationEndFacade#isOne2One() 154 */ 155 @Override 156 protected boolean handleIsOne2One() 157 { 158 return !this.isMany() && !this.getOtherEnd().isMany(); 159 } 160 161 /** 162 * @see org.andromda.metafacades.uml.AssociationEndFacade#isMany2One() 163 */ 164 @Override 165 protected boolean handleIsMany2One() 166 { 167 return this.isMany() && !this.getOtherEnd().isMany(); 168 } 169 170 /** 171 * @see org.andromda.metafacades.uml.AssociationEndFacade#isMany() 172 */ 173 @Override 174 protected boolean handleIsMany() 175 { 176 boolean isMany = false; 177 final Multiplicity multiplicity = this.metaObject.getMultiplicity(); 178 179 // we'll say a null multiplicity is 1 180 if (multiplicity != null) 181 { 182 final Collection<MultiplicityRange> ranges = multiplicity.getRange(); 183 if (ranges != null && !ranges.isEmpty()) 184 { 185 for (MultiplicityRange multiplicityRange : ranges) 186 { 187 final int upper = multiplicityRange.getUpper(); 188 isMany = upper > 1 || upper < 0; 189 } 190 } 191 } 192 if (null!=this.getType() && !isMany) 193 { 194 // isCollectionType causes too many problems with the metafacades 195 isMany = this.getType().isArrayType(); 196 } 197 return isMany; 198 } 199 200 /** 201 * UML2 Only: Returns false always. 202 * @return false 203 * @see org.andromda.metafacades.uml.AssociationEndFacade#isLeaf() 204 */ 205 @Override 206 public boolean handleIsLeaf() 207 { 208 return false; 209 } 210 211 /** 212 * @see org.andromda.metafacades.uml.AssociationEndFacade#isOrdered() 213 */ 214 @Override 215 protected boolean handleIsOrdered() 216 { 217 boolean ordered = false; 218 219 final OrderingKind ordering = metaObject.getOrdering(); 220 221 // no ordering is 'unordered' 222 if (ordering != null) 223 { 224 ordered = ordering.equals(OrderingKindEnum.OK_ORDERED); 225 } 226 227 return ordered; 228 } 229 230 /** 231 * UML2 Only: Returns false always. 232 * @return hasStereotype(UMLProfile.STEREOTYPE_UNIQUE) 233 * @see org.andromda.metafacades.uml.AssociationEndFacade#isUnique() 234 */ 235 @Override 236 public boolean handleIsUnique() 237 { 238 return this.hasStereotype(UMLProfile.STEREOTYPE_UNIQUE); 239 } 240 241 /** 242 * @see org.andromda.metafacades.uml.AssociationEndFacade#isAggregation() 243 */ 244 @Override 245 protected boolean handleIsAggregation() 246 { 247 return AggregationKindEnum.AK_AGGREGATE.equals(metaObject.getAggregation()); 248 } 249 250 /** 251 * @see org.andromda.metafacades.uml.AssociationEndFacade#isComposition() 252 */ 253 @Override 254 protected boolean handleIsComposition() 255 { 256 return AggregationKindEnum.AK_COMPOSITE.equals(metaObject.getAggregation()); 257 } 258 259 /** 260 * @see org.andromda.metafacades.uml.AssociationEndFacade#isReadOnly() 261 */ 262 @Override 263 protected boolean handleIsReadOnly() 264 { 265 return ChangeableKindEnum.CK_FROZEN.equals(metaObject.getChangeability()); 266 } 267 268 /** 269 * @see org.andromda.metafacades.uml.AssociationEndFacade#isNavigable() 270 */ 271 @Override 272 protected boolean handleIsNavigable() 273 { 274 return metaObject.isNavigable(); 275 } 276 277 /** 278 * @see org.andromda.metafacades.uml.AssociationEndFacade#getGetterName() 279 */ 280 @Override 281 protected String handleGetGetterName() 282 { 283 return UMLMetafacadeUtils.getGetterPrefix(this.getType()) + StringUtilsHelper.capitalize(this.getName()); 284 } 285 286 /** 287 * @see org.andromda.metafacades.uml.AssociationEndFacade#getSetterName() 288 */ 289 @Override 290 protected String handleGetSetterName() 291 { 292 return "set" + StringUtils.capitalize(this.getName()); 293 } 294 295 /** 296 * @see org.andromda.metafacades.uml.AssociationEndFacade#getAdderName() 297 */ 298 @Override 299 protected String handleGetAdderName() 300 { 301 return "add" + StringUtils.capitalize(this.getName()); 302 } 303 304 /** 305 * @see org.andromda.metafacades.uml.AssociationEndFacade#getRemoverName() 306 */ 307 @Override 308 protected String handleGetRemoverName() 309 { 310 return "remove" + StringUtils.capitalize(this.getName()); 311 } 312 313 /** 314 * @see org.andromda.metafacades.uml.AssociationEndFacade#isBindingDependenciesPresent() 315 */ 316 @Override 317 protected boolean handleIsBidirectional() 318 { 319 return isNavigable() && getOtherEnd().isNavigable(); 320 } 321 322 /** 323 * @see org.andromda.metafacades.uml.AssociationEndFacade#getAssociation() 324 */ 325 @Override 326 protected UmlAssociation handleGetAssociation() 327 { 328 return metaObject.getAssociation(); 329 } 330 331 /** 332 * @see org.andromda.metafacades.uml.AssociationEndFacade#getGetterSetterTypeName() 333 */ 334 @Override 335 protected String handleGetGetterSetterTypeName() 336 { 337 String name = null; 338 if (this.isMany() && this.getType()!=null && !this.getType().isArrayType() && !this.getType().isCollectionType()) 339 { 340 final TypeMappings mappings = this.getLanguageMappings(); 341 if (mappings != null) 342 { 343 name = 344 this.isOrdered() ? mappings.getTo(UMLProfile.LIST_TYPE_NAME) 345 : mappings.getTo(UMLProfile.COLLECTION_TYPE_NAME); 346 } 347 348 // set this association end's type as a template parameter if required 349 if (BooleanUtils.toBoolean( 350 ObjectUtils.toString(this.getConfiguredProperty(UMLMetafacadeProperties.ENABLE_TEMPLATING))) 351 && this.getType() != null) 352 { 353 String type = this.getType().getFullyQualifiedName(); 354 /*Collection<GeneralizableElementFacade> specializations = this.getType().getAllSpecializations(); 355 if ((specializations != null && !specializations.isEmpty())) 356 { 357 name += "<? extends " + type + '>'; 358 } 359 else 360 {*/ 361 name += '<' + type + '>'; 362 //} 363 } 364 } 365 if (name == null && this.getType() != null) 366 { 367 name = this.getType().getFullyQualifiedName(); 368 } 369 return name; 370 } 371 372 /** 373 * @see org.andromda.metafacades.uml.AssociationEndFacade#isRequired() 374 */ 375 @Override 376 protected boolean handleIsRequired() 377 { 378 final int lower = this.getMultiplicityRangeLower(); 379 return lower >= 1; 380 } 381 382 /** 383 * @see org.andromda.metafacades.uml.AssociationEndFacade#isChild() 384 */ 385 @Override 386 protected boolean handleIsChild() 387 { 388 return this.getOtherEnd() != null && this.getOtherEnd().isComposition(); 389 } 390 391 /** 392 * Returns the upper range of the multiplicity for the passed in attribute 393 * 394 * @return int the upper range of the multiplicity or 1 if it isn't defined. 395 */ 396 private int getMultiplicityRangeUpper() 397 { 398 Integer upper = null; 399 final Multiplicity multiplicity = metaObject.getMultiplicity(); 400 if (multiplicity != null) 401 { 402 final Collection<MultiplicityRange> ranges = multiplicity.getRange(); 403 if (ranges != null) 404 { 405 for (MultiplicityRange multiplicityRange : ranges) 406 { 407 upper = Integer.valueOf(multiplicityRange.getUpper()); 408 } 409 } 410 } 411 if (upper == null) 412 { 413 upper = Integer.valueOf(1); 414 } 415 return upper.intValue(); 416 } 417 418 /** 419 * Returns the lower range of the multiplicity for the passed in associationEnd 420 * 421 * @return int the lower range of the multiplicity or 1 if it isn't defined. 422 */ 423 private int getMultiplicityRangeLower() 424 { 425 Integer lower = null; 426 final Multiplicity multiplicity = this.metaObject.getMultiplicity(); 427 if (multiplicity != null) 428 { 429 final Collection<MultiplicityRange> ranges = multiplicity.getRange(); 430 if (ranges != null) 431 { 432 for (MultiplicityRange multiplicityRange : ranges) 433 { 434 lower = Integer.valueOf(multiplicityRange.getLower()); 435 } 436 } 437 } 438 if (lower == null) 439 { 440 final String defaultMultiplicity = this.getDefaultMultiplicity(); 441 if (defaultMultiplicity.startsWith("0")) 442 { 443 lower = Integer.valueOf(0); 444 } 445 else 446 { 447 lower = Integer.valueOf(1); 448 } 449 } 450 return lower.intValue(); 451 } 452 453 /** 454 * Gets the default multiplicity for this attribute (the 455 * multiplicity if none is defined). 456 * 457 * @return the default multiplicity as a String. 458 */ 459 private String getDefaultMultiplicity() 460 { 461 return ObjectUtils.toString(this.getConfiguredProperty(UMLMetafacadeProperties.DEFAULT_MULTIPLICITY)); 462 } 463 464 /** 465 * Get the UML upper multiplicity 466 * Not implemented for UML1.4 467 */ 468 @Override 469 protected int handleGetUpper() 470 { 471 return this.getMultiplicityRangeUpper(); 472 } 473 474 /** 475 * Get the UML lower multiplicity 476 */ 477 @Override 478 protected int handleGetLower() 479 { 480 return this.getMultiplicityRangeLower(); 481 } 482 483 /** 484 * @see org.andromda.metafacades.uml14.AssociationEndFacadeLogic#handleIsDerived() 485 */ 486 @Override 487 protected boolean handleIsDerived() 488 { 489 // UML 1.4 does not have derived association ends. 490 return false; 491 } 492 493 /** 494 * UML2 only. Can't determine association scope in UML14. 495 * @see org.andromda.metafacades.uml.AttributeFacade#isStatic() 496 */ 497 @Override 498 public boolean handleIsStatic() 499 { 500 return false; 501 } 502}