Package org.andromda.metafacades.emf.uml2

Source Code of org.andromda.metafacades.emf.uml2.StereotypeFilter

package org.andromda.metafacades.emf.uml2;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.andromda.core.common.ExceptionUtils;
import org.andromda.core.metafacade.MetafacadeConstants;
import org.andromda.metafacades.uml.ClassifierFacade;
import org.andromda.metafacades.uml.UMLProfile;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.Transformer;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.uml2.Association;
import org.eclipse.uml2.Classifier;
import org.eclipse.uml2.Comment;
import org.eclipse.uml2.Element;
import org.eclipse.uml2.EnumerationLiteral;
import org.eclipse.uml2.Generalization;
import org.eclipse.uml2.InstanceSpecification;
import org.eclipse.uml2.LiteralInteger;
import org.eclipse.uml2.LiteralString;
import org.eclipse.uml2.LiteralUnlimitedNatural;
import org.eclipse.uml2.Model;
import org.eclipse.uml2.MultiplicityElement;
import org.eclipse.uml2.NamedElement;
import org.eclipse.uml2.Namespace;
import org.eclipse.uml2.Operation;
import org.eclipse.uml2.Package;
import org.eclipse.uml2.Parameter;
import org.eclipse.uml2.Profile;
import org.eclipse.uml2.Property;
import org.eclipse.uml2.Slot;
import org.eclipse.uml2.Stereotype;
import org.eclipse.uml2.UML2Package;
import org.eclipse.uml2.ValueSpecification;
import org.eclipse.uml2.util.UML2Resource;
import org.eclipse.uml2.util.UML2Util;


/**
* Contains utilities for the Eclipse/UML2 metafacades.
*
* @author Steve Jerman
* @author Chad Brandon
* @author Wouter Zoons
*/
public class UmlUtilities
{
    /**
     * The logger instance.
     */
    private static Logger logger = Logger.getLogger(UmlUtilities.class);

    /**
     * A transformer which transforms:
     * <ul>
     *   <li>each property in an attribute or an association end</li>
     *   <li>each slot in an attribute link or a link end</li>
     *   <li>each instance specification in an object instance or a link instance</li>
     * </ul>
     * This is needed because UML2 is an API in which there is no conceptual difference between
     * fundamentally different elements (see list above); which makes it harder to map to metafacades
     * geared towards UML 1.4
     */
    protected static final Transformer ELEMENT_TRANSFORMER =
        new Transformer()
        {
            public Object transform(Object element)
            {
                final Object transformedObject;

                if (element instanceof Property)
                {
                    final Property property = (Property)element;

                    if (property instanceof AssociationEnd || property instanceof Attribute)
                    {
                        transformedObject = property;
                    }
                    else if (property.getAssociation() != null)
                    {
                        transformedObject = new AssociationEndImpl(property);
                    }
                    else
                    {
                        transformedObject = new AttributeImpl(property);
                    }
                }
                else if (element instanceof Slot)
                {
                    final Slot slot = (Slot)element;

                    if (slot instanceof LinkEnd || slot instanceof AttributeLink)
                    {
                        transformedObject = slot;
                    }
                    else if (this.transform(slot.getDefiningFeature()) instanceof Attribute)
                    {
                        transformedObject = new AttributeLinkImpl(slot);
                    }
                    else
                    {
                        transformedObject = new LinkEndImpl(slot);
                    }
                }
                else if (element instanceof InstanceSpecification)
                {
                    final InstanceSpecification instanceSpecification = (InstanceSpecification)element;

                    if (instanceSpecification instanceof LinkInstance ||
                        instanceSpecification instanceof ObjectInstance ||
                        instanceSpecification instanceof EnumerationLiteral)
                    {
                        transformedObject = instanceSpecification;
                    }
                    else if (!instanceSpecification.getClassifiers().isEmpty() &&
                        instanceSpecification.getClassifiers().iterator().next() instanceof org.eclipse.uml2.Class)
                    {
                        transformedObject = new ObjectInstanceImpl(instanceSpecification);
                    }
                    else
                    {
                        transformedObject = new LinkInstanceImpl(instanceSpecification);
                    }
                }
                else
                {
                    transformedObject = element;
                }

                return transformedObject;
            }
        };

    private static Map allMetaObjectsCache = new HashMap();

