View Javadoc
1   package org.andromda.metafacades.emf.uml22;
2   
3   import java.util.ArrayList;
4   import java.util.Collection;
5   import java.util.Collections;
6   import java.util.LinkedHashSet;
7   import java.util.List;
8   import java.util.Set;
9   import org.andromda.core.metafacade.MetafacadeConstants;
10  import org.andromda.core.metafacade.MetafacadeException;
11  import org.andromda.metafacades.uml.AssociationEndFacade;
12  import org.andromda.metafacades.uml.AttributeFacade;
13  import org.andromda.metafacades.uml.ClassifierFacade;
14  import org.andromda.metafacades.uml.DependencyFacade;
15  import org.andromda.metafacades.uml.Entity;
16  import org.andromda.metafacades.uml.EntityAssociationEnd;
17  import org.andromda.metafacades.uml.EntityAttribute;
18  import org.andromda.metafacades.uml.EntityMetafacadeUtils;
19  import org.andromda.metafacades.uml.EntityQueryOperation;
20  import org.andromda.metafacades.uml.EnumerationFacade;
21  import org.andromda.metafacades.uml.FilteredCollection;
22  import org.andromda.metafacades.uml.MetafacadeUtils;
23  import org.andromda.metafacades.uml.ModelElementFacade;
24  import org.andromda.metafacades.uml.NameMasker;
25  import org.andromda.metafacades.uml.OperationFacade;
26  import org.andromda.metafacades.uml.UMLMetafacadeProperties;
27  import org.andromda.metafacades.uml.UMLProfile;
28  import org.andromda.utils.StringUtilsHelper;
29  import org.apache.commons.collections.Closure;
30  import org.apache.commons.collections.CollectionUtils;
31  import org.apache.commons.collections.Predicate;
32  import org.apache.commons.collections.Transformer;
33  import org.apache.commons.lang.ObjectUtils;
34  import org.apache.commons.lang.StringUtils;
35  import org.eclipse.uml2.uml.Class;
36  import org.eclipse.uml2.uml.Property;
37  import org.eclipse.uml2.uml.Stereotype;
38  import org.eclipse.uml2.uml.Type;
39  import org.eclipse.uml2.uml.VisibilityKind;
40  
41  /**
42   * MetafacadeLogic implementation for org.andromda.metafacades.uml.Entity.
43   *
44   * @see org.andromda.metafacades.uml.Entity
45   * @author Bob Fields
46   */
47  public class EntityLogicImpl
48      extends EntityLogic
49  {
50      private static final long serialVersionUID = 9022811369852920861L;
51  
52      /**
53       * @param metaObject
54       * @param context
55       */
56      public EntityLogicImpl(
57          final Object metaObject,
58          final String context)
59      {
60          super(metaObject, context);
61      }
62  
63      /**
64       * A collection of MOF ids for entities that have dynamic identifiers
65       * present.
66       */
67      private static final Collection<String> DYNAMIC_IDENTIFIERS_PRESENT
68          = Collections.synchronizedList(new ArrayList<String>());
69  
70      /**
71       * @see org.andromda.core.metafacade.MetafacadeBase#initialize()
72       */
73      @Override
74      public void initialize()
75      {
76          super.initialize();
77  
78          // if there are no identifiers on this entity, create and add one.
79          // enumerations don't have identifiers since they are not entities
80          if (!this.isIdentifiersPresent() && this.isAllowDefaultIdentifiers())
81          {
82              this.createIdentifier();
83              DYNAMIC_IDENTIFIERS_PRESENT.add(this.getId());
84          }
85      }
86  
87      /**
88       * Overridden to provide name masking.
89       *
90       * @see org.andromda.metafacades.uml.ModelElementFacade#getName()
91       */
92      @Override
93      protected String handleGetName()
94      {
95          final String nameMask = String.valueOf(this.getConfiguredProperty(UMLMetafacadeProperties.ENTITY_NAME_MASK));
96          return NameMasker.mask(
97              super.handleGetName(),
98              nameMask);
99      }
100 
101     /**
102      * @see org.andromda.metafacades.uml.Entity#getQueryOperations()
103      */
104     @Override
105     protected Collection<OperationFacade> handleGetQueryOperations()
106     {
107         return this.getQueryOperations(false);
108     }
109 
110     /**
111      * @see org.andromda.metafacades.uml.Entity#getQueryOperations(boolean)
112      */
113     @Override
114     protected Collection<OperationFacade> handleGetQueryOperations(final boolean follow)
115     {
116         final Collection<OperationFacade> operations = new ArrayList<OperationFacade>(this.getOperations());
117         final Collection<OperationFacade> queryOperations = new ArrayList<OperationFacade>();
118 
119         MetafacadeUtils.filterByType(
120             operations,
121             EntityQueryOperation.class);
122         for (OperationFacade operation : operations)
123         {
124             queryOperations.add((EntityQueryOperation)operation);
125         }
126         for (ClassifierFacade superClass = (ClassifierFacade)this.getGeneralization(); superClass != null && follow;
127             superClass = (ClassifierFacade)superClass.getGeneralization())
128         {
129             if (Entity.class.isAssignableFrom(superClass.getClass()))
130             {
131                 final Entity entity = (Entity)superClass;
132                 queryOperations.addAll(entity.getQueryOperations());
133             }
134         }
135         return queryOperations;
136     }
137 
138     /**
139      * @see org.andromda.metafacades.uml.Entity#getIdentifiers()
140      */
141     @Override
142     protected Collection<ModelElementFacade> handleGetIdentifiers()
143     {
144         return this.handleGetIdentifiers(true);
145     }
146 
147     /**
148      * @see org.andromda.metafacades.uml.Entity#getIdentifiers(boolean)
149      */
150     @Override
151     protected Collection<ModelElementFacade> handleGetIdentifiers(final boolean follow)
152     {
153         return EntityMetafacadeUtils.getIdentifiers(
154             this,
155             follow);
156     }
157 
158     /**
159      * Creates an identifier from the default identifier properties specified
160      * within a namespace.
161      */
162     private void createIdentifier()
163     {
164         // first check if the foreign identifier flag is set, and
165         // let those taken precedence if so
166         if (!this.checkForAndAddForeignIdentifiers())
167         {
168             this.createIdentifier(
169                 this.getDefaultIdentifier(),
170                 this.getDefaultIdentifierType(),
171                 this.getDefaultIdentifierVisibility());
172         }
173     }
174 
175     /**
176      * Creates a new identifier and adds it to the underlying meta model
177      * classifier instance.
178      *
179      * @param name the name to give the identifier
180      * @param type the type to give the identifier
181      * @param visibility the visibility to give the identifier
182      */
183     private void createIdentifier(
184         final String name,
185         final String type,
186         final String visibility)
187     {
188         final Class umlClass = (Class)this.metaObject;
189 
190         // if we auto-create entity identifiers it will only be on hierarchy roots,
191         // problems would arise when calls to #checkForAndAddForeignIdentifiers()
192         // navigate over associated entities, effectively initializing their facade instances:
193         // this results in subclasses having an identifier generated before their ancestors
194         // ideally the method mentioned above would not make use of facades but meta-classes only,
195         // if one is to refactor it that way this comment may be removed together with the line of code under it
196         //
197         // notice how the next line of code does not make use of facades, this is done on purpose in order
198         // to avoid using uninitialized facades
199         //
200         // (Wouter, Sept. 20 2006) also see other UML implementations
201         if (!umlClass.getGeneralizations().isEmpty()) {return;}
202 
203         if (umlClass.getAttribute(name, umlClass) == null)
204         {
205             // ((org.eclipse.uml2.uml.Classifier)metaObject).getModel();
206             final Object modelElement =
207                 UmlUtilities.findByFullyQualifiedName(
208                     umlClass.eResource().getResourceSet(),
209                     type,
210                     MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR,
211                     true);
212             if (modelElement instanceof Type)
213             {
214                 final Type element = (Type)modelElement;
215                 // Identifiers will always have lowerBound 0, since they are optional when creating the Entity class but still valid.
216                 // Creates a property with the specified name, type, lower bound, and upper bound
217                 final Property property = umlClass.createOwnedAttribute(
218                         name,
219                         element,
220                         0,
221                         1);
222                 VisibilityKind kind = VisibilityKind.PUBLIC_LITERAL;
223                 if ("package".equalsIgnoreCase(visibility))
224                 {
225                     kind = VisibilityKind.PACKAGE_LITERAL;
226                 }
227                 if ("private".equalsIgnoreCase(visibility))
228                 {
229                     kind = VisibilityKind.PRIVATE_LITERAL;
230                 }
231                 if ("protected".equalsIgnoreCase(visibility))
232                 {
233                     kind = VisibilityKind.PROTECTED_LITERAL;
234                 }
235                 property.setVisibility(kind);
236                 final Stereotype stereotype =
237                     UmlUtilities.findApplicableStereotype(
238                         property,
239                         UMLProfile.STEREOTYPE_IDENTIFIER);
240                 if (stereotype == null)
241                 {
242                     throw new MetafacadeException("Could not apply '" + UMLProfile.STEREOTYPE_IDENTIFIER + "' to " +
243                         property + ", the stereotype could not be found");
244                 }
245                 property.applyStereotype(stereotype);
246             }
247         }
248     }
249 
250     /**
251      * @see org.andromda.metafacades.uml.Entity#isIdentifiersPresent()
252      */
253     @Override
254     protected boolean handleIsIdentifiersPresent()
255     {
256         final Collection<ModelElementFacade> identifiers = this.getIdentifiers(true);
257         return identifiers != null && !identifiers.isEmpty();
258     }
259 
260     /**
261      * @see org.andromda.metafacades.uml.Entity#isDynamicIdentifiersPresent()
262      */
263     @Override
264     protected boolean handleIsDynamicIdentifiersPresent()
265     {
266         return DYNAMIC_IDENTIFIERS_PRESENT.contains(this.getId());
267     }
268 
269     /**
270      * @see org.andromda.metafacades.uml.Entity#getTableName()
271      */
272     @Override
273     protected String handleGetTableName()
274     {
275         final String prefixProperty = UMLMetafacadeProperties.TABLE_NAME_PREFIX;
276         final String tableNamePrefix =
277             this.isConfiguredProperty(prefixProperty)
278             ? ObjectUtils.toString(this.getConfiguredProperty(prefixProperty)) : null;
279         return EntityMetafacadeUtils.getSqlNameFromTaggedValue(
280             tableNamePrefix,
281             this,
282             UMLProfile.TAGGEDVALUE_PERSISTENCE_TABLE,
283             Short.valueOf(this.getMaxSqlNameLength()),
284             this.getConfiguredProperty(UMLMetafacadeProperties.SQL_NAME_SEPARATOR),
285             this.getConfiguredProperty(UMLMetafacadeProperties.SHORTEN_SQL_NAMES_METHOD));
286     }
287 
288     /**
289      * @see org.andromda.metafacades.uml.Entity#getOperationCallFromAttributes(boolean)
290      */
291     @Override
292     protected String handleGetOperationCallFromAttributes(final boolean withIdentifiers)
293     {
294         return this.getOperationCallFromAttributes(
295             withIdentifiers,
296             false);
297     }
298 
299     /**
300      * @see org.andromda.metafacades.uml.Entity#getOperationCallFromAttributes(boolean,
301      *      boolean)
302      */
303     @Override
304     protected String handleGetOperationCallFromAttributes(
305         final boolean withIdentifiers,
306         final boolean follow)
307     {
308         final StringBuilder buffer = new StringBuilder("(");
309 
310         final Set<AttributeFacade> attributes = new LinkedHashSet<AttributeFacade>(this.getAttributes());
311 
312         for (ClassifierFacade superClass = (ClassifierFacade)this.getGeneralization(); superClass != null && follow;
313             superClass = (ClassifierFacade)superClass.getGeneralization())
314         {
315             if (superClass instanceof Entity)
316             {
317                 final Entity entity = (Entity)superClass;
318                 attributes.addAll(entity.getAttributes());
319             }
320         }
321 
322         if (!attributes.isEmpty())
323         {
324             String separator = "";
325             for (AttributeFacade attribute : attributes)
326             {
327                 final EntityAttribute entityAttribute = (EntityAttribute)attribute;
328                 if (withIdentifiers || !entityAttribute.isIdentifier())
329                 {
330                     buffer.append(separator);
331                     if (entityAttribute.getType() != null)
332                     {
333                         buffer.append(entityAttribute.getType().getFullyQualifiedName());
334                     }
335                     buffer.append(' ');
336                     buffer.append(entityAttribute.getName());
337                     separator = ", ";
338                 }
339             }
340         }
341         buffer.append(')');
342         return buffer.toString();
343     }
344 
345     /**
346      * @see org.andromda.metafacades.uml.Entity#getAttributeTypeList(boolean,
347      *      boolean)
348      */
349     @Override
350     protected String handleGetAttributeTypeList(
351         final boolean follow,
352         final boolean withIdentifiers)
353     {
354         return this.getTypeList(this.getAttributes(
355                 follow,
356                 withIdentifiers));
357     }
358 
359     /**
360      * @see org.andromda.metafacades.uml.Entity#getAttributeNameList(boolean,
361      *      boolean)
362      */
363     @Override
364     protected String handleGetAttributeNameList(
365         final boolean follow,
366         final boolean withIdentifiers)
367     {
368         return this.getAttributeNameList(follow, withIdentifiers, true);
369     }
370 
371     /**
372      * @see org.andromda.metafacades.uml.Entity#getAttributeNameList(boolean,
373      *      boolean, boolean)
374      */
375     @Override
376     protected String handleGetAttributeNameList(
377         final boolean follow,
378         final boolean withIdentifiers,
379         final boolean withDerived)
380     {
381         return this.getNameList(this.getAttributes(
382                 follow,
383                 withIdentifiers,
384                 withDerived));
385     }
386 
387     /**
388      * @see org.andromda.metafacades.uml.Entity#getRequiredAttributeTypeList(boolean,
389      *      boolean)
390      */
391     @Override
392     protected String handleGetRequiredAttributeTypeList(
393         final boolean follow,
394         final boolean withIdentifiers)
395     {
396         return this.getTypeList(this.getRequiredAttributes(
397                 follow,
398                 withIdentifiers));
399     }
400 
401     /**
402      * @see org.andromda.metafacades.uml.Entity#getRequiredAttributeNameList(boolean,
403      *      boolean)
404      */
405     @Override
406     protected String handleGetRequiredAttributeNameList(
407         final boolean follow,
408         final boolean withIdentifiers)
409     {
410         return this.getNameList(this.getRequiredAttributes(
411                 follow,
412                 withIdentifiers));
413     }
414 
415     /**
416      * @see org.andromda.metafacades.uml.Entity#getRequiredPropertyTypeList(boolean,
417      *      boolean)
418      */
419     @Override
420     protected String handleGetRequiredPropertyTypeList(
421         final boolean follow,
422         final boolean withIdentifiers)
423     {
424         return this.getTypeList(this.getRequiredProperties(
425                 follow,
426                 withIdentifiers));
427     }
428 
429     /**
430      * @see org.andromda.metafacades.uml.Entity#getRequiredPropertyNameList(boolean,
431      *      boolean)
432      */
433     @Override
434     protected String handleGetRequiredPropertyNameList(
435         final boolean follow,
436         final boolean withIdentifiers)
437     {
438         return this.getNameList(this.getRequiredProperties(
439                 follow,
440                 withIdentifiers));
441     }
442 
443     /**
444      * Constructs a comma separated list of attribute type names from the passed
445      * in collection of <code>attributes</code>.
446      *
447      * @param properties
448      *            the attributes and associationEnds to construct the list from.
449      * @return the comma separated list of attribute types.
450      */
451     private String getTypeList(final Collection<? extends ModelElementFacade> properties)
452     {
453         final StringBuilder list = new StringBuilder();
454         final String comma = ", ";
455         CollectionUtils.forAllDo(
456             properties,
457             new Closure()
458             {
459                 public void execute(final Object object)
460                 {
461                     if (object instanceof AttributeFacade)
462                     {
463                         final AttributeFacade attribute = (AttributeFacade)object;
464                         if (attribute.getType() != null)
465                         {
466                             list.append(attribute.getType().getFullyQualifiedName());
467                             list.append(comma);
468                         }
469                     }
470                     if (object instanceof AssociationEndFacade)
471                     {
472                         final AssociationEndFacade associationEnd = (AssociationEndFacade)object;
473                         if (associationEnd.getType() != null)
474                         {
475                             list.append(associationEnd.getType().getFullyQualifiedName());
476                             list.append(comma);
477                         }
478                     }
479                 }
480             });
481         if (list.toString().endsWith(comma))
482         {
483             list.delete(
484                 list.lastIndexOf(comma),
485                 list.length());
486         }
487         return list.toString();
488     }
489 
490     /**
491      * Constructs a comma separated list of attribute names from the passed in
492      * collection of <code>attributes</code>.
493      *
494      * @param properties
495      *            the attributes and associationEnds to construct the list from.
496      * @return the comma separated list of attribute names.
497      */
498     private String getNameList(final Collection properties)
499     {
500         final StringBuilder list = new StringBuilder();
501         final String comma = ", ";
502         CollectionUtils.forAllDo(
503             properties,
504             new Closure()
505             {
506                 public void execute(final Object object)
507                 {
508                     if (object instanceof EntityAttribute)
509                     {
510                         list.append(((AttributeFacade)object).getName());
511                         list.append(comma);
512                     }
513                     if (object instanceof EntityAssociationEnd)
514                     {
515                         list.append(((AssociationEndFacade)object).getName());
516                         list.append(comma);
517                     }
518                 }
519             });
520         if (list.toString().endsWith(comma))
521         {
522             list.delete(
523                 list.lastIndexOf(comma),
524                 list.length());
525         }
526         return list.toString();
527     }
528 
529     /**
530      * @see org.andromda.metafacades.uml.Entity#isChild()
531      */
532     @Override
533     protected boolean handleIsChild()
534     {
535         return CollectionUtils.find(
536             this.getAssociationEnds(),
537             new Predicate()
538             {
539                 public boolean evaluate(final Object object)
540                 {
541                     return ((AssociationEndFacade)object).getOtherEnd().isComposition();
542                 }
543             }) != null;
544     }
545 
546     /**
547      * @see org.andromda.metafacades.uml.Entity#getParentEnd()
548      */
549     @Override
550     protected AssociationEndFacade handleGetParentEnd()
551     {
552         AssociationEndFacade parentEnd = null;
553         final AssociationEndFacade end =
554             (AssociationEndFacade)CollectionUtils.find(
555                 this.getAssociationEnds(),
556                 new Predicate()
557                 {
558                     public boolean evaluate(final Object object)
559                     {
560                         return ((AssociationEndFacade)object).getOtherEnd().isComposition();
561                     }
562                 });
563         if (end != null)
564         {
565             parentEnd = end.getOtherEnd();
566         }
567         return parentEnd;
568     }
569 
570     /**
571      * @see org.andromda.metafacades.uml.Entity#getChildEnds()
572      */
573     @Override
574     protected Collection<AssociationEndFacade> handleGetChildEnds()
575     {
576         final Collection<AssociationEndFacade> childEnds =
577             new FilteredCollection(this.getAssociationEnds())
578             {
579                 private static final long serialVersionUID = -7200489183737785955L;
580 
581                 @Override
582                 public boolean evaluate(final Object object)
583                 {
584                     return ((AssociationEndFacade)object).isComposition();
585                 }
586             };
587         CollectionUtils.transform(
588             childEnds,
589             new Transformer()
590             {
591                 public Object transform(final Object object)
592                 {
593                     return ((AssociationEndFacade)object).getOtherEnd();
594                 }
595             });
596         return childEnds;
597     }
598 
599     /**
600      * @see org.andromda.metafacades.uml.Entity#getBusinessOperations()
601      */
602     @Override
603     protected Collection<OperationFacade> handleGetBusinessOperations()
604     {
605         final Collection<OperationFacade> businessOperations = new ArrayList<OperationFacade>(this.getImplementationOperations());
606         MetafacadeUtils.filterByNotType(
607             businessOperations,
608             EntityQueryOperation.class);
609         return businessOperations;
610     }
611 
612     /**
613      * @see org.andromda.metafacades.uml.Entity#getEntityReferences()
614      */
615     @Override
616     protected Collection<DependencyFacade> handleGetEntityReferences()
617     {
618         return new FilteredCollection(this.getSourceDependencies())
619             {
620             private static final long serialVersionUID = -302184888689870478L;
621 
622             @Override
623                 public boolean evaluate(final Object object)
624                 {
625                 final ModelElementFacade targetElement = ((DependencyFacade)object).getTargetElement();
626                     return targetElement instanceof Entity;
627                 }
628             };
629     }
630 
631     /**
632      * @see org.andromda.metafacades.uml.Entity#getAttributes(boolean, boolean)
633      */
634     @Override
635     protected Collection<AttributeFacade> handleGetAttributes(
636         final boolean follow,
637         final boolean withIdentifiers)
638     {
639         final Collection<AttributeFacade> attributes = this.getAttributes(follow);
640         CollectionUtils.filter(
641             attributes,
642             new Predicate()
643             {
644                 public boolean evaluate(final Object object)
645                 {
646                     boolean valid = true;
647                     if (!withIdentifiers && object != null && object instanceof EntityAttribute)
648                     {
649                         valid = !((EntityAttribute)object).isIdentifier();
650                     }
651                     return valid;
652                 }
653             });
654         return attributes;
655     }
656 
657     /**
658      * @see org.andromda.metafacades.uml.Entity#getAttributes(boolean, boolean, boolean)
659      */
660     @Override
661     protected Collection<AttributeFacade> handleGetAttributes(
662         final boolean follow,
663         final boolean withIdentifiers,
664         final boolean withDerived)
665     {
666         final Collection<AttributeFacade> attributes = this.getAttributes(follow);
667         CollectionUtils.filter(
668             attributes,
669             new Predicate()
670             {
671                 public boolean evaluate(final Object object)
672                 {
673                     boolean valid = true;
674                     if (!withIdentifiers && object != null && object instanceof EntityAttribute)
675                     {
676                         valid = !((EntityAttribute)object).isIdentifier();
677                     }
678                     if (valid && !withDerived && object instanceof EntityAttribute)
679                     {
680                         valid = !((EntityAttribute)object).isDerived();
681                     }
682                     return valid;
683                 }
684             });
685         return attributes;
686     }
687 
688     /**
689      * @see org.andromda.metafacades.uml.Entity#getProperties(boolean, boolean)
690      */
691     @Override
692     protected Collection<ModelElementFacade> handleGetProperties(
693         final boolean follow,
694         final boolean withIdentifiers)
695     {
696         final Collection<ModelElementFacade> properties = this.getProperties(follow);
697         // only filter when we don't want identifiers
698         if (!withIdentifiers)
699         {
700             CollectionUtils.filter(
701                 properties,
702                 new Predicate()
703                 {
704                     public boolean evaluate(final Object object)
705                     {
706                         return !(object instanceof EntityAttribute) || !((EntityAttribute)object).isIdentifier();
707                     }
708                 });
709         }
710 
711         return properties;
712     }
713 
714     /**
715      * @see org.andromda.metafacades.uml.Entity#getRequiredAttributes(boolean,
716      *      boolean)
717      */
718     @Override
719     protected Collection<AttributeFacade> handleGetRequiredAttributes(
720         final boolean follow,
721         final boolean withIdentifiers)
722     {
723         final Collection<AttributeFacade> attributes = this.getAttributes(
724                 follow,
725                 withIdentifiers,
726                 false);
727 
728         // only filter when we don't want identifiers
729         if (!withIdentifiers)
730         {
731             CollectionUtils.filter(
732                 attributes,
733                 new Predicate()
734                 {
735                     public boolean evaluate(final Object object)
736                     {
737                         final AttributeFacade attribute = (AttributeFacade)object;
738                         return
739                             attribute.isRequired() &&
740                             (!(object instanceof EntityAttribute) || !((EntityAttribute)object).isIdentifier());
741                     }
742                 });
743         }
744 
745         return attributes;
746     }
747 
748     /**
749      * @see org.andromda.metafacades.uml.Entity#getRequiredProperties(boolean,
750      *      boolean)
751      */
752     @Override
753     protected Collection<ModelElementFacade> handleGetRequiredProperties(
754         final boolean follow,
755         final boolean withIdentifiers)
756     {
757         final Set<ModelElementFacade> properties = new LinkedHashSet<ModelElementFacade>(this.getProperties(
758                     follow,
759                     withIdentifiers));
760         CollectionUtils.filter(
761             properties,
762             new Predicate()
763             {
764                 public boolean evaluate(final Object object)
765                 {
766                     boolean valid = false;
767                     if (object instanceof AttributeFacade)
768                     {
769                         final AttributeFacade attribute = (AttributeFacade)object;
770                         valid = attribute.isRequired() && !attribute.isDerived();
771                         if (valid && !withIdentifiers && object instanceof EntityAttribute)
772                         {
773                             valid = !((EntityAttribute)object).isIdentifier();
774                         }
775                     }
776                     else if (object instanceof AssociationEndFacade)
777                     {
778                         final AssociationEndFacade assocationEnd = (AssociationEndFacade)object;
779                         valid = assocationEnd.isRequired() && !assocationEnd.isDerived();
780                     }
781                     return valid;
782                 }
783             });
784 
785         final List<ModelElementFacade> sortedProperties = new ArrayList<ModelElementFacade>(properties);
786         MetafacadeUtils.sortByFullyQualifiedName(sortedProperties);
787         return sortedProperties;
788     }
789 
790     /**
791      * Gets the maximum name length SQL names may be
792      * @return UMLMetafacadeProperties.MAX_SQL_NAME_LENGTH
793      */
794     @Override
795     protected short handleGetMaxSqlNameLength()
796     {
797         return Short.valueOf((String)this.getConfiguredProperty(UMLMetafacadeProperties.MAX_SQL_NAME_LENGTH));
798     }
799 
800     /**
801      * Returns true/false on whether or not default identifiers are allowed
802      */
803     private boolean isAllowDefaultIdentifiers()
804     {
805         return Boolean.valueOf((String)this.getConfiguredProperty(UMLMetafacadeProperties.ALLOW_DEFAULT_IDENTITIFIERS))
806                       .booleanValue();
807     }
808 
809     /**
810      * Gets the name of the default identifier.
811      */
812     private String getDefaultIdentifier()
813     {
814         return ObjectUtils.toString(this.getConfiguredProperty(UMLMetafacadeProperties.DEFAULT_IDENTIFIER_PATTERN))
815                           .replaceAll(
816             "\\{0\\}",
817             StringUtilsHelper.lowerCamelCaseName(this.handleGetName()));
818     }
819 
820     /**
821      * Gets the name of the default identifier type.
822      */
823     private String getDefaultIdentifierType()
824     {
825         return (String)this.getConfiguredProperty(UMLMetafacadeProperties.DEFAULT_IDENTIFIER_TYPE);
826     }
827 
828     /**
829      * Gets the default identifier visibility.
830      */
831     private String getDefaultIdentifierVisibility()
832     {
833         return (String)this.getConfiguredProperty(UMLMetafacadeProperties.DEFAULT_IDENTIFIER_VISIBILITY);
834     }
835 
836     /**
837      * Checks to see if this entity has any associations where the foreign
838      * identifier flag may be set, and if so creates and adds identifiers just
839      * like the foreign entity to this entity.
840      *
841      * @return true if any identifiers were added, false otherwise
842      */
843     private boolean checkForAndAddForeignIdentifiers()
844     {
845         boolean identifiersAdded = false;
846         final EntityAssociationEnd end = this.getForeignIdentifierEnd();
847         if (end != null && end.getType() instanceof Entity)
848         {
849             final Entity foreignEntity = (Entity)end.getOtherEnd().getType();
850             final Collection<ModelElementFacade> identifiers = EntityMetafacadeUtils.getIdentifiers(
851                     foreignEntity,
852                     true);
853             for (ModelElementFacade identifier : identifiers)
854             {
855                 if (identifier instanceof EntityAttribute)
856                 {
857                     this.createIdentifier(
858                             identifier.getName(),
859                             ((EntityAttribute)identifier).getType().getFullyQualifiedName(true),
860                             identifier.getVisibility());
861                 }
862                 else if (identifier instanceof EntityAssociationEnd)
863                 {
864                     this.createIdentifier(
865                             identifier.getName(),
866                             ((EntityAssociationEnd)identifier).getType().getFullyQualifiedName(true),
867                             identifier.getVisibility());
868                 }
869                 identifiersAdded = true;
870             }
871         }
872         return identifiersAdded;
873     }
874 
875     /**
876      * Override to filter out any association ends that point to model elements
877      * other than other entities.
878      *
879      * @see org.andromda.metafacades.uml.ClassifierFacade#getAssociationEnds()
880      */
881     @Override
882     public List<AssociationEndFacade> handleGetAssociationEnds()
883     {
884         final List<AssociationEndFacade> associationEnds = this.shieldedElements(super.handleGetAssociationEnds());
885         CollectionUtils.filter(
886             associationEnds,
887             new Predicate()
888             {
889                 public boolean evaluate(final Object object)
890                 {
891                     final ClassifierFacade type = ((AssociationEndFacade)object).getOtherEnd().getType();
892                     /*if (!(type instanceof Entity || type instanceof EnumerationFacade))
893                     {
894                         logger.debug("EntityLogic.getAssociationEnds " + type);
895                     }*/
896                     return type != null && (type instanceof Entity || type instanceof EnumerationFacade
897                         || type.hasStereotype(UMLProfile.STEREOTYPE_EMBEDDED_VALUE));
898                 }
899             });
900         return associationEnds;
901     }
902 
903     /**
904      * @see org.andromda.metafacades.emf.uml22.EntityLogic#handleIsUsingForeignIdentifier()
905      */
906     @Override
907     protected boolean handleIsUsingForeignIdentifier()
908     {
909         return this.getForeignIdentifierEnd() != null;
910     }
911 
912     /**
913      * Gets the association end that is flagged as having the foreign identifier
914      * set (or null if none is).
915      */
916     private EntityAssociationEnd getForeignIdentifierEnd()
917     {
918         return (EntityAssociationEnd)CollectionUtils.find(
919             this.getAssociationEnds(),
920             new Predicate()
921             {
922                 public boolean evaluate(final Object object)
923                 {
924                     boolean valid = false;
925                     if (object != null && EntityAssociationEnd.class.isAssignableFrom(object.getClass()))
926                     {
927                         final EntityAssociationEnd end = (EntityAssociationEnd)object;
928                         valid = end.isForeignIdentifier();
929                     }
930                     return valid;
931                 }
932             });
933     }
934 
935     /**
936      * @see org.andromda.metafacades.uml.Entity#isUsingAssignedIdentifier()
937      */
938     @Override
939     protected boolean handleIsUsingAssignedIdentifier()
940     {
941         boolean assigned = false;
942         final Collection<ModelElementFacade> identifiers = this.getIdentifiers();
943         if (identifiers != null && !identifiers.isEmpty())
944         {
945             final ModelElementFacade identifier = identifiers.iterator().next();
946             // TODO Does not use the value of taggedValue Entity andromda_hibernate_generator_class (13 - assigned)
947             assigned =
948                     Boolean.valueOf(
949                         ObjectUtils.toString(
950                         identifier.findTaggedValue(UMLProfile.TAGGEDVALUE_PERSISTENCE_ASSIGNED_IDENTIFIER)))
951                        .booleanValue();
952             // Association relationships (FK part of PK related to PK in another table) are always assigned.
953             if (!assigned && identifier instanceof AssociationEndFacade)
954             {
955                 assigned = true;
956             }
957         }
958         return assigned;
959     }
960 
961     /**
962      * @see org.andromda.metafacades.uml.Entity#getSchema()
963      */
964     @Override
965     protected String handleGetSchema()
966     {
967         String schemaName = ObjectUtils.toString(this.findTaggedValue(UMLProfile.TAGGEDVALUE_PERSISTENCE_SCHEMA));
968         if (StringUtils.isBlank(schemaName))
969         {
970             schemaName = ObjectUtils.toString(this.getConfiguredProperty(UMLMetafacadeProperties.SCHEMA_NAME));
971         }
972         return schemaName;
973     }
974 
975     /**
976      * @see org.andromda.metafacades.uml.Entity#getIdentifierAssociationEnds()
977      */
978     @Override
979     protected Collection<AssociationEndFacade> handleGetIdentifierAssociationEnds()
980     {
981         final Collection<AssociationEndFacade> associationEnds = new ArrayList(this.getAssociationEnds());
982         MetafacadeUtils.filterByStereotype(
983             associationEnds,
984             UMLProfile.STEREOTYPE_IDENTIFIER);
985         return associationEnds;
986     }
987 
988     /**
989      * @see org.andromda.metafacades.uml.Entity#isCompositeIdentifier()
990      */
991     @Override
992     protected boolean handleIsCompositeIdentifier()
993     {
994         int identifiers = this.getIdentifiers().isEmpty() ? 0 : this.getIdentifiers().size();
995         /*identifiers +=
996             this.getIdentifierAssociationEnds().isEmpty() ? 0 : this.getIdentifierAssociationEnds().size();*/
997         return identifiers >= 2;
998     }
999 
1000     /**
1001      * @see org.andromda.metafacades.uml.Entity#getAllEntityReferences()
1002      */
1003     @Override
1004     protected Collection<DependencyFacade> handleGetAllEntityReferences()
1005     {
1006         final Collection<DependencyFacade> result = new LinkedHashSet<DependencyFacade>();
1007 
1008         // get references of the service itself
1009         result.addAll(this.getEntityReferences());
1010 
1011         // get references of all super classes
1012         CollectionUtils.forAllDo(this.getAllGeneralizations(), new Closure()
1013         {
1014             public void execute(final Object object)
1015             {
1016                 if (object instanceof Entity)
1017                 {
1018                     final Entity entity = (Entity)object;
1019                     result.addAll(entity.getEntityReferences());
1020                 }
1021             }
1022 
1023         });
1024         return result;
1025     }
1026 
1027     /**
1028      * @see org.andromda.metafacades.uml.Entity#getEmbeddedValues()
1029      */
1030     @Override
1031     protected Collection<AttributeFacade> handleGetEmbeddedValues()
1032     {
1033         final Collection<AttributeFacade> embeddedValues = new ArrayList<AttributeFacade>();
1034         for (final AttributeFacade attribute : (Iterable<AttributeFacade>) this.getAttributes(true))
1035         {
1036             final ClassifierFacade type = attribute.getType();
1037             if (type != null && type.isEmbeddedValue())
1038             {
1039                 embeddedValues.add(attribute);
1040             }
1041         }
1042         return embeddedValues;
1043     }
1044 
1045     /**
1046      * @see org.andromda.metafacades.uml.Entity#getFullyQualifiedIdentifierTypeName()
1047      */
1048     @Override
1049     public String handleGetFullyQualifiedIdentifierTypeName()
1050     {
1051         String rtn = null;
1052         if(isCompositeIdentifier())
1053         {
1054             rtn = getFullyQualifiedName()+(String)this.getConfiguredProperty(
1055                 UMLMetafacadeProperties.COMPOSITE_IDENTIFIER_TYPE_NAME_SUFIX);
1056         }
1057         else
1058         {
1059             final Collection<ModelElementFacade> identifiers = getIdentifiers();
1060             if (identifiers != null && !identifiers.isEmpty())
1061             {
1062                 final ModelElementFacade facade = identifiers.iterator().next();
1063                 if (facade instanceof EntityAttribute)
1064                 {
1065                     rtn = ((EntityAttribute)facade).getType().getFullyQualifiedName();
1066                 }
1067                 else if (facade instanceof EntityAssociationEnd)
1068                 {
1069                     rtn = ((EntityAssociationEnd)facade).getType().getFullyQualifiedName();
1070                 }
1071                 else
1072                 {
1073                     rtn = "";
1074                 }
1075             }
1076             else
1077             {
1078                 rtn = "";
1079             }
1080         }
1081         return rtn;
1082     }
1083 
1084     /**
1085      * @see org.andromda.metafacades.uml.Entity#getIdentifierName()
1086      */
1087     @Override
1088     public String handleGetIdentifierName()
1089     {
1090         if(isCompositeIdentifier())
1091         {
1092             return StringUtils.uncapitalize(getName()) + (String)this.getConfiguredProperty(
1093                 UMLMetafacadeProperties.COMPOSITE_IDENTIFIER_NAME_SUFIX);
1094         }
1095         else
1096         {
1097             final Collection<ModelElementFacade> identifiers = getIdentifiers();
1098             if (identifiers != null && !identifiers.isEmpty())
1099             {
1100                 return getIdentifiers().iterator().next().getName();
1101             }
1102             else
1103             {
1104                 return "";
1105             }
1106         }
1107     }
1108 
1109     /**
1110      * @see org.andromda.metafacades.uml.Entity#getIdentifierTypeName()
1111      */
1112     @Override
1113     public String handleGetIdentifierTypeName()
1114     {
1115         if(isCompositeIdentifier())
1116         {
1117             return getName()+(String)this.getConfiguredProperty(UMLMetafacadeProperties.COMPOSITE_IDENTIFIER_TYPE_NAME_SUFIX);
1118         }
1119         final Collection<ModelElementFacade> identifiers = getIdentifiers();
1120         if (identifiers != null && !identifiers.isEmpty())
1121         {
1122             ModelElementFacade facade = identifiers.iterator().next();
1123             if (facade instanceof EntityAttribute)
1124             {
1125                 return ((EntityAttribute)facade).getType().getName();
1126             }
1127             else if (facade instanceof EntityAssociationEnd)
1128             {
1129                 return ((EntityAssociationEnd)facade).getType().getName();
1130             }
1131             else
1132             {
1133                 return "";
1134             }
1135         }
1136         else
1137         {
1138             return "";
1139         }
1140     }
1141 
1142     /**
1143      * @see org.andromda.metafacades.uml.Entity#getIdentifierGetterName()
1144      */
1145     @Override
1146     public String handleGetIdentifierGetterName()
1147     {
1148         return "get"+StringUtils.capitalize(getIdentifierName());
1149     }
1150 
1151     /**
1152      * @see org.andromda.metafacades.uml.Entity#getIdentifierSetterName()
1153      */
1154     @Override
1155     public String handleGetIdentifierSetterName()
1156     {
1157         return "set"+StringUtils.capitalize(getIdentifierName());
1158     }
1159 }