/***************************************************************************** * Copyright (c) 2008 CEA LIST. * * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Chokri Mraidha (CEA LIST) Chokri.Mraidha@cea.fr - Initial API and implementation * Patrick Tessier (CEA LIST) Patrick.Tessier@cea.fr - modification * Vincent Lorenzo (CEA LIST) Vincent.Lorenzo@cea.fr - add getNearestProfileApplication *****************************************************************************/ package org.eclipse.papyrus.uml.profile.utils; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.core.runtime.Assert; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.papyrus.uml.profile.Activator; import org.eclipse.papyrus.uml.profile.Message; import org.eclipse.papyrus.uml.profile.definition.IPapyrusVersionConstants; import org.eclipse.papyrus.uml.profile.definition.PapyrusDefinitionAnnotation; import org.eclipse.papyrus.uml.profile.definition.Version; import org.eclipse.uml2.uml.Comment; import org.eclipse.uml2.uml.DataType; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.ElementImport; import org.eclipse.uml2.uml.Enumeration; import org.eclipse.uml2.uml.EnumerationLiteral; import org.eclipse.uml2.uml.InstanceSpecification; import org.eclipse.uml2.uml.LiteralBoolean; import org.eclipse.uml2.uml.LiteralInteger; import org.eclipse.uml2.uml.LiteralString; import org.eclipse.uml2.uml.LiteralUnlimitedNatural; import org.eclipse.uml2.uml.NamedElement; import org.eclipse.uml2.uml.Package; import org.eclipse.uml2.uml.PackageImport; import org.eclipse.uml2.uml.PrimitiveType; import org.eclipse.uml2.uml.Profile; import org.eclipse.uml2.uml.ProfileApplication; import org.eclipse.uml2.uml.Slot; import org.eclipse.uml2.uml.Stereotype; import org.eclipse.uml2.uml.StructuralFeature; import org.eclipse.uml2.uml.TemplateBinding; import org.eclipse.uml2.uml.TemplateSignature; import org.eclipse.uml2.uml.TemplateableElement; import org.eclipse.uml2.uml.Type; import org.eclipse.uml2.uml.ValueSpecification; import org.eclipse.uml2.uml.util.UMLUtil; /** * Some utils extracted from com.cea.utils classes (package and element) * TODO: not all are used, cleanup with respect to types */ public class Util { /** * Return a usable string label for passed object. * * @param object * the object * * @return the label */ public static String getLabel(Object object, boolean shortLabel) { String label = ""; if(object == null) { return "undefined"; } if(object instanceof ValueSpecification) { label = getLabel((ValueSpecification)object); } else if(object instanceof Element) { Element cE = (Element)object; String cName = null; String suffix = ""; String cComLabel = ""; NamedElement cNE = null; if(object instanceof NamedElement) { cNE = (NamedElement)object; } else if(object instanceof PackageImport) { PackageImport cPI = (PackageImport)object; suffix = " (PackageImport)"; cNE = cPI.getImportedPackage(); } else if(object instanceof ElementImport) { ElementImport cEI = (ElementImport)object; suffix = " (ElementImport)"; cNE = cEI.getImportedElement(); } else if(object instanceof ProfileApplication) { ProfileApplication cPA = (ProfileApplication)object; suffix = " (ProfileApplication)"; cNE = cPA.getAppliedProfile(); } else if(object instanceof Comment) { Comment cCom = (Comment)object; suffix = " (Comment)"; String cComBody = cCom.getBody(); if(cComBody != null && cComBody.length() >= 10) { cComLabel = cComBody.substring(0, 9) + "..."; } else { cComLabel = cComBody; } } else if(object instanceof TemplateSignature) { TemplateableElement te = ((TemplateSignature)object).getTemplate(); suffix = " (TemplateSignature owner)"; if(te instanceof NamedElement) { cNE = (NamedElement)te; } } else if(object instanceof TemplateBinding) { TemplateableElement te = ((TemplateBinding)object).getBoundElement(); suffix = " (TemplateBinding bound-element)"; if(te instanceof NamedElement) { cNE = (NamedElement)te; } } if(shortLabel) { if(object instanceof Comment) { cName = cComLabel; } else if(cNE != null) { cName = cNE.getName(); } } else { if(object instanceof Comment) { cName = cComLabel + suffix; } else if(cNE != null) { cName = cNE.getQualifiedName() + suffix; } } if(cName != null) { label = cName; } else { label = cE.toString(); } } return label; } /** * Check if a type is a metaclass. * * @param type * to check * * @return true if type is metaclass, else false */ public static boolean isMetaclass(Type type) { boolean isMetaclass = false; if((type instanceof org.eclipse.uml2.uml.Class) && (type.getAppliedStereotypes() != null) && (type.getAppliedStereotypes().size() > 0)) { Stereotype firstStereotype = type.getAppliedStereotypes().get(0); if(firstStereotype.getName().equals("Metaclass")) { isMetaclass = true; } } return isMetaclass; } /** * Convert the list of element in a list of string after some basic checks. * * @param elements * the elements * * @return the string array from list */ public static String[] getStringArrayFromList(List<Element> elements) { ArrayList<String> tmp = new ArrayList<String>(); // if no possible selection : abort if(elements.size() == 0) { return null; } // First create tmp list Iterator<Element> it = elements.iterator(); while(it.hasNext()) { Object current = it.next(); String label = getLabel(current, false); tmp.add(label); } // if no possible selection : abort if(tmp.size() == 0) { return null; } // Put this in array String[] elementsNames = new String[tmp.size()]; for(int i = 0; i < tmp.size(); i++) { elementsNames[i] = tmp.get(i); } // PostCondition if(elementsNames.length != elements.size()) { Message.error("Number of elements in name list does not match number or elements."); elementsNames = null; } return elementsNames; } /** * Treat a string provided by the user for a primitiveType and return * the corresponding object. * * @param dialogValue * user input string * @param type * expected * * @return object */ public static Object getValueObjectFromString(String dialogValue, Type type) { Object newValue = null; String typeName = type.getQualifiedName(); try { if(type instanceof PrimitiveType || ((type instanceof DataType) && !(type instanceof Enumeration))) { if(typeName.equals("UMLPrimitiveTypes::Integer")) { newValue = Integer.valueOf(dialogValue); } else if(typeName.equals("UMLPrimitiveTypes::UnlimitedNatural")) { if(Integer.signum(Integer.parseInt(dialogValue)) != -1) { newValue = Integer.valueOf(dialogValue); } else { Message.warning("UnlimitedNatural must be positive or null."); } } else if(typeName.equals("UMLPrimitiveTypes::String")) { newValue = dialogValue; } else if(typeName.equals("UMLPrimitiveTypes::Boolean")) { newValue = Boolean.valueOf(dialogValue); } else { // user defined primitive type newValue = dialogValue; } } else if(type instanceof Enumeration) { Enumeration enumeration = (Enumeration)type; EnumerationLiteral literal = enumeration.getOwnedLiteral(dialogValue); if(literal != null) { newValue = literal; } } } catch (NumberFormatException e) { Message.warning("Bad format number."); } catch (Exception e) { e.printStackTrace(); } return newValue; } /** * Helper function used by getInstancesFilteredByType */ private static void checkAndAddElement(EObject currentEObj, @SuppressWarnings("rawtypes") Class metaType, Stereotype appliedStereotype, ArrayList<Element> filteredElements) { if(currentEObj instanceof Element) { Element piCurrentElt = (Element)currentEObj; if(appliedStereotype != null) { // It is not sufficient to call getAppliedStereotypes, since we also want to // retrieve elements that apply a sub-stereotype if(piCurrentElt.getAppliedSubstereotype(appliedStereotype, null) != null) { filteredElements.add(piCurrentElt); } Iterator<Stereotype> appStIter = piCurrentElt.getAppliedStereotypes().iterator(); while(appStIter.hasNext()) { Stereotype currentSt = appStIter.next(); if(currentSt.conformsTo(appliedStereotype)) { filteredElements.add(piCurrentElt); } } } else { // if (appliedStereotype == null) if(metaType.isInstance(piCurrentElt)) { filteredElements.add(piCurrentElt); } /** add imported meta elements */ else if(piCurrentElt instanceof ElementImport) { Iterator<EObject> eIter = ((ElementImport)piCurrentElt).getImportedElement().eAllContents(); while(eIter.hasNext()) { EObject currentEIelt = eIter.next(); if((currentEIelt instanceof Element) && (metaType.isInstance(currentEIelt))) { filteredElements.add((Element)currentEIelt); } } } } } } /** * Retrieve an ArrayList of all instances in the model that * are instances of the java.lang.Class metaType or with a * stereotype applied * * @param metaType * selected classes * @param model * to check * @param appliedStereotype * may be null, metatype is ignored if not null * @return an arraylist containing the selected instances */ public static ArrayList<Element> getInstancesFilteredByType(Element element, @SuppressWarnings("rawtypes") Class metaType, Stereotype appliedStereotype) { // retrieve parent element Package topPackage = Util.topPackage(element); Assert.isNotNull(topPackage, "Top package should not be null for element " + element); Iterator<EObject> iter = topPackage.eAllContents(); ArrayList<Element> filteredElements = new ArrayList<Element>(); while(iter.hasNext()) { EObject currentEObj = iter.next(); // If currentElt is an ElementImport, it is replaced by the imported // Element. if(currentEObj instanceof ElementImport) { ElementImport elementImport = (ElementImport)currentEObj; currentEObj = elementImport.getImportedElement(); } /* package imports treatment */ else if(currentEObj instanceof PackageImport) { Package importedPkg = ((PackageImport)currentEObj).getImportedPackage(); if(importedPkg != null) { Iterator<EObject> piIter = importedPkg.eAllContents(); while(piIter.hasNext()) { EObject piCurrentEObj = piIter.next(); checkAndAddElement(piCurrentEObj, metaType, appliedStereotype, filteredElements); } } } // Filtering elements checkAndAddElement(currentEObj, metaType, appliedStereotype, filteredElements); } return filteredElements; } /** * Reorder stereotype applications. * * @param element * the element * @param stereotypes * the stereotypes */ public static void reorderStereotypeApplications(Element element, EList<Stereotype> stereotypes) { for(Iterator<Stereotype> s = stereotypes.iterator(); s.hasNext();) { EObject stereotypeApplication = element.getStereotypeApplication(s.next()); if(stereotypeApplication != null) { UMLUtil.setBaseElement(stereotypeApplication, null); UMLUtil.setBaseElement(stereotypeApplication, element); Resource eResource = stereotypeApplication.eResource(); if(eResource != null) { EList<EObject> contents = eResource.getContents(); contents.move(contents.size() - 1, stereotypeApplication); } } } } /** * Return the labe for a value specification * * @param object * @return */ public static String getLabel(ValueSpecification value) { String label = ""; if(value instanceof LiteralBoolean) { label = "<LiteralBoolean> "; } else if(value instanceof LiteralInteger) { label = "<LiteralInteger> "; } else if(value instanceof LiteralString) { label = "<LiteralString> "; } else if(value instanceof LiteralUnlimitedNatural) { label = "<LiteralUnlimitedNatural> "; } else { label = "<ValueSpecification> "; } // Add the value label = label + value.stringValue(); return label; } /** * Return the label for a value specification * * @param object * @return */ public static String getOriginLabel(ValueSpecification value) { String label = getLabel(value); Element owner = value.getOwner(); // Add parent qualified name when possible if(owner instanceof NamedElement) { NamedElement ownerNE = (NamedElement)value.getOwner(); if(ownerNE.isSetName()) { label = label + " (" + ownerNE.getQualifiedName() + ")"; } } else if(owner instanceof Slot) { Slot ownerSlot = (Slot)owner; InstanceSpecification ownerISpec = ownerSlot.getOwningInstance(); StructuralFeature definingFeature = ownerSlot.getDefiningFeature(); label = label + " (" + ownerISpec.getQualifiedName() + "::" + definingFeature.getLabel() + ")"; } // else nothing return label; } /** * This method is used to look for the top package that contains this element. * * @param element * the element for which top package must be returned * @return the top package */ public static Package topPackage(Element element) { if(element.getOwner() == null) { return (Package)element; } else { return topPackage(element.getOwner()); } } /** * Returns every PapyrusDefinitionAnnotation corresponding to the version of profile definitions * * @param profile * the profile to study * @return every eAnnotations associated to the profile definitions or an empty list if no * eAnnotation exists for given profile */ public static List<PapyrusDefinitionAnnotation> getAllPapyrusDefinitionAnnotation(Profile profile) { List<PapyrusDefinitionAnnotation> definitions = new ArrayList<PapyrusDefinitionAnnotation>(); Iterator<EAnnotation> it = getAllPapyrusVersionAnnotation(profile).iterator(); while(it.hasNext()) { definitions.add(PapyrusDefinitionAnnotation.parseEAnnotation(it.next())); } return definitions; } /** * Returns every eAnnotations associated to the profile definitions * * @param profile * the profile to study * @return every eAnnotations associated to the profile definitions or an empty list if no * eAnnotation exists for given profile */ public static List<EAnnotation> getAllPapyrusVersionAnnotation(Profile profile) { List<EAnnotation> annotations = new ArrayList<EAnnotation>(); EAnnotation definitions = profile.getEAnnotation("http://www.eclipse.org/uml2/2.0.0/UML"); if(definitions == null) { return annotations; } Iterator<EObject> it = definitions.getContents().iterator(); while(it.hasNext()) { // content are EPackage EPackage object = (EPackage)it.next(); EAnnotation annotation = object.getEAnnotation(IPapyrusVersionConstants.PAPYRUS_EANNOTATION_SOURCE); if(annotation != null) { annotations.add(annotation); } } return annotations; } /** * Returns the eAnnotation associated to the current profile definition * * @return the eAnnotation associated to the current profile definition or <code>null</code> if no * eAnnotation exists for given profile */ public static EAnnotation getPapyrusVersionAnnotation(Profile profile) { if(profile.getDefinition() != null) { return profile.getDefinition().getEAnnotation(IPapyrusVersionConstants.PAPYRUS_EANNOTATION_SOURCE); } return null; } /** * Returns the version of the current profile definition * * @param profile * the profile to check * @return the version of the current profile definition */ public static Version getProfileDefinitionVersion(Profile profile) { EAnnotation annotation = getPapyrusVersionAnnotation(profile); if(annotation == null) { return Version.emptyVersion; } else { // retrieve the version from the annotation Version version; String value = ""; try { value = annotation.getDetails().get(IPapyrusVersionConstants.PAPYRUS_VERSION_KEY); version = new Version((value != null) ? value : ""); } catch (Exception e) { Activator.logWarning("impossible to parse the version value: " + value); version = Version.emptyVersion; } return version; } } /** * Returns the author of the current profile definition * * @param profile * the profile to check * @return the author of the current profile definition or the empty string if none was given */ public static String getProfileDefinitionAuthor(Profile profile) { EAnnotation annotation = getPapyrusVersionAnnotation(profile); if(annotation == null) { return ""; } else { // retrieve the version from the annotation final String value = annotation.getDetails().get(IPapyrusVersionConstants.PAPYRUS_AUTHOR_KEY); return (value != null) ? value : ""; } } /** * Returns the date of the current profile definition * * @param profile * the profile to check * @return the date of the current profile definition or the empty string if none was given */ public static String getProfileDefinitionDate(Profile profile) { EAnnotation annotation = getPapyrusVersionAnnotation(profile); if(annotation == null) { return ""; } else { // retrieve the version from the annotation final String value = annotation.getDetails().get(IPapyrusVersionConstants.PAPYRUS_DATE_KEY); return (value != null) ? value : ""; } } /** * Returns the comment of the current profile definition * * @param profile * the profile to check * @return the comment of the current profile definition or the empty string if none was given */ public static String getProfileDefinitionComment(Profile profile) { EAnnotation annotation = getPapyrusVersionAnnotation(profile); if(annotation == null) { return ""; } else { // retrieve the version from the annotation final String value = annotation.getDetails().get(IPapyrusVersionConstants.PAPYRUS_COMMENT_KEY); return (value != null) ? value : ""; } } /** * Returns the copyright of the current profile definition * * @param profile * the profile to check * @return the copyright of the current profile definition or the empty string if none was given */ public static String getProfileDefinitionCopyright(Profile profile) { EAnnotation annotation = getPapyrusVersionAnnotation(profile); if(annotation == null) { return ""; } else { // retrieve the version from the annotation final String value = annotation.getDetails().get(IPapyrusVersionConstants.PAPYRUS_COPYRIGHT_KEY); return (value != null) ? value : ""; } } /** * We look for the nearest profile application from the Element, owning the stereotype; * * @param stereotype * @return * the nearest profile application owning the stereotype */ public static ProfileApplication getNearestProfileApplicationFor(final Element element, final Stereotype stereotype) { ProfileApplication profileApplication = null; Profile profile = stereotype.getProfile(); EObject container = element; while(profileApplication == null && container != null) { if(container instanceof Package) { profileApplication = ((Package)container).getProfileApplication(profile); } container = container.eContainer(); } return profileApplication; } }