    /**
     * List all meta objects instances of a given meta class It's a way to
     * achieve refAllOfType method in a JMI implementation. Please take care of the
     * fact that properties are not transformed here.
     *
     * @param metaClass The meta class we're looking for its instances
     * @param model     The model where we're searching
     * @return a list of objects owned by model, instance of metaClass
     */
    public static List getAllMetaObjectsInstanceOf(
        final java.lang.Class metaClass,
        final Model model)
    {
        List metaObjects = (List)allMetaObjectsCache.get(metaClass);
        if (metaObjects == null)
        {
            metaObjects = new ArrayList();

            for (Iterator it = model.eAllContents(); it.hasNext();)
            {
                Object metaObject = it.next();
                if (metaClass.isInstance(metaObject))
                {
                    metaObjects.add(metaObject);
                }
            }

            if (logger.isDebugEnabled())
            {
                logger.debug("getAllMetaObjectsInstanceOf class: " + metaClass + ". Found: " + metaObjects.size());
            }
            allMetaObjectsCache.put(metaClass, metaObjects);
        }
        return metaObjects;
    }

    /**
     * This clears the meta objects cache.  Even though this
     * isn't the "cleanest" way to handle things, we need this
     * for performance reasons (getAllMetaObjectsInstanceOf is WAY
     * to slow otherwise).
     */
    public static void clearAllMetaObjectsCache()
    {
        allMetaObjectsCache.clear();
    }

    /**
     * Get the comments for a UML Element. This will be a string with each
     * comment separated by a 2 newlines.
     *
     * @param element
     * @return concatenated string
     */
    public static String getComment(final Element element)
    {
        String commentString = "";
        EList comments = element.getOwnedComments();

        for (Iterator iterator = comments.iterator(); iterator.hasNext();)
        {
            final Comment comment = (Comment)iterator.next();
            if (!commentString.equalsIgnoreCase(""))
            {
                commentString = commentString + "\n\n";
            }
            commentString = commentString.concat(comment.getBody());
        }
        return cleanText(commentString);
    }

    /**
     * Gets rid of all excess whitespace.
     *
     * @param text the text from which to remove the white space.
     * @return the cleaned text.
     */
    public static String cleanText(String text)
    {
        text =
            text.replaceAll(
                "[\\t\\n]*",
                "");
        text =
            text.replaceAll(
                "\\s+",
                " ");

        return text;
    }

    /**
     * Gets a collection containing all of the attributes for this
     * class/interface. Superclass properties will included if
     * <code>follow</code> is true. Overridden properties will be omitted.
     *
     * @param classifier the UML class instance from which to retrieve all properties
     * @param follow        whether or not the inheritance hierarchy should be followed
     * @return all retrieved attributes.
     */
    public static List getAttributes(
        final Classifier classifier,
        final boolean follow)
    {
        final Map attributeMap = new LinkedHashMap(); // preserve ordering
        final List members = new ArrayList(classifier.getOwnedMembers());

        if (follow)
        {
            members.addAll(classifier.getInheritedMembers());
        }

        for (final Iterator memberIterator = members.iterator(); memberIterator.hasNext();)
        {
            final Object nextCandidate = memberIterator.next();
            if (nextCandidate instanceof Property)
            {
                final Property property = (Property)nextCandidate;

                if (property.getAssociation() == null)
                {
                    if (logger.isDebugEnabled())
                    {
                        logger.debug("Attribute found for " + classifier.getName() + ": " + property.getName());
                        if (attributeMap.containsKey(property.getName()))
                        {
                            logger.warn(
                                "An attribute with this name has already been registered, overriding: " +
                                property.getName());
                        }
                    }

                    // property represents an association end
                    attributeMap.put(
                        property.getName(),
                        property);
                }
            }
        }

        final List attributeList = new ArrayList(attributeMap.values());
        CollectionUtils.transform(
            attributeList,
            ELEMENT_TRANSFORMER);
        return attributeList;
    }

    /**
     * Returns <code>true</code> if the given association end's type is an ancestor of the classifier, or just the
     * argument classifier if follow is <code>false</code>.
     *
     * @param property this method returns false if this argument is not an association end
     */
    public static boolean isAssociationEndAttachedToType(
        final Classifier classifier,
        final Property property,
        final boolean follow)
    {
        boolean attachedToType = false;

        if (property.getAssociation() != null)
        {
            attachedToType = classifier.equals(property.getType());
            if (follow && !attachedToType)
            {
                final List parents = classifier.getGenerals();
                for (final Iterator iterator = parents.iterator(); iterator.hasNext();)
                {
                    final Object parent = iterator.next();
                    if (parent instanceof Classifier)
                    {
                        attachedToType =
                            isAssociationEndAttachedToType(
                                (Classifier)parent,
                                property,
                                follow);
                    }
                }
            }
        }
        return attachedToType;
    }

