001package org.andromda.cartridges.ejb3.metafacades; 002 003import java.text.MessageFormat; 004import java.util.ArrayList; 005import java.util.Collection; 006import java.util.Hashtable; 007import java.util.Map; 008import org.andromda.cartridges.ejb3.EJB3Globals; 009import org.andromda.cartridges.ejb3.EJB3Profile; 010import org.andromda.metafacades.uml.AssociationEndFacade; 011import org.andromda.metafacades.uml.AttributeFacade; 012import org.andromda.metafacades.uml.ClassifierFacade; 013import org.andromda.metafacades.uml.Entity; 014import org.andromda.metafacades.uml.EntityMetafacadeUtils; 015import org.andromda.metafacades.uml.MetafacadeUtils; 016import org.andromda.metafacades.uml.ModelElementFacade; 017import org.andromda.metafacades.uml.TaggedValueFacade; 018import org.andromda.metafacades.uml.TypeMappings; 019import org.andromda.metafacades.uml.UMLMetafacadeProperties; 020import org.andromda.metafacades.uml.UMLMetafacadeUtils; 021import org.andromda.metafacades.uml.UMLProfile; 022import org.apache.commons.lang.BooleanUtils; 023import org.apache.commons.lang.ObjectUtils; 024import org.apache.commons.lang.StringUtils; 025 026/** 027 * <p/> 028 * Represents an EJB association end. </p> 029 * MetafacadeLogic implementation for org.andromda.cartridges.ejb3.metafacades.EJB3AssociationEndFacade. 030 * 031 * @see EJB3AssociationEndFacade 032 */ 033public class EJB3AssociationEndFacadeLogicImpl 034 extends EJB3AssociationEndFacadeLogic 035{ 036 private static final long serialVersionUID = 34L; 037 /** 038 * The default composite association cascade property 039 */ 040 private static final String ENTITY_DEFAULT_COMPOSITE_CASCADE = "entityCompositeCascade"; 041 042 /** 043 * The default aggregation association cascade property 044 */ 045 private static final String ENTITY_DEFAULT_AGGREGATION_CASCADE = "entityAggregationCascade"; 046 047 /** 048 * The namespace property storing default collection type for associations 049 */ 050 private static final String ASSOCIATION_COLLECTION_TYPE = "associationCollectionType"; 051 052 /** 053 * A flag indicating whether or not specific (java.util.Set, java.util.List, 054 * etc) collection interfaces should be used in assocation mutators and 055 * accessors or whether the generic java.util.Collection interface should be 056 * used. 057 */ 058 private static final String SPECIFIC_COLLECTION_INTERFACES = "specificCollectionInterfaces"; 059 060 /** 061 * The property that defines the default collection interface, this is the 062 * interface used if the property defined by 063 * {@link #SPECIFIC_COLLECTION_INTERFACES} is false. 064 */ 065 private static final String DEFAULT_COLLECTION_INTERFACE = "defaultCollectionInterface"; 066 067 /** 068 * Stores the default collection index name. 069 */ 070 private static final String COLLECTION_INDEX_NAME = "associationEndCollectionIndexName"; 071 072 /** 073 * Stores the default collection index type. 074 */ 075 private static final String COLLECTION_INDEX_TYPE = "associationEndCollectionIndexType"; 076 077 /** 078 * Represents the EJB3 <code>ALL</code> cascade option and fully qualified representation. 079 */ 080 private static final String ENTITY_CASCADE_ALL = "ALL"; 081 private static final String ENTITY_CASCADE_ALL_FQN = "javax.persistence.CascadeType.ALL"; 082 083 /** 084 * Represents the EJB3 <code>PERSIST</code> cascade option. 085 */ 086 private static final String ENTITY_CASCADE_PERSIST = "PERSIST"; 087 private static final String ENTITY_CASCADE_PERSIST_FQN = "javax.persistence.CascadeType.PERSIST"; 088 089 /** 090 * Represents the EJB3 <code>MERGE</code> cascade option. 091 */ 092 private static final String ENTITY_CASCADE_MERGE = "MERGE"; 093 private static final String ENTITY_CASCADE_MERGE_FQN = "javax.persistence.CascadeType.MERGE"; 094 095 /** 096 * Represents the EJB3 <code>REMOVE</code> cascade option. 097 */ 098 private static final String ENTITY_CASCADE_REMOVE = "REMOVE"; 099 private static final String ENTITY_CASCADE_REMOVE_FQN = "javax.persistence.CascadeType.REMOVE"; 100 101 /** 102 * Represents the EJB3 <code>REFRESH</code> cascade option. 103 */ 104 private static final String ENTITY_CASCADE_REFRESH = "REFRESH"; 105 private static final String ENTITY_CASCADE_REFRESH_FQN = "javax.persistence.CascadeType.REFRESH"; 106 107 /** 108 * Represents the value used to represents NO cascade option. 109 */ 110 private static final String ENTITY_CASCADE_NONE = "NONE"; 111 112 /** 113 * Stores the cascade map of fully qualified cascade types 114 */ 115 private static final Map<String, String> cascadeTable = new Hashtable<String, String>(); 116 117 static 118 { 119 cascadeTable.put(ENTITY_CASCADE_ALL, ENTITY_CASCADE_ALL_FQN); 120 cascadeTable.put(ENTITY_CASCADE_PERSIST, ENTITY_CASCADE_PERSIST_FQN); 121 cascadeTable.put(ENTITY_CASCADE_MERGE, ENTITY_CASCADE_MERGE_FQN); 122 cascadeTable.put(ENTITY_CASCADE_REMOVE, ENTITY_CASCADE_REMOVE_FQN); 123 cascadeTable.put(ENTITY_CASCADE_REFRESH, ENTITY_CASCADE_REFRESH_FQN); 124 } 125 126 /** 127 * Value for set 128 */ 129 private static final String COLLECTION_TYPE_SET = "set"; 130 131 /** 132 * Value for map 133 */ 134 private static final String COLLECTION_TYPE_MAP = "map"; 135 136 /** 137 * Value for list 138 */ 139 private static final String COLLECTION_TYPE_LIST = "list"; 140 141 /** 142 * Value for collections 143 */ 144 private static final String COLLECTION_TYPE_COLLECTION = "bag"; 145 146 /** 147 * Stores the valid collection types 148 */ 149 private static final Collection<String> collectionTypes = new ArrayList<String>(); 150 151 static 152 { 153 collectionTypes.add(COLLECTION_TYPE_SET); 154 collectionTypes.add(COLLECTION_TYPE_MAP); 155 collectionTypes.add(COLLECTION_TYPE_LIST); 156 collectionTypes.add(COLLECTION_TYPE_COLLECTION); 157 } 158 159 /** 160 * Stores the property indicating whether or not composition should define 161 * the eager loading strategy and aggregation define lazy loading strategy. 162 */ 163 private static final String COMPOSITION_DEFINES_EAGER_LOADING = "compositionDefinesEagerLoading"; 164 165 /** 166 * The property that stores whether relationship collection caching is enabled. 167 */ 168 private static final String HIBERNATE_ASSOCIATION_ENABLE_CACHE = "hibernateEnableAssociationsCache"; 169 170 /** 171 * Stores the default cache strategy for relationship Collections. 172 */ 173 private static final String HIBERNATE_ASSOCIATION_CACHE = "hibernateAssociationCache"; 174 175 /** 176 * The 'list' type implementation to use. 177 */ 178 private static final String LIST_TYPE_IMPLEMENTATION = "listTypeImplementation"; 179 180 /** 181 * The 'set' type implementation to use. 182 */ 183 private static final String SET_TYPE_IMPLEMENTATION = "setTypeImplementation"; 184 185 /** 186 * The 'map' type implementation to use. 187 */ 188 private static final String MAP_TYPE_IMPLEMENTATION = "mapTypeImplementation"; 189 190 // ---------------- constructor ------------------------------- 191 192 /** 193 * @param metaObject 194 * @param context 195 */ 196 public EJB3AssociationEndFacadeLogicImpl(final Object metaObject, final String context) 197 { 198 super (metaObject, context); 199 } 200 201 // --------------- methods --------------------- 202 203 /** 204 * @see AssociationEndFacade#getGetterSetterTypeName() 205 */ 206 @Override public String getGetterSetterTypeName() 207 { 208 String getterSetterTypeName = null; 209 210 if (this.isMany()) 211 { 212 final boolean specificInterfaces = 213 Boolean.valueOf( 214 ObjectUtils.toString(this.getConfiguredProperty(SPECIFIC_COLLECTION_INTERFACES))).booleanValue(); 215 216 final TypeMappings mappings = this.getLanguageMappings(); 217 if (mappings != null) 218 { 219 if (this.isMap()) 220 { 221 getterSetterTypeName = mappings.getTo(UMLProfile.MAP_TYPE_NAME); 222 } 223 else if (specificInterfaces) 224 { 225 if (this.isSet()) 226 { 227 getterSetterTypeName = mappings.getTo(UMLProfile.SET_TYPE_NAME); 228 } 229 else if (this.isList()) 230 { 231 getterSetterTypeName = mappings.getTo(UMLProfile.LIST_TYPE_NAME); 232 } 233 else if (this.isCollection()) 234 { 235 getterSetterTypeName = mappings.getTo(UMLProfile.COLLECTION_TYPE_NAME); 236 } 237 } 238 else 239 { 240 getterSetterTypeName = this.getDefaultCollectionInterface(); 241 } 242 } 243 else 244 { 245 getterSetterTypeName = this.getDefaultCollectionInterface(); 246 } 247 } 248 else 249 { 250 final ClassifierFacade type = this.getType(); 251 if (type instanceof EJB3EntityFacade) 252 { 253 final String typeName = ((EJB3EntityFacade)type).getFullyQualifiedEntityName(); 254 if (StringUtils.isNotBlank(typeName)) 255 { 256 getterSetterTypeName = typeName; 257 } 258 } 259 } 260 261 if (getterSetterTypeName == null) 262 { 263 getterSetterTypeName = super.getGetterSetterTypeName(); 264 } 265 else if (this.isMany()) 266 { 267 /** 268 * Set this association end's type as a template parameter if required 269 */ 270 if ("true".equals(this.getConfiguredProperty(UMLMetafacadeProperties.ENABLE_TEMPLATING))) 271 { 272 getterSetterTypeName += '<' 273 + (this.isMap() ? this.getCollectionIndexType() + ", " : "") 274 + this.getType().getFullyQualifiedName() + '>'; 275 } 276 } 277 return getterSetterTypeName; 278 } 279 280 /** 281 * Overridden to provide handling of inheritance. 282 * 283 * @see AssociationEndFacade#isRequired() 284 */ 285 @Override 286 public boolean isRequired() 287 { 288 // TODO: Fix UML Association isRequired to use getOtherEnd 289 boolean required = super.isRequired(); 290 Object type = this.getOtherEnd().getType(); 291 292 if ((type != null) && EJB3EntityFacade.class.isAssignableFrom(type.getClass())) 293 { 294 EJB3EntityFacade entity = (EJB3EntityFacade)type; 295 296 /** 297 * Exclude ONLY if single table inheritance exists 298 */ 299 if (entity.isRequiresGeneralizationMapping() && entity.isInheritanceSingleTable() 300 && !entity.isEmbeddableSuperclassGeneralizationExists()) 301 { 302 required = false; 303 } 304 } 305 306 return required; 307 } 308 309 /** 310 * @return fetch type 311 * @see EJB3AssociationEndFacade#getFetchType() 312 */ 313 @Override 314 protected String handleGetFetchType() 315 { 316 String fetchType = (String)this.findTaggedValue(EJB3Profile.TAGGEDVALUE_PERSISTENCE_FETCH_TYPE); 317 318 if (StringUtils.isBlank(fetchType)) 319 { 320 // check whether or not composition defines eager loading is turned on 321 final boolean compositionDefinesEagerLoading = 322 Boolean.valueOf(String.valueOf(this.getConfiguredProperty(COMPOSITION_DEFINES_EAGER_LOADING))) 323 .booleanValue(); 324 325 if (compositionDefinesEagerLoading) 326 { 327 if (this.getOtherEnd().isComposition()) 328 { 329 fetchType = EJB3Globals.FETCH_TYPE_EAGER; 330 } 331 else if (this.getOtherEnd().isAggregation()) 332 { 333 fetchType = EJB3Globals.FETCH_TYPE_LAZY; 334 } 335 } 336 } 337 338 /** 339 * Go for defaults if blank 340 */ 341 if (StringUtils.isBlank(fetchType)) 342 { 343 if (this.getOtherEnd().isOne2Many() || this.getOtherEnd().isMany2Many()) 344 { 345 fetchType = EJB3Globals.FETCH_TYPE_LAZY; 346 } 347 else 348 { 349 fetchType = EJB3Globals.FETCH_TYPE_EAGER; 350 } 351 } 352 return fetchType; 353 } 354 355 /** 356 * @see EJB3AssociationEndFacadeLogic#handleIsEager() 357 */ 358 @Override 359 protected boolean handleIsEager() 360 { 361 boolean isEager = false; 362 if (StringUtils.isNotBlank(this.getFetchType())) 363 { 364 if (EJB3Globals.FETCH_TYPE_EAGER.equalsIgnoreCase(this.getFetchType())) 365 { 366 isEager = true; 367 } 368 } 369 return isEager; 370 } 371 372 /** 373 * @see EJB3AssociationEndFacadeLogic#handleIsLazy() 374 */ 375 @Override 376 protected boolean handleIsLazy() 377 { 378 boolean isLazy = false; 379 if (StringUtils.isNotBlank(this.getFetchType())) 380 { 381 if (EJB3Globals.FETCH_TYPE_LAZY.equalsIgnoreCase(this.getFetchType())) 382 { 383 isLazy = true; 384 } 385 } 386 return isLazy; 387 } 388 389 /** 390 * @see EJB3AssociationEndFacadeLogic#handleIsOwning() 391 */ 392 @Override 393 protected boolean handleIsOwning() 394 { 395 return !UMLMetafacadeUtils.isOwningEnd(this); 396 /*boolean owning = false; 397 if (this.isAggregation() || this.isComposition() || !this.getOtherEnd().isNavigable() 398 || BooleanUtils.toBoolean( 399 ObjectUtils.toString(this.findTaggedValue( 400 EJB3Profile.TAGGEDVALUE_PERSISTENCE_ASSOCIATION_END_PRIMARY)))) 401 { 402 owning = true; 403 } 404 // See if this end or the other end is tagged as the association owner 405 else if (BooleanUtils.toBoolean( 406 ObjectUtils.toString(this.getOtherEnd().findTaggedValue( 407 EJB3Profile.TAGGEDVALUE_PERSISTENCE_ASSOCIATION_END_PRIMARY)))) 408 { 409 owning = false; 410 } 411 // If other end not tagged, the many side of 1:M owns the bidirectional relationship 412 else if (this.isMany() && !this.getOtherEnd().isMany()) 413 { 414 owning = true; 415 } 416 // Other side: aggregation/composition owns the bidirectional relationship 417 else if (this.getOtherEnd().isAggregation() || this.getOtherEnd().isComposition()) 418 { 419 owning = false; 420 } 421 // Other side: the many side of 1:M owns the bidirectional relationship if no composition/aggregation 422 else if (!this.isMany() && this.getOtherEnd().isMany()) 423 { 424 owning = false; 425 } 426 // If bidirectional 1:1 or M:M, choose the side with the longest type name because it typically indicates a composition relationship 427 //else if (this.getOtherEnd().getType().getName().length() 428 // > this.getType().getName().length()) 429 else if (this.getName().length() 430 > this.getOtherEnd().getName().length()) 431 { 432 owning = true; 433 } 434 // If length is the same, alphabetically earliest is the owner 435 else if (this.getName().compareTo( 436 this.getOtherEnd().getName()) < 0) 437 { 438 owning = true; 439 } 440 //System.out.println("handleIsOwning=" + owning + " for " + this.getName() + " OName=" + this.getOtherEnd().getName() + " Aggregation=" + this.isAggregation() + " Aggregation=" + this.isAggregation() + " Composition=" + this.isComposition() + " !Navigable=" + !this.isNavigable() + " Many=" + this.isMany() + " OMany=" + this.getOtherEnd().isMany() + " Upper=" + this.getUpper() + " OUpper=" + this.getOtherEnd().getUpper() + " OAggregation=" + this.getOtherEnd().isAggregation() + " OComposition=" + this.getOtherEnd().isComposition() + " ONavigable=" + this.getOtherEnd().isNavigable() + this); 441 return owning;*/ 442 } 443 444 /** 445 * @see EJB3AssociationEndFacadeLogic#handleIsOptional() 446 */ 447 @Override 448 protected boolean handleIsOptional() 449 { 450 boolean optional = true; 451 String optionalString = (String)this.findTaggedValue(EJB3Profile.TAGGEDVALUE_PERSISTENCE_OPTIONAL); 452 453 if (StringUtils.isBlank(optionalString)) 454 { 455 optional = !this.isRequired(); 456 } 457 else 458 { 459 optional = Boolean.valueOf(optionalString).booleanValue(); 460 } 461 return optional; 462 } 463 464 /** 465 * @see EJB3AssociationEndFacadeLogic#handleGetOrderByClause() 466 */ 467 @Override 468 protected String handleGetOrderByClause() 469 { 470 return (String)this.findTaggedValue(EJB3Profile.TAGGEDVALUE_PERSISTENCE_ORDERBY); 471 } 472 473 /** 474 * @see EJB3AssociationEndFacadeLogic#handleGetColumnDefinition() 475 */ 476 @Override 477 protected String handleGetColumnDefinition() 478 { 479 return (String)this.findTaggedValue(EJB3Profile.TAGGEDVALUE_PERSISTENCE_COLUMN_DEFINITION); 480 } 481 482 /** 483 * Returns true if the tagged name exists for this association end. 484 * 485 * @param name The tagged name to lookup. 486 * @return boolean True if the tagged name exists. False otherwise. 487 * 488 * @see EJB3AssociationEndFacadeLogic#handleHasTaggedValue(String) 489 */ 490 @Override 491 protected boolean handleHasTaggedValue(String name) 492 { 493 boolean exists = false; 494 if (StringUtils.isNotBlank(name)) 495 { 496 // trim to remove leading/trailing spaces 497 name = StringUtils.trimToEmpty(name); 498 499 // loop over tagged values and match the argument tagged value name 500 for (TaggedValueFacade taggedValue : this.getTaggedValues()) 501 { 502 // return with true on the first match found 503 //if (name.equals(taggedValue.getName())) 504 String tagName = taggedValue.getName(); 505 if (name.equals(tagName) || MetafacadeUtils.getEmfTaggedValue(name).equals(tagName) 506 || MetafacadeUtils.getUml14TaggedValue(name).equals(tagName)) 507 { 508 exists = true; 509 break; 510 } 511 } 512 } 513 return exists; 514 } 515 516 /** 517 * Resolves a comma separated list of cascade types from andromda.xml 518 519 * @param cascadesString 520 * @return fully qualified cascade type sequence 521 */ 522 private String getFullyQualifiedCascadeTypeList(final String cascadesString) 523 { 524 StringBuilder buf = null; 525 if (StringUtils.isNotBlank(cascadesString)) 526 { 527 String[] ct = cascadesString.split(","); 528 for (int i = 0; i < ct.length; i++) 529 { 530 final String value = ct[i].trim(); 531 if (StringUtils.isNotBlank(value)) 532 { 533 if (buf == null) 534 { 535 buf = new StringBuilder(); 536 } 537 else 538 { 539 buf.append(", "); 540 } 541 542 buf.append(cascadeTable.get(value)); 543 } 544 } 545 } 546 return buf == null ? null : buf.toString(); 547 } 548 549 /** 550 * @see EJB3AssociationEndFacadeLogic#handleGetCascadeType() 551 */ 552 @Override 553 protected String handleGetCascadeType() 554 { 555 String cascade = null; 556 final Collection<Object> taggedValues = this.findTaggedValues(EJB3Profile.TAGGEDVALUE_PERSISTENCE_CASCADE_TYPE); 557 if (taggedValues != null && !taggedValues.isEmpty()) 558 { 559 StringBuilder buf = null; 560 for (Object value : taggedValues) 561 { 562 if (buf == null) 563 { 564 buf = new StringBuilder(); 565 } 566 else 567 { 568 buf.append(", "); 569 } 570 if (StringUtils.isNotBlank((String)value)) 571 { 572 buf.append(cascadeTable.get(value)); 573 } 574 } 575 if (buf != null) 576 { 577 cascade = buf.toString(); 578 } 579 } 580 else if ((this.getOtherEnd() != null) && 581 (this.getOtherEnd().isAggregation() || this.getOtherEnd().isComposition())) 582 { 583 cascade = cascadeTable.get(ENTITY_CASCADE_REMOVE); 584 if (this.getOtherEnd().isComposition()) 585 { 586 if (StringUtils.isBlank(this.getCompositionCascadeType())) 587 { 588 if (this.getType() instanceof EJB3EntityFacade) 589 { 590 EJB3EntityFacade entity = (EJB3EntityFacade)this.getType(); 591 cascade = (ENTITY_CASCADE_NONE.equalsIgnoreCase(entity.getDefaultCascadeType()) ? 592 null : this.getFullyQualifiedCascadeTypeList(entity.getDefaultCascadeType())); 593 } 594 } 595 else 596 { 597 cascade = (ENTITY_CASCADE_NONE.equalsIgnoreCase(this.getCompositionCascadeType()) ? 598 null : this.getFullyQualifiedCascadeTypeList(this.getCompositionCascadeType())); 599 } 600 } 601 else if (this.getOtherEnd().isAggregation()) 602 { 603 if (StringUtils.isBlank(this.getAggregationCascadeType())) 604 { 605 if (this.getType() instanceof EJB3EntityFacade) 606 { 607 EJB3EntityFacade entity = (EJB3EntityFacade)this.getType(); 608 cascade = (ENTITY_CASCADE_NONE.equalsIgnoreCase(entity.getDefaultCascadeType()) ? 609 null : this.getFullyQualifiedCascadeTypeList(entity.getDefaultCascadeType())); 610 } 611 } 612 else 613 { 614 cascade = (ENTITY_CASCADE_NONE.equalsIgnoreCase(this.getAggregationCascadeType()) ? 615 null : this.getFullyQualifiedCascadeTypeList(this.getAggregationCascadeType())); 616 } 617 } 618 } 619 else if (this.isComposition()) 620 { 621 /* 622 * On the composite side of the relationship, always enforce no cascade delete 623 * property indicating no cascadable propagation - overriding a default cascade 624 * value 625 */ 626 // TODO cascade can only be null at this point - anything else to change? 627 //cascade = null; 628 } 629 else if (this.isAggregation()) 630 { 631 /* 632 * On the aggregation side of the relationship, always enforce no cascade delete 633 * property indicating no cascadable propagation - overriding a default cascade 634 * value 635 */ 636 // TODO cascade can only be null at this point - anything else to change? 637 //cascade = null; 638 } 639 return cascade; 640 } 641 642 /** 643 * @see EJB3AssociationEndFacadeLogic#handleGetCompositionCascadeType() 644 */ 645 @Override 646 protected String handleGetCompositionCascadeType() 647 { 648 return StringUtils.trimToEmpty( 649 ObjectUtils.toString(this.getConfiguredProperty(ENTITY_DEFAULT_COMPOSITE_CASCADE))); 650 } 651 652 /** 653 * @see EJB3AssociationEndFacadeLogic#handleGetAggregationCascadeType() 654 */ 655 @Override 656 protected String handleGetAggregationCascadeType() 657 { 658 return StringUtils.trimToEmpty( 659 ObjectUtils.toString(this.getConfiguredProperty(ENTITY_DEFAULT_AGGREGATION_CASCADE))); 660 } 661 662 /** 663 * @see EJB3AssociationEndFacadeLogic#handleGetCollectionType() 664 */ 665 @Override 666 protected String handleGetCollectionType() 667 { 668 String collectionType = this.getSpecificCollectionType(); 669 if (!collectionTypes.contains(collectionType)) 670 { 671 if (this.isOrdered()) 672 { 673 collectionType = COLLECTION_TYPE_LIST; 674 } 675 else 676 { 677 collectionType = 678 (String)this.getConfiguredProperty(ASSOCIATION_COLLECTION_TYPE); 679 } 680 } 681 return collectionType; 682 } 683 684 /** 685 * @see EJB3AssociationEndFacadeLogic#handleGetCollectionTypeImplemenationClass() 686 */ 687 @Override 688 protected String handleGetCollectionTypeImplemenationClass() 689 { 690 String collectionTypeImplementationClass = null; 691 if (this.isMany()) 692 { 693 if (this.isSet()) 694 { 695 collectionTypeImplementationClass = String.valueOf( 696 this.getConfiguredProperty(SET_TYPE_IMPLEMENTATION)); 697 } 698 else if (this.isMap()) 699 { 700 collectionTypeImplementationClass = String.valueOf( 701 this.getConfiguredProperty(MAP_TYPE_IMPLEMENTATION)); 702 } 703 else if (this.isList() || this.isCollection()) 704 { 705 collectionTypeImplementationClass = String.valueOf( 706 this.getConfiguredProperty(LIST_TYPE_IMPLEMENTATION)); 707 } 708 } 709 return collectionTypeImplementationClass; 710 } 711 712 /** 713 * @see EJB3AssociationEndFacadeLogic#handleGetCollectionTypeImplementation() 714 */ 715 @Override 716 protected String handleGetCollectionTypeImplementation() 717 { 718 return this.getCollectionTypeImplementation(null); 719 } 720 721 /** 722 * @see EJB3AssociationEndFacadeLogic#handleGetCollectionTypeImplementation(String) 723 */ 724 @Override 725 protected String handleGetCollectionTypeImplementation(final String arg) 726 { 727 StringBuilder implementation = new StringBuilder(); 728 if (this.isMany()) 729 { 730 implementation.append("new "); 731 implementation.append(this.getCollectionTypeImplemenationClass()); 732 733 // set this association end's type as a template parameter if required 734 if (Boolean.valueOf(String.valueOf(this.getConfiguredProperty(UMLMetafacadeProperties.ENABLE_TEMPLATING))) 735 .booleanValue()) 736 { 737 implementation.append("<"); 738 if (this.isMap()) 739 { 740 implementation.append(this.getCollectionIndexType()); 741 implementation.append(", "); 742 } 743 implementation.append(this.getType().getFullyQualifiedName()); 744 implementation.append(">"); 745 } 746 implementation.append("("); 747 if (StringUtils.isNotBlank(arg)) 748 { 749 implementation.append(arg); 750 } 751 implementation.append(")"); 752 } 753 754 return implementation.toString(); 755 } 756 757 /** 758 * Gets the collection type defined on this association end. 759 * 760 * @return the specific collection type. 761 */ 762 private String getSpecificCollectionType() 763 { 764 return ObjectUtils.toString( 765 this.findTaggedValue(EJB3Profile.TAGGEDVALUE_ASSOCIATION_COLLECTION_TYPE)); 766 } 767 768 /** 769 * @see EJB3AssociationEndFacadeLogic#handleGetCollectionIndexType() 770 */ 771 @Override 772 protected String handleGetCollectionIndexType() 773 { 774 Object value = this.findTaggedValue(EJB3Profile.TAGGEDVALUE_ASSOCIATION_INDEX_TYPE); 775 if (value == null) 776 { 777 Object name = this.findTaggedValue(EJB3Profile.TAGGEDVALUE_ASSOCIATION_INDEX); 778 if (name == null) 779 { 780 ClassifierFacade facade = this.getOtherEnd().getType(); 781 if (facade instanceof EJB3EntityFacade) 782 { 783 // Find the identifier 784 ModelElementFacade identifier = ((EJB3EntityFacade)facade).getIdentifier(); 785 if (identifier instanceof AttributeFacade) 786 { 787 value = ((AttributeFacade)identifier).getType().getFullyQualifiedName(); 788 return value.toString(); 789 } 790 else if (identifier instanceof AssociationEndFacade) 791 { 792 value = ((AssociationEndFacade)identifier).getType().getFullyQualifiedName(); 793 return value.toString(); 794 } 795 } 796 } 797 // Find the attribute corresponding to name 798 Collection<AttributeFacade> attributes = ((EJB3EntityFacade)this.getOtherEnd().getType()).getAttributes(); 799 for (AttributeFacade attrib : attributes) 800 { 801 EJB3EntityAttributeFacade attribute = (EJB3EntityAttributeFacade)attrib; 802 if (attribute.getName().equals(name)) 803 { 804 value = attribute.getType().getFullyQualifiedName(); 805 return value.toString(); 806 } 807 } 808 809 // value can only be null at this point 810 value = this.getConfiguredProperty(COLLECTION_INDEX_TYPE); 811 if (StringUtils.isBlank(ObjectUtils.toString(value))) 812 { 813 value = null; 814 } 815 } 816 817 if (value != null) 818 { 819 if (value instanceof String) 820 { 821 value = this.getRootPackage().findModelElement((String)value); 822 } 823 if (value instanceof EJB3TypeFacade) 824 { 825 value = ((EJB3TypeFacade)value).getFullyQualifiedEJB3Type(); 826 } 827 } 828 return (value != null) ? ObjectUtils.toString(value) : null; 829 } 830 831 /** 832 * @see EJB3AssociationEndFacadeLogic#handleGetCollectionIndexName() 833 */ 834 @Override 835 protected String handleGetCollectionIndexName() 836 { 837 Object value = this.findTaggedValue(EJB3Profile.TAGGEDVALUE_ASSOCIATION_INDEX); 838 if ((value == null) && this.isConfiguredProperty(COLLECTION_INDEX_NAME)) 839 { 840 value = this.getConfiguredProperty(COLLECTION_INDEX_NAME); 841 if (StringUtils.isBlank(ObjectUtils.toString(value))) 842 { 843 value = null; 844 } 845 } 846 847 if (value != null) 848 { 849 return ObjectUtils.toString(value); 850 } 851 final String otherEntityName = ((EJB3EntityFacade)this.getOtherEnd().getType()).getEntityName(); 852 final Object separator = this.getConfiguredProperty(UMLMetafacadeProperties.SQL_NAME_SEPARATOR); 853 return EntityMetafacadeUtils.toSqlName( 854 otherEntityName, 855 separator) + separator + EntityMetafacadeUtils.toSqlName( 856 this.getName(), 857 separator) + separator + "IDX"; 858 } 859 860 /** 861 * @see EJB3AssociationEndFacadeLogic#handleIsMap() 862 */ 863 @Override 864 protected boolean handleIsMap() 865 { 866 boolean isMap = COLLECTION_TYPE_MAP.equalsIgnoreCase(this.getCollectionType()); 867 if (isMap && StringUtils.isBlank(this.getSpecificCollectionType())) 868 { 869 isMap = !this.isOrdered(); 870 } 871 return isMap; 872 } 873 874 /** 875 * @see EJB3AssociationEndFacadeLogic#handleIsList() 876 */ 877 @Override 878 protected boolean handleIsList() 879 { 880 boolean isList = COLLECTION_TYPE_LIST.equalsIgnoreCase(this.getCollectionType()); 881 if (!isList && StringUtils.isBlank(this.getSpecificCollectionType())) 882 { 883 isList = this.isOrdered(); 884 } 885 return isList; 886 } 887 888 /** 889 * @see EJB3AssociationEndFacadeLogic#handleIsSet() 890 */ 891 @Override 892 protected boolean handleIsSet() 893 { 894 boolean isSet = COLLECTION_TYPE_SET.equalsIgnoreCase(this.getCollectionType()); 895 if (isSet && StringUtils.isBlank(this.getSpecificCollectionType())) 896 { 897 isSet = !this.isOrdered(); 898 } 899 return isSet; 900 } 901 902 /** 903 * @see EJB3AssociationEndFacadeLogic#handleIsCollection() 904 */ 905 @Override 906 protected boolean handleIsCollection() 907 { 908 boolean isCollection = COLLECTION_TYPE_COLLECTION.equalsIgnoreCase(this.getCollectionType()); 909 if (!isCollection && StringUtils.isBlank(this.getSpecificCollectionType())) 910 { 911 isCollection = this.isOrdered(); 912 } 913 return isCollection; 914 } 915 916 /** 917 * @see EJB3AssociationEndFacadeLogic#handleGetLabelName() 918 */ 919 @Override 920 protected String handleGetLabelName() 921 { 922 String labelNamePattern = (this.isMany() ? 923 (String)this.getConfiguredProperty(EJB3Globals.LABEL_COLLECTION_NAME_PATTERN) : 924 (String)this.getConfiguredProperty(EJB3Globals.LABEL_SINGLE_NAME_PATTERN)); 925 926 return MessageFormat.format( 927 labelNamePattern, 928 StringUtils.trimToEmpty(this.getName())); 929 } 930 931 /** 932 * @see EJB3AssociationEndFacadeLogic#handleGetGetterLabelName() 933 */ 934 @Override 935 protected String handleGetGetterLabelName() 936 { 937 return UMLMetafacadeUtils.getGetterPrefix(this.getType()) + StringUtils.capitalize(this.getLabelName()); 938 } 939 940 /** 941 * @see EJB3AssociationEndFacadeLogic#handleGetSetterLabelName() 942 */ 943 @Override 944 protected String handleGetSetterLabelName() 945 { 946 return "set" + StringUtils.capitalize(this.getLabelName()); 947 } 948 949 /** 950 * @see EJB3AssociationEndFacadeLogic#handleGetCacheType() 951 */ 952 @Override 953 protected String handleGetCacheType() 954 { 955 String cacheType = (String)super.findTaggedValue(EJB3Profile.TAGGEDVALUE_HIBERNATE_ASSOCIATION_CACHE); 956 if (StringUtils.isBlank(cacheType)) 957 { 958 cacheType = String.valueOf(this.getConfiguredProperty(HIBERNATE_ASSOCIATION_CACHE)); 959 } 960 return StringUtils.trimToEmpty(cacheType); 961 } 962 963 /** 964 * @see EJB3AssociationEndFacadeLogic#handleIsAssociationCacheEnabled() 965 */ 966 @Override 967 protected boolean handleIsAssociationCacheEnabled() 968 { 969 return BooleanUtils.toBoolean(String.valueOf(this.getConfiguredProperty(HIBERNATE_ASSOCIATION_ENABLE_CACHE))); 970 } 971 972 /** 973 * @see EJB3AssociationEndFacadeLogic#handleIsForeignKeyConstraintDefined() 974 */ 975 @Override 976 protected boolean handleIsForeignKeyConstraintDefined() 977 { 978 boolean fkConstraintDefined = false; 979 if (super.findTaggedValue(UMLProfile.TAGGEDVALUE_PERSISTENCE_FOREIGN_KEY_CONSTRAINT_NAME) != null) 980 { 981 fkConstraintDefined = true; 982 } 983 return fkConstraintDefined; 984 } 985 986 /** 987 * @see EJB3AssociationEndFacadeLogic#handleGetForeignKeyConstraintName(String) 988 */ 989 @Override 990 protected String handleGetForeignKeyConstraintName(final String suffix) 991 { 992 String constraintName; 993 994 final Object taggedValueObject = super.findTaggedValue( 995 UMLProfile.TAGGEDVALUE_PERSISTENCE_FOREIGN_KEY_CONSTRAINT_NAME); 996 997 /** 998 * Construct our own foreign key constraint name here 999 */ 1000 StringBuilder buffer = new StringBuilder(); 1001 1002 if (taggedValueObject == null) 1003 { 1004 final ClassifierFacade type = this.getOtherEnd().getType(); 1005 if (type instanceof Entity) 1006 { 1007 //Entity entity = (Entity)type; 1008 //Instead of using the entity name, use the association end name to avoid duplication of 1009 //FK constraint names which causes failures during table creation for some DBs (MySQL) 1010 buffer.append( 1011 EntityMetafacadeUtils.toSqlName( 1012 this.getOtherEnd().getName(), 1013 this.getConfiguredProperty(UMLMetafacadeProperties.SQL_NAME_SEPARATOR))); 1014 } 1015 else 1016 { 1017 // should not happen 1018 buffer.append(type.getName().toUpperCase()); 1019 } 1020 1021 buffer.append(this.getConfiguredProperty(UMLMetafacadeProperties.SQL_NAME_SEPARATOR)); 1022 1023 /** 1024 * Add the suffix - which is the name of the identifier pk column if not blank 1025 * otherwise use the column name of the relationship 1026 */ 1027 if (StringUtils.isNotBlank(suffix)) 1028 { 1029 buffer.append(suffix); 1030 } 1031 else 1032 { 1033 buffer.append(this.getColumnName()); 1034 } 1035 constraintName = buffer.toString(); 1036 1037 final String constraintSuffix = 1038 ObjectUtils.toString(this.getConfiguredProperty(UMLMetafacadeProperties.CONSTRAINT_SUFFIX)).trim(); 1039 1040 /** 1041 * we take into consideration the maximum length allowed 1042 */ 1043 final String maxLengthString = (String)super.getConfiguredProperty(UMLMetafacadeProperties.MAX_SQL_NAME_LENGTH); 1044 final short maxLength = (short)(Short.valueOf(maxLengthString).shortValue() - constraintSuffix.length()); 1045 final String method = (String)super.getConfiguredProperty(UMLMetafacadeProperties.SHORTEN_SQL_NAMES_METHOD); 1046 buffer = new StringBuilder( 1047 EntityMetafacadeUtils.ensureMaximumNameLength(constraintName, Short.valueOf(maxLength),method)); 1048 buffer.append(constraintSuffix); 1049 } 1050 else 1051 { 1052 // use the tagged value 1053 buffer.append(taggedValueObject.toString()); 1054 } 1055 1056 return buffer.toString(); 1057 } 1058 1059 /** 1060 * @see EJB3AssociationEndFacadeLogic#handleGetForeignKeyName(String) 1061 */ 1062 @Override 1063 protected String handleGetForeignKeyName(String suffix) 1064 { 1065 String columnName = null; 1066 // prevent ClassCastException if the association isn't an Entity 1067 if (this.getType() instanceof Entity) 1068 { 1069 if (StringUtils.isNotBlank(suffix)) 1070 { 1071 suffix = new String( 1072 this.getConfiguredProperty(UMLMetafacadeProperties.SQL_NAME_SEPARATOR) + 1073 suffix + 1074 this.getForeignKeySuffix()); 1075 } 1076 else 1077 { 1078 suffix = this.getForeignKeySuffix(); 1079 } 1080 1081 final String columnNamePrefix = 1082 this.isConfiguredProperty(UMLMetafacadeProperties.COLUMN_NAME_PREFIX) 1083 ? ObjectUtils.toString(this.getConfiguredProperty(UMLMetafacadeProperties.COLUMN_NAME_PREFIX)) : null; 1084 columnName = 1085 EntityMetafacadeUtils.getSqlNameFromTaggedValue( 1086 columnNamePrefix, 1087 this, 1088 UMLProfile.TAGGEDVALUE_PERSISTENCE_COLUMN, 1089 ((Entity)this.getType()).getMaxSqlNameLength(), 1090 suffix, 1091 this.getConfiguredProperty(UMLMetafacadeProperties.SQL_NAME_SEPARATOR), 1092 this.getConfiguredProperty(UMLMetafacadeProperties.SHORTEN_SQL_NAMES_METHOD)); 1093 } 1094 return columnName; 1095 } 1096 1097 /** 1098 * @see EJB3AssociationEndFacadeLogic#handleGetDefaultCollectionInterface() 1099 */ 1100 @Override 1101 protected String handleGetDefaultCollectionInterface() 1102 { 1103 return ObjectUtils.toString(this.getConfiguredProperty(DEFAULT_COLLECTION_INTERFACE)); 1104 } 1105 1106 /** 1107 * @see EJB3AssociationEndFacadeLogic#handleIsCollectionInterfaceSortedSet() 1108 */ 1109 @Override 1110 protected boolean handleIsCollectionInterfaceSortedSet() 1111 { 1112 boolean isInterfaceSortedSet = false; 1113 if (this.getGetterSetterTypeName().startsWith(EJB3Globals.COLLECTION_INTERFACE_SORTED_SET)) 1114 { 1115 isInterfaceSortedSet = true; 1116 } 1117 return isInterfaceSortedSet; 1118 } 1119 1120 /** 1121 * @see EJB3AssociationEndFacadeLogic#handleGetHibernateCascadeType() 1122 */ 1123 @Override 1124 protected String handleGetHibernateCascadeType() 1125 { 1126 return (String)this.findTaggedValue(EJB3Profile.TAGGEDVALUE_HIBERNATE_CASCADE); 1127 } 1128 1129 /** 1130 * @see EJB3AssociationEndFacadeLogic#handleIsHibernateCascadeExists() 1131 */ 1132 @Override 1133 protected boolean handleIsHibernateCascadeExists() 1134 { 1135 return StringUtils.isNotBlank(this.getHibernateCascadeType()) ? true : false; 1136 } 1137 1138 /** 1139 * @see EJB3AssociationEndFacadeLogic#handleIsColumnNullable() 1140 */ 1141 @Override 1142 protected boolean handleIsColumnNullable() 1143 { 1144 boolean nullable = true; 1145 String nullableString = (String)this.findTaggedValue(EJB3Profile.TAGGEDVALUE_PERSISTENCE_COLUMN_NULLABLE); 1146 1147 if (StringUtils.isBlank(nullableString)) 1148 { 1149 nullable = (this.isIdentifier() || this.isUnique()) ? false : !this.isRequired(); 1150 } 1151 else 1152 { 1153 nullable = Boolean.valueOf(nullableString).booleanValue(); 1154 } 1155 return nullable; 1156 } 1157}