001package org.andromda.metafacades.uml14;
002
003import java.util.ArrayList;
004import java.util.Collection;
005import java.util.Iterator;
006import java.util.LinkedHashSet;
007import java.util.List;
008import java.util.Set;
009import org.andromda.core.metafacade.MetafacadeConstants;
010import org.andromda.metafacades.uml.AssociationEndFacade;
011import org.andromda.metafacades.uml.AttributeFacade;
012import org.andromda.metafacades.uml.ClassifierFacade;
013import org.andromda.metafacades.uml.DependencyFacade;
014import org.andromda.metafacades.uml.Entity;
015import org.andromda.metafacades.uml.EntityAssociationEnd;
016import org.andromda.metafacades.uml.EntityAttribute;
017import org.andromda.metafacades.uml.EntityMetafacadeUtils;
018import org.andromda.metafacades.uml.EntityQueryOperation;
019import org.andromda.metafacades.uml.FilteredCollection;
020import org.andromda.metafacades.uml.MetafacadeUtils;
021import org.andromda.metafacades.uml.ModelElementFacade;
022import org.andromda.metafacades.uml.NameMasker;
023import org.andromda.metafacades.uml.OperationFacade;
024import org.andromda.metafacades.uml.UMLMetafacadeProperties;
025import org.andromda.metafacades.uml.UMLProfile;
026import org.andromda.utils.StringUtilsHelper;
027import org.apache.commons.collections.Closure;
028import org.apache.commons.collections.CollectionUtils;
029import org.apache.commons.collections.Predicate;
030import org.apache.commons.collections.Transformer;
031import org.apache.commons.lang.ObjectUtils;
032import org.apache.commons.lang.StringUtils;
033import org.omg.uml.foundation.core.Attribute;
034import org.omg.uml.foundation.core.Classifier;
035
036
037/**
038 * Metaclass facade implementation.
039 * @author Bob Fields
040 */
041public class EntityLogicImpl
042    extends EntityLogic
043{
044    private static final long serialVersionUID = 8742467678618468728L;
045
046    /**
047     * @param metaObject
048     * @param context
049     */
050    public EntityLogicImpl(
051        final Object metaObject,
052        final String context)
053    {
054        super(metaObject, context);
055    }
056
057    /**
058     * A collection of MOF ids for entities that have dynamic
059     * identifiers present.
060     */
061    private static final Collection dynamicIdentifiersPresent = new ArrayList();
062
063    /**
064     * @see org.andromda.core.metafacade.MetafacadeBase#initialize()
065     */
066    public void initialize()
067    {
068        super.initialize();
069
070        // if there are no identifiers on this entity, create and add one.
071        // enumeration don't have identifiers since they are not entities
072        if (!this.isIdentifiersPresent() && this.isAllowDefaultIdentifiers())
073        {
074            this.createIdentifier();
075            dynamicIdentifiersPresent.add(this.getId());
076        }
077    }
078
079    /**
080     * Overridden to provide name masking.
081     *
082     * @see org.andromda.metafacades.uml.ModelElementFacade#getName()
083     */
084    @Override
085    protected String handleGetName()
086    {
087        final String nameMask = String.valueOf(this.getConfiguredProperty(UMLMetafacadeProperties.ENTITY_NAME_MASK));
088        return NameMasker.mask(
089            super.handleGetName(),
090            nameMask);
091    }
092
093    /**
094     * @see org.andromda.metafacades.uml.Entity#getQueryOperations()
095     */
096    @Override
097    protected Collection<OperationFacade> handleGetQueryOperations()
098    {
099        return this.getQueryOperations(false);
100    }
101
102    /**
103     * @see org.andromda.metafacades.uml.Entity#getQueryOperations(boolean)
104     */
105    @Override
106    protected Collection<OperationFacade> handleGetQueryOperations(final boolean follow)
107    {
108        final Collection<OperationFacade> operations = new ArrayList<OperationFacade>(this.getOperations());
109        final Collection<OperationFacade> queryOperations = new ArrayList<OperationFacade>();
110
111        MetafacadeUtils.filterByType(
112                operations,
113            EntityQueryOperation.class);
114        for (OperationFacade operation : operations)
115        {
116            queryOperations.add((EntityQueryOperation)operation);
117        }
118        for (ClassifierFacade superClass = (ClassifierFacade)getGeneralization(); superClass != null && follow;
119            superClass = (ClassifierFacade)superClass.getGeneralization())
120        {
121            if (Entity.class.isAssignableFrom(superClass.getClass()))
122            {
123                Entity entity = (Entity)superClass;
124                queryOperations.addAll(entity.getQueryOperations());
125            }
126        }
127        return queryOperations;
128    }
129
130    /**
131     * @see org.andromda.metafacades.uml.Entity#getIdentifiers()
132     */
133    @Override
134    protected Collection<ModelElementFacade> handleGetIdentifiers()
135    {
136        return this.getIdentifiers(true);
137    }
138
139    /**
140     * @see org.andromda.metafacades.uml.Entity#getIdentifiers(boolean)
141     */
142    @Override
143    protected Collection<ModelElementFacade> handleGetIdentifiers(final boolean follow)
144    {
145        return EntityMetafacadeUtils.getIdentifiers(
146            this,
147            follow);
148    }
149
150    /**
151     * Creates an identifier from the default identifier properties specified within a namespace.
152     */
153    private void createIdentifier()
154    {
155        // first check if the foreign identifier flag is set, and
156        // let those taken precedence if so
157        if (!this.checkForAndAddForeignIdentifiers())
158        {
159            this.createIdentifier(
160                this.getDefaultIdentifier(),
161                this.getDefaultIdentifierType(),
162                this.getDefaultIdentifierVisibility());
163        }
164    }
165
166    /**
167     * Creates a new identifier and adds it to the underlying meta model
168     * classifier instance.
169     *
170     * @param name the name to give the identifier
171     * @param type the type to give the identifier
172     * @param visibility the visibility to give the identifier
173     */
174    private void createIdentifier(
175        final String name,
176        final String type,
177        final String visibility)
178    {
179        final Classifier classifier = (Classifier)this.metaObject;
180
181        // if we auto-create entity identifiers it will only be on hierarchy roots,
182        // problems would arise when calls to #checkForAndAddForeignIdentifiers()
183        // navigate over associated entities, effectively initializing their facade instances:
184        // this results in subclasses having an identifier generated before their ancestors
185        // ideally the method mentioned above would not make use of facades but meta-classes only,
186        // if one is to refactor it that way this comment may be removed together with the line of code under it
187        //
188        // notice how the next line of code does not make use of facades, this is done on purpose in order
189        // to avoid using uninitialized facades
190        //
191        // (Wouter, Sept. 20 2006) also see other UML implementations
192        if (!classifier.getGeneralization().isEmpty()) return;
193
194        // only create the identifier if an identifer with the name doesn't
195        // already exist
196        if (!UML14MetafacadeUtils.attributeExists(
197                classifier,
198                name))
199        {
200            final Attribute identifier =
201                UML14MetafacadeUtils.createAttribute(
202                    name,
203                    type,
204                    visibility,
205                    MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR);
206
207            identifier.getStereotype().add(
208                UML14MetafacadeUtils.findOrCreateStereotype(UMLProfile.STEREOTYPE_IDENTIFIER));
209
210            classifier.getFeature().add(identifier);
211        }
212    }
213
214    /**
215     * @see org.andromda.metafacades.uml.Entity#isIdentifiersPresent()
216     */
217    @Override
218    protected boolean handleIsIdentifiersPresent()
219    {
220        final Collection<ModelElementFacade> identifiers = this.getIdentifiers(true);
221        return identifiers != null && !identifiers.isEmpty();
222    }
223
224    /**
225     * @see org.andromda.metafacades.uml.Entity#isDynamicIdentifiersPresent()
226     */
227    @Override
228    protected boolean handleIsDynamicIdentifiersPresent()
229    {
230        return dynamicIdentifiersPresent.contains(this.getId());
231    }
232
233    /**
234     * @see org.andromda.metafacades.uml.Entity#getTableName()
235     */
236    @Override
237    protected String handleGetTableName()
238    {
239        final String prefixProperty = UMLMetafacadeProperties.TABLE_NAME_PREFIX;
240        final String tableNamePrefix =
241            this.isConfiguredProperty(prefixProperty)
242            ? ObjectUtils.toString(this.getConfiguredProperty(prefixProperty)) : null;
243        return EntityMetafacadeUtils.getSqlNameFromTaggedValue(
244            tableNamePrefix,
245            this,
246            UMLProfile.TAGGEDVALUE_PERSISTENCE_TABLE,
247            this.getMaxSqlNameLength(),
248            this.getConfiguredProperty(UMLMetafacadeProperties.SQL_NAME_SEPARATOR),
249            this.getConfiguredProperty(UMLMetafacadeProperties.SHORTEN_SQL_NAMES_METHOD));
250    }
251
252    /**
253     * @see org.andromda.metafacades.uml.Entity#getOperationCallFromAttributes(boolean)
254     */
255    @Override
256    protected String handleGetOperationCallFromAttributes(final boolean withIdentifiers)
257    {
258        return this.getOperationCallFromAttributes(
259            withIdentifiers,
260            false);
261    }
262
263    /**
264     * @see org.andromda.metafacades.uml.Entity#getOperationCallFromAttributes(boolean, boolean)
265     */
266    @Override
267    protected String handleGetOperationCallFromAttributes(
268        final boolean withIdentifiers,
269        final boolean follow)
270    {
271        final StringBuilder buffer = new StringBuilder();
272        String separator = "";
273        buffer.append('(');
274
275        final Collection<AttributeFacade> attributes = new ArrayList(this.getAttributes());
276
277        for (ClassifierFacade superClass = (ClassifierFacade)getGeneralization(); superClass != null && follow;
278            superClass = (ClassifierFacade)superClass.getGeneralization())
279        {
280            if (superClass instanceof Entity)
281            {
282                final Entity entity = (Entity)superClass;
283                attributes.addAll(entity.getAttributes());
284            }
285        }
286
287        if (!attributes.isEmpty())
288        {
289            for (final Iterator iterator = attributes.iterator(); iterator.hasNext();)
290            {
291                final EntityAttribute attribute = (EntityAttribute)iterator.next();
292                if (withIdentifiers || !attribute.isIdentifier())
293                {
294                    buffer.append(separator);
295                    if (attribute.getType() != null)
296                    {
297                        buffer.append(attribute.getType().getFullyQualifiedName());
298                    }
299                    buffer.append(' ');
300                    buffer.append(attribute.getName());
301                    separator = ", ";
302                }
303            }
304        }
305        buffer.append(')');
306        return buffer.toString();
307    }
308
309    /**
310     * @see org.andromda.metafacades.uml.Entity#getAttributeTypeList(boolean, boolean)
311     */
312    @Override
313    protected String handleGetAttributeTypeList(
314        final boolean follow,
315        final boolean withIdentifiers)
316    {
317        return this.getTypeList(this.getAttributes(
318                follow,
319                withIdentifiers));
320    }
321
322    /**
323     * @see org.andromda.metafacades.uml.Entity#getAttributeNameList(boolean, boolean)
324     */
325    @Override
326    protected String handleGetAttributeNameList(
327        final boolean follow,
328        final boolean withIdentifiers)
329    {
330        return this.getNameList(this.getAttributes(
331                follow,
332                withIdentifiers));
333    }
334
335    /**
336     * @see org.andromda.metafacades.uml.Entity#getAttributeNameList(boolean, boolean, boolean)
337     */
338    @Override
339    protected String handleGetAttributeNameList(
340        final boolean follow,
341        final boolean withIdentifiers,
342        final boolean withDerived)
343    {
344        return this.getNameList(this.getAttributes(
345                follow,
346                withIdentifiers,
347                withDerived));
348    }
349
350    /**
351     * @see org.andromda.metafacades.uml.Entity#getRequiredAttributeTypeList(boolean, boolean)
352     */
353    @Override
354    protected String handleGetRequiredAttributeTypeList(
355        final boolean follow,
356        final boolean withIdentifiers)
357    {
358        return this.getTypeList(this.getRequiredAttributes(
359                follow,
360                withIdentifiers));
361    }
362
363    /**
364     * @see org.andromda.metafacades.uml.Entity#getRequiredAttributeNameList(boolean, boolean)
365     */
366    @Override
367    protected String handleGetRequiredAttributeNameList(
368        final boolean follow,
369        final boolean withIdentifiers)
370    {
371        return this.getNameList(this.getRequiredAttributes(
372                follow,
373                withIdentifiers));
374    }
375
376    /**
377     * @see org.andromda.metafacades.uml.Entity#getRequiredPropertyTypeList(boolean, boolean)
378     */
379    @Override
380    protected String handleGetRequiredPropertyTypeList(
381        final boolean follow,
382        final boolean withIdentifiers)
383    {
384        return this.getTypeList(this.getRequiredProperties(
385                follow,
386                withIdentifiers));
387    }
388
389    /**
390     * @see org.andromda.metafacades.uml.Entity#getRequiredPropertyNameList(boolean, boolean)
391     */
392    @Override
393    protected String handleGetRequiredPropertyNameList(
394        final boolean follow,
395        final boolean withIdentifiers)
396    {
397        return this.getNameList(this.getRequiredProperties(
398                follow,
399                withIdentifiers));
400    }
401
402    /**
403     * Constructs a comma separated list of attribute type names from the passed in collection of
404     * <code>attributes</code>.
405     *
406     * @param attributes the attributes to construct the list from.
407     * @return the comma separated list of attribute types.
408     */
409    private String getTypeList(final Collection attributes)
410    {
411        final StringBuilder list = new StringBuilder();
412        final String comma = ", ";
413        CollectionUtils.forAllDo(
414            attributes,
415            new Closure()
416            {
417                public void execute(final Object object)
418                {
419                    if (object instanceof AttributeFacade)
420                    {
421                        final AttributeFacade attribute = (AttributeFacade)object;
422                        if (attribute.getType() != null)
423                        {
424                            list.append(attribute.getType().getFullyQualifiedName());
425                            list.append(comma);
426                        }
427                    }
428                    if (object instanceof AssociationEndFacade)
429                    {
430                        final AssociationEndFacade associationEnd = (AssociationEndFacade)object;
431                        if (associationEnd.getType() != null)
432                        {
433                            list.append(associationEnd.getType().getFullyQualifiedName());
434                            list.append(comma);
435                        }
436                    }
437                }
438            });
439        if (list.toString().endsWith(comma))
440        {
441            list.delete(
442                list.lastIndexOf(comma),
443                list.length());
444        }
445        return list.toString();
446    }
447
448    /**
449     * Constructs a comma separated list of attribute names from the passed in collection of <code>attributes</code>.
450     *
451     * @param properties the properties to construct the list from.
452     * @return the comma separated list of attribute names.
453     */
454    private String getNameList(final Collection properties)
455    {
456        final StringBuilder list = new StringBuilder();
457        final String comma = ", ";
458        CollectionUtils.forAllDo(
459            properties,
460            new Closure()
461            {
462                public void execute(Object object)
463                {
464                    if (object instanceof EntityAttribute)
465                    {
466                        list.append(((AttributeFacade)object).getName());
467                        list.append(comma);
468                    }
469                    if (object instanceof EntityAssociationEnd)
470                    {
471                        list.append(((AssociationEndFacade)object).getName());
472                        list.append(comma);
473                    }
474                }
475            });
476        if (list.toString().endsWith(comma))
477        {
478            list.delete(
479                list.lastIndexOf(comma),
480                list.length());
481        }
482        return list.toString();
483    }
484
485    /**
486     * @see org.andromda.metafacades.uml.Entity#isChild()
487     */
488    @Override
489    protected boolean handleIsChild()
490    {
491        return CollectionUtils.find(
492            this.getAssociationEnds(),
493            new Predicate()
494            {
495                public boolean evaluate(Object object)
496                {
497                    return ((AssociationEndFacade)object).getOtherEnd().isComposition();
498                }
499            }) != null;
500    }
501
502    /**
503     * @see org.andromda.metafacades.uml.Entity#getParentEnd()
504     */
505    @Override
506    protected AssociationEndFacade handleGetParentEnd()
507    {
508        AssociationEndFacade parentEnd = null;
509        final AssociationEndFacade end =
510            (AssociationEndFacade)CollectionUtils.find(
511                this.getAssociationEnds(),
512                new Predicate()
513                {
514                    public boolean evaluate(Object object)
515                    {
516                        return ((AssociationEndFacade)object).getOtherEnd().isComposition();
517                    }
518                });
519        if (end != null)
520        {
521            parentEnd = end.getOtherEnd();
522        }
523        return parentEnd;
524    }
525
526    /**
527     * @see org.andromda.metafacades.uml.Entity#getChildEnds()
528     */
529    @Override
530    protected Collection<AssociationEndFacade> handleGetChildEnds()
531    {
532        final Collection<AssociationEndFacade> childEnds =
533            new FilteredCollection(this.getAssociationEnds())
534            {
535                private static final long serialVersionUID = -4602337379703645043L;
536
537                public boolean evaluate(Object object)
538                {
539                    return ((AssociationEndFacade)object).isComposition();
540                }
541            };
542        CollectionUtils.transform(
543            childEnds,
544            new Transformer()
545            {
546                public Object transform(Object object)
547                {
548                    return ((AssociationEndFacade)object).getOtherEnd();
549                }
550            });
551        return childEnds;
552    }
553
554    /**
555     * @see org.andromda.metafacades.uml.Entity#getBusinessOperations()
556     */
557    @Override
558    protected Collection<OperationFacade> handleGetBusinessOperations()
559    {
560        final Collection<OperationFacade> businessOperations = new ArrayList(this.getImplementationOperations());
561        MetafacadeUtils.filterByNotType(
562            businessOperations,
563            EntityQueryOperation.class);
564        return businessOperations;
565    }
566
567    /**
568     * @see org.andromda.metafacades.uml.Entity#getEntityReferences()
569     */
570    @Override
571    protected Collection<DependencyFacade> handleGetEntityReferences()
572    {
573        return new FilteredCollection(this.getSourceDependencies())
574            {
575            private static final long serialVersionUID = -8696886289865317133L;
576
577            public boolean evaluate(Object object)
578                {
579                    ModelElementFacade targetElement = ((DependencyFacade)object).getTargetElement();
580                    return targetElement instanceof Entity;
581                }
582            };
583    }
584
585    /**
586     * @see org.andromda.metafacades.uml.Entity#getAttributes(boolean, boolean)
587     */
588    @Override
589    protected Collection handleGetAttributes(
590        boolean follow,
591        final boolean withIdentifiers)
592    {
593        return this.getAttributes(follow, withIdentifiers, true);
594    }
595
596    /**
597     * @see org.andromda.metafacades.uml.Entity#getAttributes(boolean, boolean, boolean)
598     */
599    @Override
600    protected Collection handleGetAttributes(
601        boolean follow,
602        final boolean withIdentifiers,
603        final boolean withDerived)
604    {
605        final Collection attributes = this.getAttributes(follow);
606        CollectionUtils.filter(
607            attributes,
608            new Predicate()
609            {
610                public boolean evaluate(Object object)
611                {
612                    boolean valid = true;
613                    if (!withIdentifiers && object instanceof EntityAttribute)
614                    {
615                        valid = !((EntityAttribute)object).isIdentifier();
616                    }
617                    if (valid && !withDerived && object instanceof EntityAttribute)
618                    {
619                        valid = !((EntityAttribute)object).isDerived();
620                    }
621                    return valid;
622                }
623            });
624        return attributes;
625    }
626
627    /**
628     * @see org.andromda.metafacades.uml.Entity#getProperties(boolean, boolean)
629     */
630    @Override
631    protected Collection handleGetProperties(
632        boolean follow,
633        final boolean withIdentifiers)
634    {
635        final Collection properties = this.getProperties(follow);
636        CollectionUtils.filter(
637            properties,
638            new Predicate()
639            {
640                public boolean evaluate(Object object)
641                {
642                    boolean valid = true;
643                    if (!withIdentifiers && object instanceof EntityAttribute)
644                    {
645                        valid = !((EntityAttribute)object).isIdentifier();
646                    }
647                    return valid;
648                }
649            });
650        return properties;
651    }
652
653    /**
654     * @see org.andromda.metafacades.uml.Entity#getRequiredAttributes(boolean, boolean)
655     */
656    @Override
657    protected Collection handleGetRequiredAttributes(
658        boolean follow,
659        final boolean withIdentifiers)
660    {
661        final Collection attributes = this.getAttributes(
662                follow,
663                withIdentifiers, false);
664        CollectionUtils.filter(
665            attributes,
666            new Predicate()
667            {
668                public boolean evaluate(Object object)
669                {
670                    boolean valid;
671                    valid = ((AttributeFacade)object).isRequired();
672                    if (valid && !withIdentifiers && object instanceof EntityAttribute)
673                    {
674                        valid = !((EntityAttribute)object).isIdentifier();
675                    }
676                    return valid;
677                }
678            });
679        return attributes;
680    }
681
682    /**
683     * @see org.andromda.metafacades.uml.Entity#getRequiredProperties(boolean, boolean)
684     */
685    @Override
686    protected Collection handleGetRequiredProperties(
687        final boolean follow,
688        final boolean withIdentifiers)
689    {
690        final Set properties = new LinkedHashSet(this.getProperties(
691                    follow,
692                    withIdentifiers));
693        CollectionUtils.filter(
694            properties,
695            new Predicate()
696            {
697                public boolean evaluate(final Object object)
698                {
699                    boolean valid = false;
700                    if (object instanceof AttributeFacade)
701                    {
702                        AttributeFacade attribute = (AttributeFacade)object;
703                        valid = attribute.isRequired() && !attribute.isDerived();
704                        if (valid && !withIdentifiers && object instanceof EntityAttribute)
705                        {
706                            valid = !((EntityAttribute)object).isIdentifier();
707                        }
708                    }
709                    else if (object instanceof AssociationEndFacade)
710                    {
711                        valid = ((AssociationEndFacade)object).isRequired();
712                    }
713                    return valid;
714                }
715            });
716
717        List sortedProperties = new ArrayList(properties);
718        MetafacadeUtils.sortByFullyQualifiedName(sortedProperties);
719        return sortedProperties;
720    }
721
722    /**
723     * Gets the maximum name length SQL names may be
724     */
725    @Override
726    protected short handleGetMaxSqlNameLength()
727    {
728        return Short.valueOf((String)this.getConfiguredProperty(UMLMetafacadeProperties.MAX_SQL_NAME_LENGTH));
729    }
730
731    /**
732     * Returns true/false on whether or not default identifiers are allowed
733     */
734    private boolean isAllowDefaultIdentifiers()
735    {
736        return Boolean.valueOf((String)this.getConfiguredProperty(UMLMetafacadeProperties.ALLOW_DEFAULT_IDENTITIFIERS))
737                      .booleanValue();
738    }
739
740    /**
741     * Gets the name of the default identifier.
742     */
743    private String getDefaultIdentifier()
744    {
745        return ObjectUtils.toString(this.getConfiguredProperty(UMLMetafacadeProperties.DEFAULT_IDENTIFIER_PATTERN))
746                          .replaceAll(
747            "\\{0\\}",
748            StringUtilsHelper.lowerCamelCaseName(this.getName()));
749    }
750
751    /**
752     * Gets the name of the default identifier type.
753     */
754    private String getDefaultIdentifierType()
755    {
756        return (String)this.getConfiguredProperty(UMLMetafacadeProperties.DEFAULT_IDENTIFIER_TYPE);
757    }
758
759    /**
760     * Gets the default identifier visibility.
761     */
762    private String getDefaultIdentifierVisibility()
763    {
764        return (String)this.getConfiguredProperty(UMLMetafacadeProperties.DEFAULT_IDENTIFIER_VISIBILITY);
765    }
766
767    /**
768     * Checks to see if this entity has any associations where the foreign identifier flag may be set, and if so creates
769     * and adds identifiers just like the foreign entity to this entity.
770     *
771     * @return true if any identifiers were added, false otherwise
772     */
773    private boolean checkForAndAddForeignIdentifiers()
774    {
775        boolean identifiersAdded = false;
776        final EntityAssociationEnd end = this.getForeignIdentifierEnd();
777        if (end != null && end.getType() instanceof Entity)
778        {
779            final Entity foreignEntity = (Entity)end.getOtherEnd().getType();
780            final Collection<ModelElementFacade> identifiers = EntityMetafacadeUtils.getIdentifiers(
781                    foreignEntity,
782                    true);
783            for (final ModelElementFacade facade : identifiers)
784            {
785                if (facade instanceof AttributeFacade)
786                {
787                    AttributeFacade identifier = (AttributeFacade)facade;
788                    this.createIdentifier(
789                            identifier.getName(),
790                            identifier.getType().getFullyQualifiedName(true),
791                            identifier.getVisibility());
792                }
793                else if (facade instanceof AssociationEndFacade)
794                {
795                    AssociationEndFacade identifier = (AssociationEndFacade)facade;
796                    this.createIdentifier(
797                            identifier.getName(),
798                            identifier.getType().getFullyQualifiedName(true),
799                            identifier.getVisibility());
800                }
801                identifiersAdded = true;
802            }
803        }
804        return identifiersAdded;
805    }
806
807    /**
808     * Override to filter out any association ends that point to model elements other than other entities.
809     *
810     * @see org.andromda.metafacades.uml.ClassifierFacade#getAssociationEnds()
811     */
812    @Override
813    public List handleGetAssociationEnds()
814    {
815        final List associationEnds = (List)this.shieldedElements(super.handleGetAssociationEnds());
816        CollectionUtils.filter(
817            associationEnds,
818            new Predicate()
819            {
820                public boolean evaluate(Object object)
821                {
822                    return ((AssociationEndFacade)object).getOtherEnd().getType() instanceof Entity;
823                }
824            });
825        return associationEnds;
826    }
827
828    /**
829     * @see org.andromda.metafacades.uml14.EntityLogic#handleIsUsingForeignIdentifier()
830     */
831    protected boolean handleIsUsingForeignIdentifier()
832    {
833        return this.getForeignIdentifierEnd() != null;
834    }
835
836    /**
837     * Gets the association end that is flagged as having the foreign identifier set (or null if none is).
838     */
839    private EntityAssociationEnd getForeignIdentifierEnd()
840    {
841        return (EntityAssociationEnd)CollectionUtils.find(
842            this.getAssociationEnds(),
843            new Predicate()
844            {
845                public boolean evaluate(Object object)
846                {
847                    boolean valid = false;
848                    if (object != null && EntityAssociationEnd.class.isAssignableFrom(object.getClass()))
849                    {
850                        EntityAssociationEnd end = (EntityAssociationEnd)object;
851                        valid = end.isForeignIdentifier();
852                    }
853                    return valid;
854                }
855            });
856    }
857
858    /**
859     * @see org.andromda.metafacades.uml.Entity#isUsingAssignedIdentifier()
860     */
861    @Override
862    protected boolean handleIsUsingAssignedIdentifier()
863    {
864        boolean assigned = false;
865        final Collection<ModelElementFacade> identifiers = this.getIdentifiers();
866        if (identifiers != null && !identifiers.isEmpty())
867        {
868            ModelElementFacade facade = identifiers.iterator().next();
869            if (facade instanceof AttributeFacade)
870            {
871                final AttributeFacade identifier = (AttributeFacade)facade;
872                assigned =
873                    Boolean.valueOf(
874                       ObjectUtils.toString(
875                        identifier.findTaggedValue(UMLProfile.TAGGEDVALUE_PERSISTENCE_ASSIGNED_IDENTIFIER)))
876                       .booleanValue();
877            }
878        }
879        return assigned;
880    }
881
882    /**
883     * @see org.andromda.metafacades.uml.Entity#getSchema()
884     */
885    @Override
886    protected String handleGetSchema()
887    {
888        String schemaName = ObjectUtils.toString(this.findTaggedValue(UMLProfile.TAGGEDVALUE_PERSISTENCE_SCHEMA));
889        if (StringUtils.isBlank(schemaName))
890        {
891            schemaName = ObjectUtils.toString(this.getConfiguredProperty(UMLMetafacadeProperties.SCHEMA_NAME));
892        }
893        return schemaName;
894    }
895
896    /**
897     * @see org.andromda.metafacades.uml.Entity#getIdentifierAssociationEnds()
898     */
899    @Override
900    protected Collection handleGetIdentifierAssociationEnds()
901    {
902        final Collection<AssociationEndFacade> associationEnds = new ArrayList<AssociationEndFacade>(this.getAssociationEnds());
903        MetafacadeUtils.filterByStereotype(
904            associationEnds,
905            UMLProfile.STEREOTYPE_IDENTIFIER);
906        return associationEnds;
907    }
908
909    /**
910     * @see org.andromda.metafacades.uml.Entity#isCompositeIdentifier()
911     */
912    @Override
913    protected boolean handleIsCompositeIdentifier()
914    {
915        int identifiers = (!this.getIdentifiers().isEmpty()) ? this.getIdentifiers().size() : 0;
916        identifiers =
917            identifiers +
918            (!this.getIdentifierAssociationEnds().isEmpty() ? this.getIdentifierAssociationEnds().size() : 0);
919        return identifiers >= 2;
920    }
921
922    /**
923     * @see org.andromda.metafacades.uml.Entity#getAllEntityReferences()
924     */
925    @Override
926    protected Collection<DependencyFacade> handleGetAllEntityReferences()
927    {
928        final Collection<DependencyFacade> result = new LinkedHashSet<DependencyFacade> ();
929
930        // get references of the service itself
931        result.addAll(this.getEntityReferences());
932
933        // get references of all super classes
934        CollectionUtils.forAllDo(this.getAllGeneralizations(), new Closure()
935        {
936            public void execute(Object object)
937            {
938                if (object instanceof Entity)
939                {
940                    final Entity entity = (Entity)object;
941                    result.addAll(entity.getEntityReferences());
942                }
943            }
944
945        });
946        return result;
947    }
948
949    /**
950     * @see org.andromda.metafacades.uml.Entity#getEmbeddedValues()
951     */
952    @Override
953    protected Collection<AttributeFacade> handleGetEmbeddedValues()
954    {
955        final Collection<AttributeFacade> embeddedValues = new ArrayList<AttributeFacade>();
956        for (final Iterator<AttributeFacade> iterator = this.getAttributes(true).iterator(); iterator.hasNext();)
957        {
958            final AttributeFacade attribute = iterator.next();
959            final ClassifierFacade type = attribute.getType();
960            if (type != null && type.isEmbeddedValue())
961            {
962                embeddedValues.add(attribute);
963            }
964        }
965        return embeddedValues;
966    }
967
968    /**
969     * @see org.andromda.metafacades.uml.Entity#getFullyQualifiedIdentifierTypeName()
970     */
971    @Override
972    public String handleGetFullyQualifiedIdentifierTypeName() {
973        if(isCompositeIdentifier())
974        {
975            return getFullyQualifiedName()+(String)this.getConfiguredProperty(UMLMetafacadeProperties.COMPOSITE_IDENTIFIER_TYPE_NAME_SUFIX);
976        }
977        else
978        {
979            ModelElementFacade facade = getIdentifiers().iterator().next();
980            if (facade instanceof AttributeFacade)
981            {
982                return ((AttributeFacade)facade).getType().getFullyQualifiedName();
983            }
984            else if (facade instanceof AssociationEndFacade)
985            {
986                return ((AssociationEndFacade)facade).getType().getFullyQualifiedName();
987            }
988            else
989            {
990                return "";
991            }
992        }
993    }
994
995    /**
996     * @see org.andromda.metafacades.uml.Entity#getIdentifierName()
997     */
998    @Override
999    public String handleGetIdentifierName() {
1000        if(isCompositeIdentifier())
1001        {
1002            return StringUtils.uncapitalize(getName())+(String)this.getConfiguredProperty(UMLMetafacadeProperties.COMPOSITE_IDENTIFIER_NAME_SUFIX);
1003        }
1004        else
1005        {
1006            return getIdentifiers().iterator().next().getName();
1007        }
1008    }
1009
1010    /**
1011     * @see org.andromda.metafacades.uml.Entity#getIdentifierTypeName()
1012     */
1013    @Override
1014    public String handleGetIdentifierTypeName() {
1015        if(isCompositeIdentifier())
1016        {
1017            return getName()+(String)this.getConfiguredProperty(UMLMetafacadeProperties.COMPOSITE_IDENTIFIER_TYPE_NAME_SUFIX);
1018        }
1019        else
1020        {
1021            ModelElementFacade facade = getIdentifiers().iterator().next();
1022            if (facade instanceof AttributeFacade)
1023            {
1024                return ((AttributeFacade)facade).getType().getName();
1025            }
1026            else if (facade instanceof AssociationEndFacade)
1027            {
1028                return ((AssociationEndFacade)facade).getType().getName();
1029            }
1030            else
1031            {
1032                return "";
1033            }
1034        }
1035    }
1036
1037    /**
1038     * @see org.andromda.metafacades.uml.Entity#getIdentifierGetterName()
1039     */
1040    @Override
1041    public String handleGetIdentifierGetterName() {
1042        return "get"+StringUtils.capitalize(getIdentifierName());
1043    }
1044
1045    /**
1046     * @see org.andromda.metafacades.uml.Entity#getIdentifierSetterName()
1047     */
1048    @Override
1049    public String handleGetIdentifierSetterName() {
1050        return "set"+StringUtils.capitalize(getIdentifierName());
1051    }
1052}