    /**
     * Gets a collection containing all of the associationEnds for this
     * class/interface. Superclass properties will be included if
     * <code>follow</code> is true. Overridden properties will be omitted.
     * <p/>
     * cejeanne: Changed the way association end are found.
     *
     * @param classifier the UML class instance from which to retrieve all properties
     * @param follow     whether or not the inheritance hierarchy should be followed
     * @return all retrieved attributes.
     */
    public static List getAssociationEnds(
        final Classifier classifier,
        final boolean follow)
    {
        final List associationEnds = new ArrayList();
        final List allProperties = getAllMetaObjectsInstanceOf(
                Property.class,
                classifier.getModel());

        for (final Iterator propertyIterator = allProperties.iterator(); propertyIterator.hasNext();)
        {
            final Property property = (Property)propertyIterator.next();

            // only treat association ends, ignore attributes
            if (property.getAssociation() != null && isAssociationEndAttachedToType(
                    classifier,
                    property,
                    follow))
            {
                associationEnds.add(property);
            }
        }

        CollectionUtils.transform(
            associationEnds,
            ELEMENT_TRANSFORMER);
        return associationEnds;
    }

    /**
     * Returns <code>true</code> if and only if the given operation would have an identical signature.
     * This means:
     * <ul>
     <li>the same name</li>
     <li>the same number of parameters</li>
     <li>matching parameter types (in that very same order)</li>
     * </ul>
     */
    public static boolean isSameSignature(
        final Operation first,
        final Operation second)
    {
        boolean sameSignature = true;

        // test name
        if (isEqual(
                first.getName(),
                second.getName()))
        {
            final List firstParameters = first.getOwnedParameters();
            final List secondParameters = second.getOwnedParameters();

            // test number of parameters
            if (firstParameters.size() == secondParameters.size())
            {
                for (int i = 0; i < firstParameters.size() && sameSignature; i++)
                {
                    final Parameter firstParameter = (Parameter)firstParameters.get(i);
                    final Parameter secondParameter = (Parameter)secondParameters.get(i);

                    // test each parameter's type
                    sameSignature =
                        isEqual(
                            firstParameter.getType(),
                            secondParameter.getType());
                }
            }
            else
            {
                sameSignature = false;
            }
        }
        else
        {
            sameSignature = false;
        }

        return sameSignature;
    }

    /**
     * Returns <code>true</code> if and only if both arguments are equal, this method handles potential
     * incoming <code>null</code> values.
     */
    private static boolean isEqual(
        Object first,
        Object second)
    {
        return first == null ? second == null : first.equals(second);
    }

    /**
     * Retrieves all specializations of the given <code>classifier</code>
     * instance.
     *
     * @param classifier the classifier from which to retrieve the specializations.
     * @return all specializations.
     */
    public static List getSpecializations(final Classifier classifier)
    {
        final List specials = new ArrayList();
        for (final TreeIterator iterator = EcoreUtil.getRootContainer(classifier).eAllContents(); iterator.hasNext();)
        {
            final EObject object = (EObject)iterator.next();
            if (object instanceof Generalization)
            {
                final Generalization generalization = (Generalization)object;
                if (generalization.getGeneral().equals(classifier))
                {
                    specials.add(generalization.getSpecific());
                }
                iterator.prune();
            }
        }
        return specials;
    }

    /**
     * Retrieves the names of the stereotypes for the given <code>element</code>
     *
     * @param element the element for which to retrieve the stereotypes.
     * @return all stereotype names
     */
    public static List getStereotypeNames(final Element element)
    {
        final Collection stereotypes = element.getAppliedStereotypes();
        final List names = new ArrayList();
        if (stereotypes != null)
        {
            for (final Iterator iterator = stereotypes.iterator(); iterator.hasNext();)
            {
                final Stereotype stereotype = (Stereotype)iterator.next();
                names.add(stereotype.getName());
            }
        }
        return names;
    }

