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.metafacades.uml.AssociationEndFacade;
010import org.andromda.metafacades.uml.AttributeFacade;
011import org.andromda.metafacades.uml.ClassifierFacade;
012import org.andromda.metafacades.uml.DependencyFacade;
013import org.andromda.metafacades.uml.FilteredCollection;
014import org.andromda.metafacades.uml.GeneralizableElementFacade;
015import org.andromda.metafacades.uml.MetafacadeUtils;
016import org.andromda.metafacades.uml.ModelElementFacade;
017import org.andromda.metafacades.uml.NameMasker;
018import org.andromda.metafacades.uml.OperationFacade;
019import org.andromda.metafacades.uml.TypeMappings;
020import org.andromda.metafacades.uml.UMLMetafacadeProperties;
021import org.andromda.metafacades.uml.UMLMetafacadeUtils;
022import org.andromda.metafacades.uml.UMLProfile;
023import org.apache.commons.collections.CollectionUtils;
024import org.apache.commons.collections.Predicate;
025import org.apache.commons.collections.Transformer;
026import org.apache.commons.lang.StringUtils;
027import org.apache.log4j.Logger;
028import org.omg.uml.foundation.core.Abstraction;
029import org.omg.uml.foundation.core.AssociationClass;
030import org.omg.uml.foundation.core.Attribute;
031import org.omg.uml.foundation.core.Classifier;
032import org.omg.uml.foundation.core.DataType;
033import org.omg.uml.foundation.core.Interface;
034import org.omg.uml.foundation.core.Namespace;
035import org.omg.uml.foundation.core.Operation;
036
037/**
038 * Metaclass facade implementation.
039 * @author Bob Fields
040 */
041public class ClassifierFacadeLogicImpl
042    extends ClassifierFacadeLogic
043{
044    private static final long serialVersionUID = 34L;
045    /**
046     * @param metaObject
047     * @param context
048     */
049    public ClassifierFacadeLogicImpl(
050        Classifier metaObject,
051        String context)
052    {
053        super(metaObject, context);
054    }
055
056    /**
057     * The logger instance.
058     */
059    private static final Logger logger = Logger.getLogger(ClassifierFacadeLogicImpl.class);
060
061    /**
062     * Overridden to provide name masking.
063     *
064     * @see org.andromda.metafacades.uml.ModelElementFacade#getName()
065     */
066    @Override
067    protected String handleGetName()
068    {
069        final String nameMask =
070            String.valueOf(this.getConfiguredProperty(UMLMetafacadeProperties.CLASSIFIER_NAME_MASK));
071        return NameMasker.mask(super.handleGetName(), nameMask);
072    }
073
074    /**
075     * @see org.andromda.metafacades.uml14.ClassifierFacadeLogic#handleGetOperations()
076     */
077    protected List<Operation> handleGetOperations()
078    {
079        return new FilteredCollection(this.metaObject.getFeature())
080        {
081            private static final long serialVersionUID = 34L;
082            public boolean evaluate(Object object)
083            {
084                return object instanceof org.omg.uml.foundation.core.Operation;
085            }
086        };
087    }
088
089    /**
090     * Note: if this instance represents an actual class we resolve any realized interfaces recursively, in case this
091     * instance represents an interface we return only the owned operations.
092     *
093     * @see org.andromda.metafacades.uml.ClassifierFacade#getOperations()
094     */
095    @Override
096    protected Collection<Operation> handleGetImplementationOperations()
097    {
098        final Collection<Operation> operations = new LinkedHashSet();
099
100        // add all of this classifier's operations
101        operations.addAll(new FilteredCollection(metaObject.getFeature())
102        {
103            private static final long serialVersionUID = 34L;
104            public boolean evaluate(Object object)
105            {
106                return object instanceof Operation;
107            }
108        });
109
110        if (!this.isInterface())
111        {
112            final Collection<ClassifierFacade> interfaces = this.getInterfaceAbstractions();
113            for (Iterator interfaceIterator = interfaces.iterator(); interfaceIterator.hasNext();)
114            {
115                final ClassifierFacade interfaceElement = (ClassifierFacade)interfaceIterator.next();
116                operations.addAll(resolveInterfaceOperationsRecursively(interfaceElement));
117            }
118        }
119
120        return operations;
121    }
122
123    private static Collection<Operation> resolveInterfaceOperationsRecursively(ClassifierFacade interfaceClassifier)
124    {
125        final Collection<Operation> operations = new LinkedHashSet(interfaceClassifier.getOperations()); // preserve ordering
126
127        final Collection<GeneralizableElementFacade> generalizations = interfaceClassifier.getGeneralizations();
128        for (Iterator<GeneralizableElementFacade> generalizationIterator = generalizations.iterator(); generalizationIterator.hasNext();)
129        {
130            final ClassifierFacade parent = (ClassifierFacade)generalizationIterator.next();
131            if (parent.isInterface())
132            {
133                operations.addAll(resolveInterfaceOperationsRecursively(parent));
134            }
135        }
136
137        return operations;
138    }
139
140    /**
141     * @see org.andromda.metafacades.uml.ClassifierFacade#getAssociationEnds()
142     */
143    @Override
144    protected List handleGetAssociationEnds()
145    {
146        List associationEnds;
147        Collection participantAssociation =
148            UML14MetafacadeUtils.getCorePackage().getAParticipantAssociation().getAssociation(metaObject);
149
150        if (participantAssociation instanceof List)
151        {
152            associationEnds = (List)participantAssociation;
153        }
154        else
155        {
156            associationEnds = new ArrayList();
157            associationEnds.addAll(participantAssociation);
158        }
159
160        return associationEnds;
161    }
162
163    /**
164     * @return Owner of this Classifier. UML2 only. UML14 returns the namespace (package).
165     * Used to distinguish between a regular class and a TemplateParameter Class/Interface/Type
166     * @see org.andromda.metafacades.uml.ClassifierFacade#getAttributes(boolean)
167     */
168    protected Namespace getOwner()
169    {
170        return this.metaObject.getNamespace();
171    }
172
173    /**
174     * Indicates whether or not this classifier represents a primitive
175     * type. If this type has a wrapper then it's primitive, otherwise it isn't.
176     * @see org.andromda.metafacades.uml.ClassifierFacade#isPrimitive()
177     */
178    @Override
179    protected boolean handleIsPrimitive()
180    {
181        return this.getWrapperMappings() != null &&
182            this.getWrapperMappings().getMappings().containsFrom(this.getFullyQualifiedName());
183    }
184
185    /**
186     * Indicates whether or not this classifier represents a wrapped primitive type.
187     * @see org.andromda.metafacades.uml.ClassifierFacade#isWrappedPrimitive()
188     */
189    @Override
190    protected boolean handleIsWrappedPrimitive()
191    {
192        // Try both the fully qualified name and the ClassName
193        return this.getWrapperMappings() != null &&
194        ( this.getWrapperMappings().getMappings().containsTo(this.getFullyQualifiedName())
195          || this.getWrapperMappings().getMappings().containsTo(this.getName()));
196    }
197
198    /**
199     * @see org.andromda.metafacades.uml.ClassifierFacade#isArrayType()
200     */
201    @Override
202    protected boolean handleIsArrayType()
203    {
204        return this.getFullyQualifiedName(true).endsWith(this.getArraySuffix());
205    }
206
207    /*
208     * Gets the array suffix from the configured metafacade properties.
209     *
210     * @return the array suffix.
211    private String getArraySuffix()
212    {
213        return String.valueOf(this.getConfiguredProperty(UMLMetafacadeProperties.ARRAY_NAME_SUFFIX));
214    }
215     */
216
217    /**
218     * @see org.andromda.metafacades.uml.ClassifierFacade#getWrapperName()
219     */
220    @Override
221    protected String handleGetWrapperName()
222    {
223        String wrapperName = null;
224        if (this.getWrapperMappings() != null)
225        {
226            if (this.getWrapperMappings().getMappings().containsFrom(this.getFullyQualifiedName()))
227            {
228                wrapperName = this.getWrapperMappings().getTo(this.getFullyQualifiedName());
229            }
230        }
231        return wrapperName;
232    }
233
234    /**
235     * Gets the mappings from primitive types to wrapper types. Some languages have primitives (i.e., Java) and some
236     * languages don't, so therefore this property is optional.
237     *
238     * @return the wrapper mappings
239     */
240    protected TypeMappings getWrapperMappings()
241    {
242        final String propertyName = UMLMetafacadeProperties.WRAPPER_MAPPINGS_URI;
243        final Object property = this.getConfiguredProperty(propertyName);
244        TypeMappings mappings = null;
245        String uri;
246        if (property instanceof String)
247        {
248            uri = (String)property;
249            try
250            {
251                mappings = TypeMappings.getInstance(uri);
252                this.setProperty(
253                    propertyName,
254                    mappings);
255            }
256            catch (final Throwable throwable)
257            {
258                final String errMsg = "Error getting '" + propertyName + "' --> '" + uri + '\'';
259                logger.error(
260                    errMsg,
261                    throwable);
262
263                // don't throw the exception
264            }
265        }
266        else
267        {
268            mappings = (TypeMappings)property;
269        }
270        return mappings;
271    }
272
273    /**
274     * @see org.andromda.metafacades.uml.ClassifierFacade#isCollectionType()
275     */
276    @Override
277    protected boolean handleIsCollectionType()
278    {
279        return UMLMetafacadeUtils.isType(this, UMLProfile.COLLECTION_TYPE_NAME);
280    }
281
282    /**
283     * @see org.andromda.metafacades.uml.ClassifierFacade#isListType()
284     */
285    @Override
286    protected boolean handleIsListType()
287    {
288        return UMLMetafacadeUtils.isType(this, UMLProfile.LIST_TYPE_NAME);
289    }
290
291    /**
292     * @see org.andromda.metafacades.uml.ClassifierFacade#isSetType()
293     */
294    @Override
295    protected boolean handleIsSetType()
296    {
297        return UMLMetafacadeUtils.isType(this, UMLProfile.SET_TYPE_NAME);
298    }
299
300    /**
301     * @see org.andromda.metafacades.uml.ClassifierFacade#isBooleanType()
302     */
303    @Override
304    protected boolean handleIsBooleanType()
305    {
306        return UMLMetafacadeUtils.isType(this, UMLProfile.BOOLEAN_TYPE_NAME);
307    }
308
309    /**
310     * <p>
311     * Indicates if this type represents a char, Character, or java.lang.Character type or not.
312     * </p>
313     * @see org.andromda.metafacades.uml.ClassifierFacade#isCharacterType()
314     */
315    @Override
316    protected boolean handleIsCharacterType()
317    {
318        String characterType = UMLProfile.CHARACTER_TYPE_NAME;
319        // Check both char and Character by taking the part after datatype::
320        String charType = characterType.substring(characterType.indexOf(':')+1).substring(0, 4).toLowerCase();
321        return UMLMetafacadeUtils.isType(
322            this,
323            charType) ||
324            UMLMetafacadeUtils.isType(
325                this,
326                characterType);
327    }
328
329    /**
330     * @see org.andromda.metafacades.uml.ClassifierFacade#isDateType()
331     */
332    @Override
333    protected boolean handleIsDateType()
334    {
335        return UMLMetafacadeUtils.isType(this, UMLProfile.DATE_TYPE_NAME);
336    }
337
338    /**
339     * <p>
340     * Indicates whether or not this classifier represents a time type.
341     * </p>
342     * @see org.andromda.metafacades.uml.ClassifierFacade#isDoubleType()
343     */
344    @Override
345    protected boolean handleIsDoubleType()
346    {
347        return UMLMetafacadeUtils.isType(
348            this,
349            UMLProfile.DOUBLE_TYPE_NAME);
350    }
351
352    /**
353     * <p>
354     * Indicates whether or not this classifier represents a float type.
355     * </p>
356     * @see org.andromda.metafacades.uml.ClassifierFacade#isFloatType()
357     */
358    @Override
359    protected boolean handleIsFloatType()
360    {
361        return UMLMetafacadeUtils.isType(
362            this,
363            UMLProfile.FLOAT_TYPE_NAME);
364    }
365
366    /**
367     * <p>
368     * Indicates whether or not this classifier represents an integer type.
369     * </p>
370     * @see org.andromda.metafacades.uml.ClassifierFacade#isIntegerType()
371     */
372    @Override
373    protected boolean handleIsIntegerType()
374    {
375        String integerType = UMLProfile.INTEGER_TYPE_NAME;
376        // Check both int and Integer by taking the part after datatype::
377        String intType = integerType.substring(integerType.indexOf(':')+1).substring(0, 3).toLowerCase();
378        return UMLMetafacadeUtils.isType(
379            this,
380            intType) ||
381            UMLMetafacadeUtils.isType(
382                this,
383                integerType);
384    }
385
386    /**
387     * <p>
388     * Indicates whether or not this classifier represents a long type.
389     * </p>
390     * @see org.andromda.metafacades.uml.ClassifierFacade#isLongType()
391     */
392    @Override
393    protected boolean handleIsLongType()
394    {
395        return UMLMetafacadeUtils.isType(
396            this,
397            UMLProfile.LONG_TYPE_NAME);
398    }
399
400    /**
401     * @see org.andromda.metafacades.uml.ClassifierFacade#isTimeType()
402     */
403    @Override
404    protected boolean handleIsTimeType()
405    {
406        return UMLMetafacadeUtils.isType(this, UMLProfile.TIME_TYPE_NAME);
407    }
408
409    /**
410     * @see org.andromda.metafacades.uml.ClassifierFacade#isFileType()
411     */
412    @Override
413    protected boolean handleIsFileType()
414    {
415        return UMLMetafacadeUtils.isType(this, UMLProfile.FILE_TYPE_NAME);
416    }
417
418    /**
419     * @see org.andromda.metafacades.uml.ClassifierFacade#isBlobType()
420     */
421    @Override
422    protected boolean handleIsBlobType()
423    {
424        return UMLMetafacadeUtils.isType(this, UMLProfile.BLOB_TYPE_NAME);
425    }
426
427    /**
428     * @see org.andromda.metafacades.uml.ClassifierFacade#isClobType()
429     */
430    @Override
431    protected boolean handleIsClobType()
432    {
433        return UMLMetafacadeUtils.isType(this, UMLProfile.CLOB_TYPE_NAME);
434    }
435
436    /**
437     * @see org.andromda.metafacades.uml.ClassifierFacade#isMapType()
438     */
439    @Override
440    public boolean handleIsMapType()
441    {
442        return UMLMetafacadeUtils.isType(this, UMLProfile.MAP_TYPE_NAME);
443    }
444
445    /**
446     * @see org.andromda.metafacades.uml.ClassifierFacade#isStringType()
447     */
448    @Override
449    protected boolean handleIsStringType()
450    {
451        // Allow mapping multiple model types to String type
452        return "String".equals(this.getFullyQualifiedName())
453           || "java.lang.String".equals(this.getFullyQualifiedName())
454           || UMLMetafacadeUtils.isType(this, UMLProfile.STRING_TYPE_NAME);
455    }
456
457    /**
458     * @see org.andromda.metafacades.uml.ClassifierFacade#getAttributes()
459     */
460    @Override
461    protected List<Attribute> handleGetAttributes()
462    {
463        final List attributes = new ArrayList(this.metaObject.getFeature());
464        for (final Iterator iterator = attributes.iterator(); iterator.hasNext();)
465        {
466            if (!(iterator.next() instanceof Attribute))
467            {
468                iterator.remove();
469            }
470        }
471        return attributes;
472    }
473
474    /**
475     * @see org.andromda.metafacades.uml.ClassifierFacade#getAttributes(boolean)
476     */
477    @Override
478    protected List<AttributeFacade> handleGetAttributes(boolean follow)
479    {
480        final List<AttributeFacade> attributes = new ArrayList<AttributeFacade>(this.getAttributes());
481        for (ClassifierFacade superClass = (ClassifierFacade)getGeneralization(); superClass != null && follow;
482             superClass = (ClassifierFacade)superClass.getGeneralization())
483        {
484            for (final Iterator<AttributeFacade> iterator = superClass.getAttributes().iterator(); iterator.hasNext();)
485            {
486                final AttributeFacade superAttribute = iterator.next();
487                boolean present = false;
488                for (final Iterator<AttributeFacade> attributeIterator = this.getAttributes().iterator(); attributeIterator.hasNext();)
489                {
490                    final AttributeFacade attribute = attributeIterator.next();
491                    if (attribute.getName().equals(superAttribute.getName()))
492                    {
493                        present = true;
494                        break;
495                    }
496                }
497                if (!present)
498                {
499                    attributes.add(superAttribute);
500                }
501            }
502        }
503        return attributes;
504    }
505
506    /**
507     * @see org.andromda.metafacades.uml.ClassifierFacade#getProperties()
508     */
509    @Override
510    protected List handleGetProperties()
511    {
512        final List properties = new ArrayList(this.getAttributes());
513        properties.addAll(this.getNavigableConnectingEnds());
514        return properties;
515    }
516
517    /**
518     * @see org.andromda.metafacades.uml.ClassifierFacade#getAllProperties()
519     */
520    @Override
521    public Collection handleGetAllProperties()
522    {
523        return this.getProperties(true);
524    }
525
526    /**
527     * @see org.andromda.metafacades.uml.ClassifierFacade#getAllRequiredConstructorParameters()
528     */
529    @Override
530    public Collection handleGetAllRequiredConstructorParameters()
531    {
532        final Collection allRequiredConstructorParameters = new ArrayList();
533        allRequiredConstructorParameters.addAll(this.getRequiredConstructorParameters());
534
535        final Collection<GeneralizableElementFacade> generalizations = this.getGeneralizations();
536        for (Iterator<GeneralizableElementFacade> parents = generalizations.iterator(); parents.hasNext();)
537        {
538            final GeneralizableElementFacade parent = parents.next();
539            if (parent instanceof ClassifierFacade)
540            {
541                allRequiredConstructorParameters.addAll(((ClassifierFacade)parent).getAllRequiredConstructorParameters());
542            }
543        }
544
545        return allRequiredConstructorParameters;
546    }
547
548    /**
549     * @see org.andromda.metafacades.uml.ClassifierFacade#getRequiredConstructorParameters()
550     */
551    @Override
552    public Collection handleGetRequiredConstructorParameters()
553    {
554        final Collection requiredConstructorParameters = new ArrayList();
555
556        final Collection properties = this.getProperties();
557        for (Iterator propertyIterator = properties.iterator(); propertyIterator.hasNext();)
558        {
559            final Object property = propertyIterator.next();
560            if (property instanceof AttributeFacade)
561            {
562                final AttributeFacade attribute = (AttributeFacade)property;
563                if (!attribute.isDerived() && (attribute.isRequired() || attribute.isReadOnly()))
564                {
565                    requiredConstructorParameters.add(attribute);
566                }
567            }
568            else if (property instanceof AssociationEndFacade)
569            {
570                final AssociationEndFacade associationEnd = (AssociationEndFacade)property;
571                if (!associationEnd.isDerived() && (associationEnd.isRequired() || associationEnd.isReadOnly()))
572                {
573                    requiredConstructorParameters.add(associationEnd);
574                }
575            }
576        }
577
578        return requiredConstructorParameters;
579    }
580
581    /**
582     * @see org.andromda.metafacades.uml.ClassifierFacade#getProperties(boolean)
583     */
584    @Override
585    protected List handleGetProperties(boolean follow)
586    {
587        final List properties = new ArrayList(this.getAttributes(follow));
588        properties.addAll(this.getNavigableConnectingEnds());
589        if (follow)
590        {
591            for (ClassifierFacade superClass = (ClassifierFacade)getGeneralization(); superClass != null && follow;
592                 superClass = (ClassifierFacade)superClass.getGeneralization())
593            {
594                for (final AssociationEndFacade superAssociationEnd : superClass.getNavigableConnectingEnds())
595                {
596                    boolean present = false;
597                    for (final Iterator<AssociationEndFacade> endIterator = this.getAssociationEnds().iterator(); endIterator.hasNext();)
598                    {
599                        final AssociationEndFacade associationEnd = endIterator.next();
600                        if (associationEnd.getName().equals(superAssociationEnd.getName()))
601                        {
602                            present = true;
603                            break;
604                        }
605                    }
606                    if (!present)
607                    {
608                        properties.add(superAssociationEnd);
609                    }
610                }
611            }
612        }
613        return properties;
614    }
615
616    /**
617     * @see org.andromda.metafacades.uml.ClassifierFacade#getOperationCallFromAttributes()
618     */
619    @Override
620    protected String handleGetOperationCallFromAttributes()
621    {
622        final StringBuilder call = new StringBuilder();
623        String separator = "";
624        call.append('(');
625        for (final Iterator iterator = getAttributes().iterator(); iterator.hasNext();)
626        {
627            AttributeFacade attribute = (AttributeFacade)iterator.next();
628
629            call.append(separator);
630            String typeName = attribute.getType().getFullyQualifiedName();
631            call.append(typeName);
632            call.append(' ');
633            call.append(attribute.getName());
634            separator = ", ";
635        }
636        call.append(')');
637        return call.toString();
638    }
639
640    /**
641     * @see org.andromda.metafacades.uml.ClassifierFacade#isAbstract()
642     */
643    @Override
644    protected boolean handleIsAbstract()
645    {
646        return this.metaObject.isAbstract();
647    }
648
649    /**
650     * @see org.andromda.metafacades.uml.ClassifierFacade#getStaticAttributes()
651     */
652    @Override
653    protected Collection<AttributeFacade> handleGetStaticAttributes()
654    {
655        return new FilteredCollection(this.getAttributes())
656        {
657            private static final long serialVersionUID = 34L;
658            public boolean evaluate(Object object)
659            {
660                return ((AttributeFacade)object).isStatic();
661            }
662        };
663    }
664
665    /**
666     * @see org.andromda.metafacades.uml.ClassifierFacade#getInterfaceAbstractions()
667     */
668    @Override
669    protected Collection<ClassifierFacade> handleGetInterfaceAbstractions()
670    {
671        final Collection<ClassifierFacade> interfaceAbstractions = new LinkedHashSet<ClassifierFacade>();
672        if (this.getAbstractions() != null)
673        {
674            for (Iterator<ClassifierFacade> abstractionIterator = this.getAbstractions().iterator(); abstractionIterator.hasNext();)
675            {
676                final DependencyFacade abstraction = (DependencyFacade)abstractionIterator.next();
677                final ModelElementFacade element = abstraction.getTargetElement();
678
679                if (element instanceof ClassifierFacade)
680                {
681                    final ClassifierFacade classifier = (ClassifierFacade)element;
682                    if (classifier.isInterface())
683                    {
684                        interfaceAbstractions.add(classifier);
685                    }
686                }
687            }
688        }
689
690        return interfaceAbstractions;
691    }
692
693    /**
694     * @see org.andromda.metafacades.uml.ClassifierFacade#getImplementedInterfaceList()
695     */
696    @Override
697    protected String handleGetImplementedInterfaceList()
698    {
699        final String interfaceList;
700
701        final Collection<ClassifierFacade> interfaces = this.getInterfaceAbstractions();
702        if (interfaces.isEmpty())
703        {
704            interfaceList = "";
705        }
706        else
707        {
708            final StringBuilder list = new StringBuilder();
709            for (final Iterator iterator = interfaces.iterator(); iterator.hasNext();)
710            {
711                final ModelElementFacade element = (ModelElementFacade)iterator.next();
712                list.append(element.getBindedFullyQualifiedName(this));
713                if (iterator.hasNext())
714                {
715                    list.append(", ");
716                }
717            }
718            interfaceList = list.toString();
719        }
720
721        return interfaceList;
722    }
723
724    /**
725     * @see org.andromda.metafacades.uml.ClassifierFacade#getInstanceAttributes()
726     */
727    @Override
728    protected Collection<AttributeFacade> handleGetInstanceAttributes()
729    {
730        return new FilteredCollection(this.getAttributes())
731        {
732            private static final long serialVersionUID = 34L;
733            public boolean evaluate(Object object)
734            {
735                return !((AttributeFacade)object).isStatic();
736            }
737        };
738    }
739
740    /**
741     * @see org.andromda.metafacades.uml.ClassifierFacade#getAbstractions()
742     */
743    @Override
744    protected Collection<ClassifierFacade> handleGetAbstractions()
745    {
746        return new FilteredCollection(this.metaObject.getClientDependency())
747        {
748            private static final long serialVersionUID = 34L;
749            public boolean evaluate(Object object)
750            {
751                return object instanceof Abstraction;
752            }
753        };
754    }
755
756    /**
757     * @see org.andromda.metafacades.uml.ClassifierFacade#isDataType()
758     */
759    @Override
760    protected boolean handleIsDataType()
761    {
762        return DataType.class.isAssignableFrom(this.metaObject.getClass());
763    }
764
765    /**
766     * @see org.andromda.metafacades.uml.ClassifierFacade#isInterface()
767     */
768    @Override
769    protected boolean handleIsInterface()
770    {
771        return Interface.class.isAssignableFrom(this.metaObject.getClass());
772    }
773
774    /**
775     * @see org.andromda.metafacades.uml.ClassifierFacade#getNonArray()
776     */
777    @Override
778    protected ClassifierFacade handleGetNonArray()
779    {
780        ClassifierFacade nonArrayType = (ClassifierFacade)this.THIS();
781        if (this.getFullyQualifiedName().contains(this.getArraySuffix()))
782        {
783            nonArrayType =
784                (ClassifierFacade)this.getRootPackage().findModelElement(
785                    StringUtils.replace(
786                        this.getFullyQualifiedName(true),
787                        this.getArraySuffix(),
788                        ""));
789        }
790        return nonArrayType;
791    }
792
793    /**
794     * @see org.andromda.metafacades.uml.ClassifierFacade#getArray()
795     */
796    @Override
797    protected ClassifierFacade handleGetArray()
798    {
799        ClassifierFacade arrayType = (ClassifierFacade)this.THIS();
800        String name = this.getFullyQualifiedName(true);
801        if (!name.contains(this.getArraySuffix()))
802        {
803            name = name + this.getArraySuffix();
804            arrayType = (ClassifierFacade)this.getRootPackage().findModelElement(name);
805        }
806        return arrayType;
807    }
808
809    /**
810     * @see org.andromda.metafacades.uml.ClassifierFacade#isEnumeration()
811     */
812    @Override
813    protected boolean handleIsEnumeration()
814    {
815        return this.hasStereotype(UMLProfile.STEREOTYPE_ENUMERATION);
816    }
817
818    /**
819     * <p>
820     * A String representing the new Constructor value for this classifier type to
821     * be used in a Java environment.
822     * </p>
823     * @see org.andromda.metafacades.uml.ClassifierFacade#getJavaNullString()
824     */
825    @Override
826    protected String handleGetJavaNewString()
827    {
828        String javaNewString;
829        if (this.isPrimitive())
830        {
831            if (UMLMetafacadeUtils.isType(
832                    this,
833                    UMLProfile.BOOLEAN_TYPE_NAME))
834            {
835                javaNewString = "false";
836            }
837            else
838            {
839                javaNewString = "0";
840            }
841        }
842        else if (this.isWrappedPrimitive())
843        {
844            if (UMLMetafacadeUtils.isType(
845                this,
846                UMLProfile.BOOLEAN_TYPE_NAME))
847            {
848                javaNewString = "Boolean.FALSE";
849            }
850            else
851            {
852                javaNewString = this.getFullyQualifiedName() + ".valueOf(0)";
853            }
854        }
855        else
856        {
857            javaNewString = "new " + this.getFullyQualifiedName() + "()";
858        }
859        return javaNewString;
860    }
861
862    /**
863     * @see org.andromda.metafacades.uml.ClassifierFacade#getJavaNullString()
864     */
865    @Override
866    protected String handleGetJavaNullString()
867    {
868        String javaNullString;
869        if (isPrimitive())
870        {
871            if (UMLMetafacadeUtils.isType(
872                    this,
873                    UMLProfile.BOOLEAN_TYPE_NAME))
874            {
875                javaNullString = "false";
876            }
877            else
878            {
879                javaNullString = "0";
880            }
881        }
882        else
883        {
884            javaNullString = "null";
885        }
886        return javaNullString;
887    }
888
889    /**
890     * @see org.andromda.metafacades.uml.ClassifierFacade#getStaticOperations()
891     */
892    @Override
893    protected List<OperationFacade> handleGetStaticOperations()
894    {
895        return new FilteredCollection(this.getOperations())
896        {
897            private static final long serialVersionUID = 34L;
898            public boolean evaluate(Object object)
899            {
900                return ((OperationFacade)object).isStatic();
901            }
902        };
903    }
904
905    /**
906     * @see org.andromda.metafacades.uml.ClassifierFacade#getInstanceOperations()
907     */
908    @Override
909    protected List<OperationFacade> handleGetInstanceOperations()
910    {
911        return new FilteredCollection(this.getOperations())
912        {
913            private static final long serialVersionUID = 34L;
914            public boolean evaluate(Object object)
915            {
916                return !((OperationFacade)object).isStatic();
917            }
918        };
919    }
920
921    /**
922     * @see org.andromda.metafacades.uml.ClassifierFacade#findAttribute(String)
923     */
924    @Override
925    protected AttributeFacade handleFindAttribute(final String name)
926    {
927        return (AttributeFacade)CollectionUtils.find(
928            this.getAttributes(true),
929            new Predicate()
930            {
931                public boolean evaluate(Object object)
932                {
933                    final AttributeFacade attribute = (AttributeFacade)object;
934                    return StringUtils.trimToEmpty(attribute.getName()).equals(name);
935                }
936            });
937    }
938
939    /**
940     * @see org.andromda.metafacades.uml.ClassifierFacade#getArrayName()
941     */
942    @Override
943    protected String handleGetArrayName()
944    {
945        return this.getName() + this.getArraySuffix();
946    }
947
948    /**
949     * @see org.andromda.metafacades.uml.ClassifierFacade#getFullyQualifiedArrayName()
950     */
951    @Override
952    protected String handleGetFullyQualifiedArrayName()
953    {
954        return this.getFullyQualifiedName() + this.getArraySuffix();
955    }
956
957    /**
958     * @see org.andromda.metafacades.uml.ClassifierFacade#getSerialVersionUID()
959     */
960    @Override
961    protected long handleGetSerialVersionUID()
962    {
963        long serialVersionUID;
964        final String serialVersionString = UML14MetafacadeUtils.getSerialVersionUID(this);
965        if (serialVersionString != null)
966        {
967            serialVersionUID = Long.parseLong(serialVersionString);
968        }
969        else
970        {
971            serialVersionUID = MetafacadeUtils.calculateDefaultSUID(this);
972        }
973        return serialVersionUID;
974    }
975
976    /**
977     * @see org.andromda.metafacades.uml.ClassifierFacade#getNavigableConnectingEnds()
978     */
979    @Override
980    protected Collection handleGetNavigableConnectingEnds()
981    {
982        // TODO Change model return type from <ClassifierFacade> to <AssociationEndFacade>
983        final List<AssociationEndFacade> connectingEnds = new ArrayList<AssociationEndFacade>(this.getAssociationEnds());
984        CollectionUtils.transform(
985            connectingEnds,
986            new Transformer()
987            {
988                public AssociationEndFacade transform(final Object object)
989                {
990                    return ((AssociationEndFacade)object).getOtherEnd();
991                }
992            });
993        CollectionUtils.filter(
994            connectingEnds,
995            new Predicate()
996            {
997                public boolean evaluate(final Object object)
998                {
999                    return ((AssociationEndFacade)object).isNavigable();
1000                }
1001            });
1002        return connectingEnds;
1003    }
1004
1005    /**
1006     * @see org.andromda.metafacades.uml.ClassifierFacade#getNavigableConnectingEnds(boolean)
1007     */
1008    @Override
1009    protected List<AssociationEndFacade> handleGetNavigableConnectingEnds(boolean follow)
1010    {
1011        final List<AssociationEndFacade> connectionEnds = new ArrayList(this.getNavigableConnectingEnds());
1012
1013        for (ClassifierFacade superClass = (ClassifierFacade)getGeneralization(); superClass != null && follow;
1014             superClass = (ClassifierFacade)superClass.getGeneralization())
1015        {
1016            for (final AssociationEndFacade superAssociationEnd : superClass.getNavigableConnectingEnds())
1017            {
1018                boolean present = false;
1019                for (final Iterator<AssociationEndFacade> endIterator = this.getAssociationEnds().iterator(); endIterator.hasNext();)
1020                {
1021                    final AssociationEndFacade associationEnd = endIterator.next();
1022                    if (associationEnd.getName().equals(superAssociationEnd.getName()))
1023                    {
1024                        present = true;
1025                        break;
1026                    }
1027                }
1028                if (!present)
1029                {
1030                    connectionEnds.add(superAssociationEnd);
1031                }
1032            }
1033        }
1034        return connectionEnds;
1035    }
1036
1037    /**
1038     * @see org.andromda.metafacades.uml.ClassifierFacade#isLeaf()
1039     */
1040    @Override
1041    protected boolean handleIsLeaf()
1042    {
1043        return this.metaObject.isLeaf();
1044    }
1045
1046    /**
1047     * @see org.andromda.metafacades.uml14.ClassifierFacadeLogic#handleIsAssociationClass()
1048     */
1049    protected boolean handleIsAssociationClass()
1050    {
1051        return AssociationClass.class.isAssignableFrom(this.metaObject.getClass());
1052    }
1053
1054    /**
1055     * @see org.andromda.metafacades.uml14.ClassifierFacadeLogic#handleGetAssociatedClasses()
1056     */
1057    protected Collection<ClassifierFacade> handleGetAssociatedClasses()
1058    {
1059        final Set<ClassifierFacade> associatedClasses = new LinkedHashSet<ClassifierFacade>();
1060
1061        final List<AssociationEndFacade> associationEnds = this.getAssociationEnds();
1062        for (int i = 0; i < associationEnds.size(); i++)
1063        {
1064            final AssociationEndFacade associationEndFacade = associationEnds.get(i);
1065            associatedClasses.add(associationEndFacade.getOtherEnd().getType());
1066        }
1067
1068        return associatedClasses;
1069    }
1070
1071    /**
1072     * @see org.andromda.metafacades.uml14.ClassifierFacadeLogic#handleGetAllAssociatedClasses()
1073     */
1074    protected Collection<ClassifierFacade> handleGetAllAssociatedClasses()
1075    {
1076        final Set<ClassifierFacade> associatedClasses = new LinkedHashSet<ClassifierFacade>();
1077        associatedClasses.addAll(this.getAssociatedClasses());
1078        for (Iterator<GeneralizableElementFacade> parentIterator = this.getGeneralizations().iterator(); parentIterator.hasNext();)
1079        {
1080            final ClassifierFacade parent = (ClassifierFacade)parentIterator.next();
1081            associatedClasses.addAll(parent.getAllAssociatedClasses());
1082        }
1083
1084        return associatedClasses;
1085    }
1086
1087    /**
1088     * @see org.andromda.metafacades.uml14.ClassifierFacadeLogic#handleGetSuperClass()
1089     */
1090    protected ClassifierFacade handleGetSuperClass()
1091    {
1092        final GeneralizableElementFacade superClass = this.getGeneralization();
1093        return (ClassifierFacade)(superClass instanceof ClassifierFacade ? superClass : null);
1094    }
1095
1096    /**
1097     * @see org.andromda.metafacades.uml14.ClassifierFacadeLogic#handleIsEmbeddedValue()
1098     */
1099    protected boolean handleIsEmbeddedValue()
1100    {
1101        return this.hasStereotype(UMLProfile.STEREOTYPE_EMBEDDED_VALUE);
1102    }
1103}