001package org.andromda.metafacades.uml14;
002
003import java.util.ArrayList;
004import java.util.Collection;
005import java.util.Comparator;
006import java.util.Iterator;
007import java.util.LinkedHashSet;
008import java.util.List;
009import java.util.Set;
010import java.util.TreeSet;
011import org.andromda.metafacades.uml.ActorFacade;
012import org.andromda.metafacades.uml.AssociationEndFacade;
013import org.andromda.metafacades.uml.AttributeFacade;
014import org.andromda.metafacades.uml.ClassifierFacade;
015import org.andromda.metafacades.uml.DependencyFacade;
016import org.andromda.metafacades.uml.Entity;
017import org.andromda.metafacades.uml.EntityAttribute;
018import org.andromda.metafacades.uml.GeneralizableElementFacade;
019import org.andromda.metafacades.uml.ManageableEntity;
020import org.andromda.metafacades.uml.ModelElementFacade;
021import org.andromda.metafacades.uml.UMLMetafacadeProperties;
022import org.andromda.metafacades.uml.UMLProfile;
023import org.andromda.utils.StringUtilsHelper;
024import org.apache.commons.lang.ObjectUtils;
025import org.apache.commons.lang.StringUtils;
026
027/**
028 * MetafacadeLogic implementation for org.andromda.metafacades.uml.ManageableEntity.
029 *
030 * @see org.andromda.metafacades.uml.ManageableEntity
031 * @author Bob Fields
032 */
033public class ManageableEntityLogicImpl
034    extends ManageableEntityLogic
035{
036    private static final long serialVersionUID = -1239526138513293700L;
037
038    /**
039     * @param metaObject
040     * @param context
041     */
042    public ManageableEntityLogicImpl(Object metaObject, String context)
043    {
044        super(metaObject, context);
045    }
046
047    /**
048     * @return the configured property denoting the character sequence to use for the separation of namespaces
049     */
050    private String getNamespaceSeparator()
051    {
052        return (String)getConfiguredProperty(UMLMetafacadeProperties.NAMESPACE_SEPARATOR);
053    }
054
055    /**
056     * @return manageablePackageName
057     * @see org.andromda.metafacades.uml.ManageableEntity#getManageablePackageName()
058     */
059    protected String handleGetManageablePackageName()
060    {
061        String manageablePackageName = "";
062
063        final String parentPackage = super.getPackageName();
064        if (StringUtils.isNotBlank(parentPackage))
065        {
066            manageablePackageName = parentPackage;
067        }
068
069        final Object suffix = getConfiguredProperty(UMLMetafacadeProperties.MANAGEABLE_PACKAGE_NAME_SUFFIX);
070        if (suffix != null && StringUtils.isNotBlank(suffix.toString()))
071        {
072            manageablePackageName += this.getNamespaceSeparator() + suffix;
073        }
074
075        return manageablePackageName;
076    }
077
078    /**
079     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleGetManageablePackagePath()
080     */
081    protected String handleGetManageablePackagePath()
082    {
083        return StringUtils.replace(this.getManageablePackageName(), this.getNamespaceSeparator(), "/");
084    }
085
086    /**
087     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleGetManageableAssociationEnds()
088     */
089    protected List handleGetManageableAssociationEnds()
090    {
091        final Set manageableAssociationEnds = new LinkedHashSet();// linked hashset to guarantee ordering wo/ duplicates
092        collectAssociationEnds(manageableAssociationEnds, this);
093        return new ArrayList(manageableAssociationEnds);
094    }
095
096    /**
097     * This method recursively collects all association ends to which a manageable entity would need to navigate
098     *
099     * @param manageableAssociationEnds the collection in which to collect the association ends
100     * @param entity the entity from which to recursively gather the association ends
101     */
102    private static void collectAssociationEnds(Collection<AssociationEndFacade> manageableAssociationEnds, ManageableEntity entity)
103    {
104        final Collection<AssociationEndFacade> associationEnds = entity.getAssociationEnds();
105        for (final Iterator<AssociationEndFacade> associationEndIterator = associationEnds.iterator(); associationEndIterator.hasNext();)
106        {
107            final AssociationEndFacade associationEnd = associationEndIterator.next();
108            final AssociationEndFacade otherEnd = associationEnd.getOtherEnd();
109
110            if (otherEnd.isNavigable() && otherEnd.getType() instanceof Entity)
111            {
112                manageableAssociationEnds.add(otherEnd);
113            }
114        }
115
116        // retrieve all association ends for all parents (recursively)
117        final Collection<GeneralizableElementFacade> parentEntities = entity.getAllGeneralizations();
118        for (final Iterator<GeneralizableElementFacade> parentEntityIterator = parentEntities.iterator(); parentEntityIterator.hasNext();)
119        {
120            final Object parentEntityObject = parentEntityIterator.next();
121            if (parentEntityObject instanceof ManageableEntity)
122            {
123                collectAssociationEnds(manageableAssociationEnds, (ManageableEntity)parentEntityObject);
124            }
125        }
126    }
127
128    /**
129     * @return !this.isAbstract()
130     * @see org.andromda.metafacades.uml.ManageableEntity#isCreate()
131     */
132    protected boolean handleIsCreate()
133    {
134        return !this.isAbstract();
135    }
136
137    /**
138     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleGetManageableServiceName()
139     */
140    protected String handleGetManageableServiceName()
141    {
142        return getName() + "ManageableService";
143    }
144
145    /**
146     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleGetManageableServiceFullPath()
147     */
148    protected String handleGetManageableServiceFullPath()
149    {
150        return '/' + StringUtils.replace(
151            getFullyQualifiedManageableServiceName(),
152            getNamespaceSeparator(),
153            "/");
154    }
155
156    /**
157     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleGetFullyQualifiedManageableServiceName()
158     */
159    protected String handleGetFullyQualifiedManageableServiceName()
160    {
161        return this.getManageablePackageName() + this.getNamespaceSeparator() + getManageableServiceName();
162    }
163
164    /**
165     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleGetManageableServiceAccessorCall()
166     */
167    protected String handleGetManageableServiceAccessorCall()
168    {
169        final String property = UMLMetafacadeProperties.MANAGEABLE_SERVICE_ACCESSOR_PATTERN;
170        final String accessorImplementation =
171            this.isConfiguredProperty(property) ? ObjectUtils.toString(this.getConfiguredProperty(property))
172                : "${application.package}.ManageableServiceLocator.instance().get{1}()";
173        return accessorImplementation.replaceAll(
174            "\\{0\\}",
175            getManageablePackageName()).replaceAll(
176            "\\{1\\}",
177            getManageableServiceName());
178    }
179
180    /**
181     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleIsRead()
182     */
183    protected boolean handleIsRead()
184    {
185        return true;
186    }
187
188    /**
189     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleIsUpdate()
190     */
191    protected boolean handleIsUpdate()
192    {
193        return this.getManageableIdentifier() != null; // TODO Implement handleIsUpdate
194    }
195
196    /**
197     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleIsDelete()
198     */
199    protected boolean handleIsDelete()
200    {
201        return this.getManageableIdentifier() != null; // TODO Implement handleIsDelete
202    }
203
204    /**
205     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleGetManageableAttributes()
206     */
207    protected List handleGetManageableAttributes()
208    {
209        return new ArrayList(this.getAttributes(true));
210    }
211
212    /**
213     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleGetManageableIdentifier()
214     */
215    protected Object handleGetManageableIdentifier()
216    {
217        return this.getIdentifiers(true).iterator().next();
218    }
219
220    /**
221     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleGetManageableMembers()
222     */
223    protected List handleGetManageableMembers()
224    {
225        final List criteria = new ArrayList();
226        criteria.addAll(this.getManageableAttributes());
227        criteria.addAll(this.getManageableAssociationEnds());
228        return criteria;
229    }
230
231    private enum ListType
232    {
233        PRIMITIVE,
234        WRAPPER;
235    }
236
237    private String createListWithManageableMembers(ListType listType)
238    {
239        final StringBuilder buffer = new StringBuilder();
240
241        final List attributes = this.getManageableAttributes();
242        for (int i = 0; i < attributes.size(); i++)
243        {
244            if (buffer.length() > 0)
245            {
246                buffer.append(", ");
247            }
248
249            final AttributeFacade attribute = (AttributeFacade)attributes.get(i);
250            final ClassifierFacade type = attribute.getType();
251            if (type != null)
252            {
253                if(ListType.PRIMITIVE.equals(listType))
254                {
255                    buffer.append(type.getFullyQualifiedName());
256                    buffer.append(' ');
257                }
258                else if(ListType.WRAPPER.equals(listType))
259                {
260                    buffer.append(type.isPrimitive()? type.getWrapperName(): type.getFullyQualifiedName());
261                    buffer.append(' ');
262                }
263                buffer.append(attribute.getName());
264            }
265        }
266
267        final List associationEnds = this.getManageableAssociationEnds();
268        for (int i = 0; i < associationEnds.size(); i++)
269        {
270            final AssociationEndFacade associationEnd = (AssociationEndFacade)associationEnds.get(i);
271            final Entity entity = (Entity)associationEnd.getType();
272
273            if(entity.isCompositeIdentifier())
274            {
275                if (buffer.length() > 0)
276                {
277                    buffer.append(", ");
278                }
279                if (listType != null)
280                {
281                    buffer.append("Object");
282                    if (associationEnd.isMany())
283                    {
284                        buffer.append("[]");
285                    }
286                    buffer.append(' ');
287                }
288                buffer.append(associationEnd.getName());
289            }
290            else
291            {
292                final Iterator<ModelElementFacade> identifierIterator = entity.getIdentifiers().iterator();
293                if (identifierIterator.hasNext())
294                {
295                    final ModelElementFacade identifier = identifierIterator.next();
296                    if (identifier != null)
297                    {
298                        if (buffer.length() > 0)
299                        {
300                            buffer.append(", ");
301                        }
302
303                        ClassifierFacade type = null;
304                        if (identifier instanceof AttributeFacade)
305                        {
306                            type = ((AttributeFacade)identifier).getType();
307                        }
308                        else if (identifier instanceof AssociationEndFacade)
309                        {
310                            type = ((AssociationEndFacade)identifier).getType();
311                        }
312
313                        if (type != null)
314                        {
315                            if (listType != null)
316                            {
317                                buffer.append(type.getFullyQualifiedName());
318                                if (associationEnd.isMany())
319                                {
320                                    buffer.append("[]");
321                                }
322                                buffer.append(' ');
323                            }
324                            buffer.append(associationEnd.getName());
325                        }
326                    }
327                }
328            }
329        }
330
331        return buffer.toString();
332    }
333
334    /**
335     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleListManageableMembersWithWrapperTypes()
336     */
337    protected String handleListManageableMembersWithWrapperTypes()
338    {
339        return createListWithManageableMembers(ListType.WRAPPER);
340    }
341
342    /**
343     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleListManageableMembers(boolean)
344     */
345    protected String handleListManageableMembers(boolean withTypes)
346    {
347        return createListWithManageableMembers(withTypes? ListType.PRIMITIVE: null);
348    }
349
350    /**
351     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleIsManageable()
352     */
353    protected boolean handleIsManageable()
354    {
355        return Boolean.valueOf((String)this.getConfiguredProperty(
356            UMLMetafacadeProperties.ENABLE_MANAGEABLE_ENTITIES)).booleanValue();
357    }
358
359    /**
360     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleGetReferencingManageables()
361     */
362    protected List handleGetReferencingManageables()
363    {
364        final Set referencingManageables = new LinkedHashSet();
365        final Collection associationEnds = getAssociationEnds();
366        for (final Iterator associationEndIterator = associationEnds.iterator(); associationEndIterator.hasNext();)
367        {
368            final AssociationEndFacade associationEnd = (AssociationEndFacade)associationEndIterator.next();
369
370            if (associationEnd.isNavigable())
371            {
372                if (associationEnd.isMany() || (associationEnd.isOne2One() && associationEnd.isChild()))
373                {
374                    final Object otherEndType = associationEnd.getOtherEnd().getType();
375                    if (otherEndType instanceof Entity)
376                    {
377                        referencingManageables.add(otherEndType);
378                    }
379                }
380            }
381        }
382        return new ArrayList(referencingManageables);
383    }
384
385    /**
386     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleGetDisplayAttribute()
387     */
388    protected Object handleGetDisplayAttribute()
389    {
390        Object displayAttribute = null;
391
392        final Object taggedValueObject = findTaggedValue(UMLProfile.TAGGEDVALUE_MANAGEABLE_DISPLAY_NAME);
393        if (taggedValueObject != null)
394        {
395            displayAttribute = findAttribute(StringUtilsHelper.trimToEmpty(taggedValueObject.toString()));
396        }
397
398        final Collection attributes = getAttributes(true);
399        for (final Iterator attributeIterator = attributes.iterator();
400            attributeIterator.hasNext() && displayAttribute == null;)
401        {
402            // TODO: UML2 migrated models automatically mark all * attributes as unique. Different display attributes are selected from UML14 and UML2 migrated models.
403            // This selects the first attribute that is unique as the display value.
404            final Object attribute = attributeIterator.next();
405            if(attribute instanceof EntityAttribute)//can get attributes from ancestor classes
406            {
407                final EntityAttribute entityAttribute = (EntityAttribute)attribute;
408                if (entityAttribute.isUnique())
409                {
410                    displayAttribute = entityAttribute;
411                }
412            }
413        }
414
415        if (displayAttribute == null)
416        {
417            if (!getIdentifiers().isEmpty())
418            {
419                displayAttribute = getIdentifiers().iterator().next();
420            }
421            else if (!attributes.isEmpty())
422            {
423                displayAttribute = attributes.iterator().next();
424            }
425        }
426
427        return displayAttribute;
428    }
429
430    /**
431     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleGetUsers()
432     */
433    protected List handleGetUsers()
434    {
435        final Set users = new LinkedHashSet();
436
437        final Collection<DependencyFacade> dependencies = getTargetDependencies();
438        for (final Iterator<DependencyFacade> dependencyIterator = dependencies.iterator(); dependencyIterator.hasNext();)
439        {
440            final DependencyFacade dependency = dependencyIterator.next();
441            final Object dependencyObject = dependency.getSourceElement();
442
443            if (!users.contains(dependencyObject) && dependencyObject instanceof ActorFacade)
444            {
445                collectActors((ActorFacade)dependencyObject, users);
446            }
447        }
448
449        return new ArrayList(users);
450    }
451
452    private void collectActors(ActorFacade actor, Collection actors)
453    {
454        if (!actors.contains(actor))
455        {
456            actors.add(actor);
457
458            final Collection<ActorFacade> childActors = actor.getGeneralizedByActors();
459            for (final Iterator<ActorFacade> iterator = childActors.iterator(); iterator.hasNext();)
460            {
461                final ActorFacade childActor = iterator.next();
462                collectActors(childActor, actors);
463            }
464        }
465    }
466
467    /**
468     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleGetMaximumListSize()
469     */
470    protected int handleGetMaximumListSize()
471    {
472        int maximumListSize;
473
474        final Object taggedValueObject = findTaggedValue(UMLProfile.TAGGEDVALUE_MANAGEABLE_MAXIMUM_LIST_SIZE);
475        if (taggedValueObject != null)
476        {
477            try
478            {
479                maximumListSize = Integer.parseInt(taggedValueObject.toString());
480            }
481            catch (NumberFormatException e)
482            {
483                maximumListSize = internalDefaultMaximumListSize();
484            }
485        }
486        else
487        {
488            maximumListSize = internalDefaultMaximumListSize();
489        }
490
491        return maximumListSize;
492    }
493
494    private int internalDefaultMaximumListSize()
495    {
496        int maximumListSize;
497
498        try
499        {
500            maximumListSize =
501                Integer.parseInt((String)getConfiguredProperty(UMLMetafacadeProperties.PROPERTY_DEFAULT_MAX_LIST_SIZE));
502        }
503        catch (NumberFormatException e1)
504        {
505            maximumListSize = -1;
506        }
507
508        return maximumListSize;
509    }
510
511    /**
512     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleGetPageSize()
513     */
514    protected int handleGetPageSize()
515    {
516        int pageSize;
517
518        final Object taggedValueObject = findTaggedValue(UMLProfile.TAGGEDVALUE_MANAGEABLE_PAGE_SIZE);
519        if (taggedValueObject != null)
520        {
521            try
522            {
523                pageSize = Integer.parseInt(taggedValueObject.toString());
524            }
525            catch (NumberFormatException e)
526            {
527                pageSize = internalDefaultPageSize();
528            }
529        }
530        else
531        {
532            pageSize = internalDefaultPageSize();
533        }
534
535        return pageSize;
536    }
537
538    private int internalDefaultPageSize()
539    {
540        int pageSize;
541
542        try
543        {
544            pageSize =
545                Integer.parseInt((String)getConfiguredProperty(UMLMetafacadeProperties.PROPERTY_DEFAULT_PAGE_SIZE));
546        }
547        catch (NumberFormatException e1)
548        {
549            pageSize = 20;
550        }
551
552        return pageSize;
553    }
554
555    /**
556     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleIsResolveable()
557     */
558    protected boolean handleIsResolveable()
559    {
560        boolean resolveable;
561
562        final Object taggedValueObject = findTaggedValue(UMLProfile.TAGGEDVALUE_MANAGEABLE_RESOLVEABLE);
563        if (taggedValueObject != null)
564        {
565            try
566            {
567                resolveable = Boolean.valueOf(taggedValueObject.toString()).booleanValue();
568            }
569            catch (NumberFormatException e)
570            {
571                resolveable = internalDefaultResolveable();
572            }
573        }
574        else
575        {
576            resolveable = internalDefaultResolveable();
577        }
578
579        return resolveable;
580    }
581
582    private boolean internalDefaultResolveable()
583    {
584        boolean resolveable;
585
586        try
587        {
588            resolveable =
589                Boolean.valueOf((String)getConfiguredProperty(UMLMetafacadeProperties.PROPERTY_DEFAULT_RESOLVEABLE))
590                       .booleanValue();
591        }
592        catch (NumberFormatException ex)
593        {
594            resolveable = true;
595        }
596
597        return resolveable;
598    }
599
600    /**
601     * @see org.andromda.metafacades.uml14.ManageableEntityLogic#handleGetAllManageables()
602     */
603    protected List<ClassifierFacade> handleGetAllManageables()
604    {
605        final Set<ClassifierFacade> allManageableEntities = new TreeSet(new ManageableComparator());
606
607        final Collection<ClassifierFacade> allClasses = getModel().getAllClasses();
608        for (final Iterator<ClassifierFacade> classIterator = allClasses.iterator(); classIterator.hasNext();)
609        {
610            final ClassifierFacade classObject = classIterator.next();
611            if (classObject instanceof ManageableEntity)
612            {
613                allManageableEntities.add(classObject);
614            }
615        }
616
617        return new ArrayList<ClassifierFacade>(allManageableEntities);
618    }
619
620    /**
621     *
622     */
623    static final class ManageableComparator
624        implements Comparator
625    {
626        /**
627         * @see java.util.Comparator#compare(Object, Object)
628         */
629        public int compare(Object left, Object right)
630        {
631            final ModelElementFacade leftEntity = (ModelElementFacade)left;
632            final ModelElementFacade rightEntity = (ModelElementFacade)right;
633
634            return leftEntity.getName().compareTo(rightEntity.getName());
635        }
636    }
637}