    /**
     * Indicates whether or not the given <code>element</code> contains a
     * stereotype with the given <code>stereotypeName</code>.
     *
     * @param element the element instance.
     * @param stereotypeName the name of the stereotype
     * @return true/false
     */
    public static boolean containsStereotype(
        final Element element,
        final String stereotypeName)
    {
        Collection stereotypes = element.getAppliedStereotypes();

        boolean hasStereotype = StringUtils.isNotBlank(stereotypeName) && stereotypes != null &&
            !stereotypes.isEmpty();

        if (hasStereotype)
        {
            class StereotypeFilter
                implements Predicate
            {
                public boolean evaluate(Object object)
                {
                    boolean valid;
                    Stereotype stereotype = (Stereotype)object;
                    String name = StringUtils.trimToEmpty(stereotype.getName());
                    valid = stereotypeName.equals(name);
                    for (Iterator itStereo = stereotype.allParents().iterator(); !valid && itStereo.hasNext();)
                    {
                        Stereotype currentStereotype = (Stereotype)itStereo.next();
                        valid = StringUtils.trimToEmpty(currentStereotype.getName()).equals(stereotypeName);
                    }
                    return valid;
                }
            }
            hasStereotype =
                CollectionUtils.find(
                    stereotypes,
                    new StereotypeFilter()) != null;
        }
        if (logger.isDebugEnabled())
        {
            if (element instanceof NamedElement)
            {
                logger.debug(
                    ((NamedElement)element).getQualifiedName() + " has stereotype <<" + stereotypeName + ">> : " +
                    hasStereotype);
            }
            else
            {
                logger.debug(element.toString() + " has stereotype <<" + stereotypeName + ">> : " + hasStereotype);
            }
        }
        return hasStereotype;
    }

    /**
     * @deprecated old way to handle tag values
     *             Note: The uml profile defines it as "AndroMdaTags" and not "AndroMDATags"
     *             Stores the tagged values that may be applied to an element.
     */
    private static final String TAGGED_VALUES_STEREOTYPE = "AndroMdaTags";

    /**
     * Retrieves the TagDefinitions for the given element.
     *
     * @param element the element from which to retrieve the tagged values.
     * @return the collection of {@link TagDefinition} instances.
     */
    public static Collection getTaggedValue(final Element element)
    {
      String elementName = "";

      if (element instanceof NamedElement) {
      elementName = ((NamedElement)element).getName();
    }
      else
      {
        elementName = element.toString();
      }

      if (logger.isDebugEnabled())
        {
            logger.debug("Searching Tagged Values for " + elementName);
        }
        final Collection tags = new ArrayList();
        final Collection stereotypes = element.getAppliedStereotypes();
        for (Iterator stereoIt = stereotypes.iterator(); stereoIt.hasNext();)
        {
            Stereotype stereo = (Stereotype)stereoIt.next();
            if (stereo.getName().equals(TAGGED_VALUES_STEREOTYPE))
            {
                List tagNames = (List)element.getValue(
                        stereo,
                        "TagName");
                List tagValues = (List)element.getValue(
                        stereo,
                        "TagValue");
                for (int ctr = 0; ctr < tagValues.size(); ctr++)
                {
                    tags.add(new TagDefinitionImpl(
                            tagNames.get(ctr).toString(),
                            tagValues.get(ctr)));
                }
            }
            else if (element.hasValue(
                    stereo,
                    "value"))
            {
                final Object value = element.getValue(
                        stereo,
                        "value");
                tags.add(new TagDefinitionImpl(
                        stereo.getName(),
                        value));
            }
            else
            {
                for (Iterator tvIt = getAttributes(
                            stereo,
                            true).iterator(); tvIt.hasNext();)
                {
                    Property tagProperty = (Property)tvIt.next();
                    String tagName = tagProperty.getName();
                    if (!tagName.startsWith("base$"))
                    {
                        if (element.hasValue(
                                stereo,
                                tagName))
                        {
                            // Obtain its value
                            Object tagValue = element.getValue(
                                    stereo,
                                    tagName);
                            if (tagValue instanceof Collection)
                            {
                                Collection tagValues = (Collection)tagValue;
                                if (!tagValues.isEmpty())
                                {
                                    Collection tagValuesInString =
                                        CollectionUtils.collect(
                                            tagValues,
                                            new Transformer()
                                            {
                                                public Object transform(Object object)
                                                {
                                                    return getTagValueAsString(object);
                                                }
                                            });
                                    TagDefinition tagDefinition = new TagDefinitionImpl(tagName, tagValuesInString);
                                    tags.add(tagDefinition);
                                }
                            }
                            else
                            {
                                TagDefinition tagDefinition =
                                    new TagDefinitionImpl(tagName,
                                        getTagValueAsString(tagValue));
                                tags.add(tagDefinition);
                            }
                        }
                    }
                }
            }
        }

        if (logger.isDebugEnabled())
        {
            logger.debug("Found " + tags.size() + " tagged values for " + elementName);
        }

        return tags;
    }

    /**
     * The toString() method isn't suitable to transform the values of tagValue as String.
     * @param tagValue
     * @return the tag value as a string.
     */
    static String getTagValueAsString(Object tagValue)
    {
        String valueAsString = null;
        if (tagValue != null)
        {
            valueAsString = tagValue.toString();
            if (tagValue instanceof ValueSpecification)
            {
                ValueSpecification literal = (ValueSpecification)tagValue;
                valueAsString = literal.stringValue();
            }
            else if (tagValue instanceof InstanceSpecification)
            {
                InstanceSpecification instance = (InstanceSpecification)tagValue;
                valueAsString = instance.getName();
            }
        }
        return valueAsString;
    }

    /**
     * Attempts to find the applied stereotype with the given name on the given
     * <code>element</code>. First tries to find it with the fully qualified
     * name, and then tries it with just the name.
     *
     * @param name
     *            the name of the stereotype
     * @return the found stereotype or null if not found.
     */
    public static Stereotype findAppliedStereotype(
        final Element element,
        final String name)
    {
        Stereotype foundStereotype = element.getAppliedStereotype(name);
        if (foundStereotype == null)
        {
            final Set stereotypes = element.getAppliedStereotypes();
            if (stereotypes != null)
            {
                for (final Iterator iterator = stereotypes.iterator(); iterator.hasNext();)
                {
                    final Stereotype stereotype = (Stereotype)iterator.next();
                    if (stereotype.getName().equals(name))
                    {
                        foundStereotype = stereotype;
                        break;
                    }
                }
            }
        }
        return foundStereotype;
    }

    /**
     * Attempts to find the applicable stereotype with the given name on the
     * given <code>element</code>. First tries to find it with the fully
     * qualified name, and then tries it with just the name.
     *
     * @param name the name of the stereotype
     * @return the found stereotype or null if not found.
     */
    public static Stereotype findApplicableStereotype(
        final Element element,
        final String name)
    {
        Stereotype foundStereotype = element.getApplicableStereotype(name);
        if (foundStereotype == null)
        {
            final Set stereotypes = element.getApplicableStereotypes();
            if (stereotypes != null)
            {
                for (final Iterator iterator = stereotypes.iterator(); iterator.hasNext();)
                {
                    final Stereotype stereotype = (Stereotype)iterator.next();
                    if (stereotype.getName().equals(name))
                    {
                        foundStereotype = stereotype;
                        break;
                    }
                }
            }
        }
        return foundStereotype;
    }

    /**
     * Retrieves the serial version UID by reading the tagged value
     * {@link UMLProfile#TAGGEDVALUE_SERIALVERSION_UID} of the
     * <code>classifier</code>.
     *
     * @param classifier the classifier to be inspected.
     * @return the serial version UID of the classifier. Returns
     *         <code>null</code> if the tagged value cannot be found.
     */
    static String getSerialVersionUID(final ClassifierFacade classifier)
    {
        ExceptionUtils.checkNull(
            "classifer",
            classifier);
        String serialVersionString = (String)classifier.findTaggedValue(UMLProfile.TAGGEDVALUE_SERIALVERSION_UID);
        return StringUtils.trimToNull(serialVersionString);
    }

    /**
     * Gets the opposite end of the given <code>associationEnd</code> if the
     * property is indeed an association end, otherwise returns null.
     *
     * @param associationEnd the association end from which to retrieve the opposite end.
     * @return the opposite association end or null.
     */
    static AssociationEnd getOppositeAssociationEnd(final Property associationEnd)
    {
        Object opposite = associationEnd.getOpposite();
        if (opposite == null)
        {
            Association association = associationEnd.getAssociation();

            if (association != null)
            {
                Collection ends = association.getMemberEnds();
                for (final Iterator endIterator = ends.iterator(); endIterator.hasNext();)
                {
                    final Object end = endIterator.next();
                    if (end != null && !associationEnd.equals(end))
                    {
                        opposite = end;
                        break;
                    }
                }
            }
        }
        return new AssociationEndImpl((Property)opposite);
    }

    /**
     * Finds and returns the first model element having the given
     * <code>name</code> in the <code>modelPackage</code>, returns
     * <code>null</code> if not found.
     *
     * @return the found model element.
     */
    static Object findByPredicate(
        final ResourceSet resourceSet,
        final Predicate pred)
    {
        Object modelElement = null;
        for (final Iterator iterator = resourceSet.getResources().iterator();
            iterator.hasNext() && modelElement == null;)
        {
            final Resource resource = (Resource)iterator.next();
            final Package model =
                (Package)EcoreUtil.getObjectByType(
                    resource.getContents(),
                    UML2Package.eINSTANCE.getPackage());
            if (model != null)
            {
                for (final TreeIterator elementIterator = model.eAllContents();
                    elementIterator.hasNext() && modelElement == null;)
                {
                    final Object object = elementIterator.next();
                    if (pred.evaluate(object))
                    {
                        modelElement = object;
                    }
                }
            }
        }

        return modelElement;
    }

    /**
     * Find the Model of a ressource (UML2 Model)
     */
    public static Model findModel(final UML2Resource resource)
    {
        Model model = (Model)EcoreUtil.getObjectByType(
                resource.getContents(),
                EcorePackage.eINSTANCE.getEObject());
        if (logger.isDebugEnabled())
        {
            logger.debug("Model found: " + model);
        }
        return model;
    }

    /**
     * Constructs the package name for the given <code>metaObject</code>,
     * seperating the package name by the given <code>separator</code>.
     *
     * @param metaObject the Model Element
     * @param separator  the PSM namespace separator, ignored if <code>modelName</code> is <code>true</code>
     * @param modelName  true/false on whether or not to get the model package name
     *                   instead of the PSM package name.
     * @return the package name.
     */
    static String getPackageName(
        final NamedElement metaObject,
        final String separator,
        final boolean modelName)
    {
        final StringBuffer buffer = new StringBuffer();

        final String usedSeparator = modelName ? MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR : separator;

        for (Namespace namespace = metaObject.getNamespace(); namespace != null;
            namespace = namespace.getNamespace())
        {
            if (namespace instanceof Package && !(namespace instanceof Model) && !(namespace instanceof Profile))
            {
                if (buffer.length() != 0)
                {
                    buffer.insert(
                        0,
                        usedSeparator);
                }

                buffer.insert(
                    0,
                    namespace.getName());
            }
        }
        String packageName = buffer.toString();
        if (modelName && StringUtils.isNotBlank(packageName))
        {
            packageName =
                StringUtils.replace(
                    packageName,
                    separator,
                    MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR);
        }

        return packageName;
    }

    /**
     * Returns the package name of the closest ancestor that is an instance of <code>NamedElement</code>. If no such
     * ancestor exists the empty String is returned.
     * <p/>
     * If the argument would be an instance of <code>NamedElement</code> then this method returns that object's
     * package name.
     *
     * @see #getPackageName(org.eclipse.uml2.NamedElement, String, boolean)
     */
    static String getPackageName(
        final Element metaObject,
        final String separator,
        final boolean modelName)
    {
        final String packageName;

        if (metaObject instanceof NamedElement)
        {
            packageName =
                getPackageName(
                    (NamedElement)metaObject,
                    separator,
                    modelName);
        }
        else if (metaObject.getOwner() == null)
        {
            packageName = "";
        }
        else
        {
            packageName =
                getPackageName(
                    metaObject.getOwner(),
                    separator,
                    modelName);
        }

        return packageName;
    }

    /**
     * Finds and returns the first model element having the given
     * <code>name</code> in the <code>modelPackage</code>, returns
     * <code>null</code> if not found.
     *
     * @param rs   the resource set to search in
     * @param name the name to find.
     * @return the found model element.
     */
    static Object findByName(
        final ResourceSet rs,
        final String name)
    {
        Object modelElement = null;
        if (StringUtils.isNotBlank(name))
        {
            modelElement =
                findByPredicate(
                    rs,
                    new Predicate()
                    {
                        public boolean evaluate(final Object object)
                        {
                            if (object instanceof NamedElement)
                            {
                                return StringUtils.trimToEmpty(((NamedElement)object).getName()).equals(name);
                            }
                            return false;
                        }
                    });
        }
        return modelElement;
    }

    /**
     * Finds a given model element in the model having the specified
     * <code>fullyQualifiedName</code>. If the model element can <strong>NOT
     * </strong> be found, <code>null</code> will be returned instead.
     *
     * @param resourceSet                 the resource set to search in
     * @param fullyQualifiedName the fully qualified name of the element to search for.
     * @param separator          the PSM separator used for qualifying the name (example ".").
     * @param modelName          a flag indicating whether or not a search shall be performed
     *                           using the fully qualified model name or fully qualified PSM
     *                           name.
     * @return the found model element
     */
    static Object findByFullyQualifiedName(
        final ResourceSet resourceSet,
        final String fullyQualifiedName,
        final String separator,
        final boolean modelName)
    {
        Object modelElement;
        modelElement =
            findByPredicate(
                resourceSet,
                new Predicate()
                {
                    public boolean evaluate(final Object object)
                    {
                        if (object instanceof NamedElement)
                        {
                            NamedElement element = (NamedElement)object;
                            StringBuffer fullName = new StringBuffer(getPackageName(
                                        element,
                                        separator,
                                        modelName));
                            String name = element.getName();
                            if (StringUtils.isNotBlank(name))
                            {
                                String namespaceSeparator = MetafacadeConstants.NAMESPACE_SCOPE_OPERATOR;
                                if (!modelName)
                                {
                                    namespaceSeparator = separator;
                                }
                                fullName.append(namespaceSeparator);
                                fullName.append(name);
                            }
                            return fullName.toString().equals(fullyQualifiedName);
                        }
                        return false;
                    }
                });
        return modelElement;
    }

    /**
     * Multiplicity can be expressed as Value. String, integer... This method
     * parse it. MD11.5 uses string, and RSM integers.
     *
     * @param multValue a ValueSpecification, which need to be parsed
     * @return the parsed intrger
     */
    static int parseMultiplicity(final ValueSpecification multValue)
    {
        int value = 1;
        if (multValue != null)
        {
            if (multValue instanceof LiteralInteger)
            {
                LiteralInteger litInt = (LiteralInteger)multValue;
                value = litInt.getValue();
            }
            else if (multValue instanceof LiteralUnlimitedNatural)
            {
                LiteralUnlimitedNatural litInt = (LiteralUnlimitedNatural)multValue;
                value = litInt.getValue();
            }

            else if (multValue instanceof LiteralString)
            {
                LiteralString litStr = (LiteralString)multValue;
                String multString = litStr.getValue();
                if (multString.equals("*"))
                {
                    value = MultiplicityElement.UNLIMITED_UPPER_BOUND;
                }
                else
                {
                    value = Integer.parseInt(multString);
                }
            }
            else
            {
                logger.error("Unable to parse this value as multiplicity: " + multValue);
            }
        }
        if (logger.isDebugEnabled())
        {
            logger.debug("Parsing multiplicity: intValue = " + value + " value: " + multValue);
        }
        return value;
    }

    /**
     * There is an issue with EMF / XMI about tag value name (there should not be any @ or . inside)
     * This method checks whether <code>tagValueName</code> can be seen as <code>requestedName</code>.
     * <li>We compare them either:
     *   without name transformation
     *   removing initial '@' and replacing '.' by '_' (rsm / emf-uml2 profile)
     * EMF normalization (for MD11.5 export)
     *
     * @param requestedName
     * @param tagValueName
     */
    public static boolean doesTagValueNameMatch(
        String requestedName,
        String tagValueName)
    {
        boolean result = requestedName.equals(tagValueName);
        if (!result && requestedName.startsWith("@"))
        {
            // let's try rsm guess
            String rsmName = requestedName.substring(1);
            rsmName =
                rsmName.replace(
                    '.',
                    '_');
            result = rsmName.equals(tagValueName);
            if (!result)
            {
                // let's try emf normalization
                String emfName = EMFNormalizer.getEMFName(requestedName);
                result = emfName.equals(tagValueName);
            }
        }
        return result;
    }

    // hack to use a protected method
    private static class EMFNormalizer
        extends UML2Util
    {
        public static String getEMFName(String name)
        {
            return getValidIdentifier(name);
        }
    }
}
TOP

Related Classes of org.andromda.metafacades.emf.uml2.StereotypeFilter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.