/*****************************************************************************
* 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:
* Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.uml.tools.utils;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.EnumerationLiteral;
import org.eclipse.uml2.uml.Image;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Stereotype;
import org.eclipse.uml2.uml.util.UMLUtil;
/**
* Utility class for Stereotypes.
*/
public class StereotypeUtil {
protected static final String QUOTE = "\"";
protected static final String SPACE_SEPARATOR = "#";
protected static final String EQUAL_SEPARATOR = "=";
protected static final String PROPERTY_VALUE_SEPARATOR = "|";
protected static final String SETREOTYPE_WITH_VALUE_SEPARATOR = ";";
protected static final String ST_LEFT = String.valueOf("\u00AB");
protected static final String ST_RIGHT = String.valueOf("\u00BB");
/**
* returns the list of all super stereotypes for the specified stereotype
*
* @param stereotype
* the stereotype for which super-stereotypes are looked for.
* @return the list of all stereotypes from which the specified stereotype inherits
*/
public static List<Stereotype> getAllSuperStereotypes(Stereotype stereotype) {
List<Stereotype> generalStereotypes = new ArrayList<Stereotype>();
for(Classifier generalClassifier : stereotype.getGenerals()) {
if(generalClassifier instanceof Stereotype) {
generalStereotypes.add((Stereotype)generalClassifier);
generalStereotypes.addAll(getAllSuperStereotypes((Stereotype)generalClassifier));
}
}
return generalStereotypes;
}
/**
* Parse the stereotype image and select those that have an "icon" kind (EAnnotation).
*
* @param stereotype
* to parse
*
* @return a EList of {@link Image}
*/
public static EList<Image> getIcons(Stereotype stereotype) {
EList<Image> icons = new BasicEList<Image>();
Iterator<Image> it = stereotype.getIcons().iterator();
while(it.hasNext()) {
Image image = it.next();
if("icon".equals(ImageUtil.getKind(image))) {
icons.add(image);
}
}
return icons;
}
/**
* Returns the list of names (not qualified) of properties to display.
*
* @param stereotype
* @param stPropList
*
* @return
*/
private static List<String> getStereoPropertiesToDisplay(org.eclipse.uml2.uml.Stereotype stereotype, List<String> stPropList) {
ArrayList<String> result = new ArrayList<String>();
Iterator<String> propIter = stPropList.iterator();
while(propIter.hasNext()) {
String currentProp = propIter.next();
if(currentProp.substring(0, currentProp.lastIndexOf(".")).equals(stereotype.getQualifiedName())) {
result.add(currentProp.substring(currentProp.lastIndexOf(".") + 1, currentProp.length()));
}
}
return result;
}
/**
* return string that contains value of properties of applied stereotype
*
* @param stereotypesPropertiesToDisplay
* list of properties of stereotype to display grammar=
* {<B>stereotypequalifiedName</B>'.'<B>propertyName</B>','}*
*
* @return a string withe the following grammar grammar=
* {'\u00AB'<B>StereotypeName</B>'\u00BB''#'
* {<B>propertyName</B>'='<B>propertyValue</B>'|'}*';'}*
*/
public static String getPropertiesValues(String stereotypesPropertiesToDisplay, Element umlElement) {
HashSet<org.eclipse.uml2.uml.Stereotype> stereoSet = new HashSet<org.eclipse.uml2.uml.Stereotype>();
ArrayList<String> stPropList = new ArrayList<String>();
String propValues = "";
// fill our data structure in order to generate the string
StringTokenizer propStringTokenizer = new StringTokenizer(stereotypesPropertiesToDisplay, ",");
while(propStringTokenizer.hasMoreElements()) {
// extract property to display
String propertyQN = propStringTokenizer.nextToken();
// stereotype
String stereotypeQN = propertyQN.substring(0, propertyQN.indexOf("."));
Stereotype stereotype = umlElement.getAppliedStereotype(stereotypeQN);
if(stereotype != null) {
stereoSet.add(stereotype);
}
stPropList.add(propertyQN);
}
// Display each stereotype
Iterator<org.eclipse.uml2.uml.Stereotype> stereoIter = stereoSet.iterator();
while(stereoIter.hasNext()) {
org.eclipse.uml2.uml.Stereotype stereotype = stereoIter.next();
// display the stereotype
propValues = propValues + ST_LEFT + stereotype.getName() + ST_RIGHT + SPACE_SEPARATOR;
// get the set of property to display
Iterator<String> stPropIter = getStereoPropertiesToDisplay(stereotype, stPropList).iterator();
// display each property
while(stPropIter.hasNext()) {
String stProp = stPropIter.next();
// get the property
org.eclipse.uml2.uml.Property currentProp = getPropertyByName(stereotype, stProp);
if(currentProp == null) {
return "No value";
}
propValues += displayPropertyValue(stereotype, currentProp, umlElement, PROPERTY_VALUE_SEPARATOR);
}// display each property
if(propValues.endsWith(PROPERTY_VALUE_SEPARATOR)) {
propValues = propValues.substring(0, propValues.lastIndexOf(PROPERTY_VALUE_SEPARATOR));
}
propValues = propValues + SETREOTYPE_WITH_VALUE_SEPARATOR;
}// end display each property
return propValues;
}
/**
* Computes the display of a property value.
*
* @param stereotype
* the stereotype that contains the property to be displayed
* @param property
* the property to be displayed
* @param umlElement
* the element that is stereotyped by the specified
* @param separator
* the separator between each property value, in case several properties are
* displayed for the same property
* @return a string corresponding to the property value
*/
public static String displayPropertyValue(Stereotype stereotype, Property property, Element umlElement, String separator) {
org.eclipse.uml2.uml.Type propType = property.getType();
// property type is an enumeration
if(propType instanceof org.eclipse.uml2.uml.Enumeration) {
return getPropertyValueForEnumerationType(property, stereotype, umlElement, EQUAL_SEPARATOR, separator);
}
// property type is a metaclass
else if((propType instanceof org.eclipse.uml2.uml.Class) && (propType.getAppliedStereotypes() != null) && (propType.getAppliedStereotypes().size() > 0) && ((org.eclipse.uml2.uml.Stereotype)propType.getAppliedStereotypes().get(0)).getName().equals("Metaclass")) {
return getPropertyValueForMetaclassType(property, stereotype, umlElement, EQUAL_SEPARATOR, separator,false);
}
// property type is a stereotype
else if(propType instanceof org.eclipse.uml2.uml.Stereotype) {
return getPropertyValueForStereotypeType(property, stereotype, umlElement, EQUAL_SEPARATOR, separator,false);
}
// property is a composite class
else if((propType instanceof org.eclipse.uml2.uml.Class) && !(propType instanceof org.eclipse.uml2.uml.Stereotype) && property.isComposite()) {
return /* FIXME stProp + */property.getName() + EQUAL_SEPARATOR + property.getName() + separator;
}
// otherwise
else {
return getPropertyValue(property, stereotype, umlElement, EQUAL_SEPARATOR, separator,false);
}
}
/**
* Computes the display of a property value.
*
* @param stereotype
* the stereotype that contains the property to be displayed
* @param property
* the property to be displayed
* @param umlElement
* the element that is stereotyped by the specified
* @param separator
* the separator between each property value, in case several properties are
* displayed for the same property
* @return a string corresponding to the property value
*/
public static String displayPropertyValueToEdit(Stereotype stereotype, Property property, Element umlElement, String separator) {
org.eclipse.uml2.uml.Type propType = property.getType();
// property type is an enumeration
if(propType instanceof org.eclipse.uml2.uml.Enumeration) {
return getPropertyValueForEnumerationType(property, stereotype, umlElement, EQUAL_SEPARATOR, separator);
}
// property type is a metaclass
else if((propType instanceof org.eclipse.uml2.uml.Class) && (propType.getAppliedStereotypes() != null) && (propType.getAppliedStereotypes().size() > 0) && ((org.eclipse.uml2.uml.Stereotype)propType.getAppliedStereotypes().get(0)).getName().equals("Metaclass")) {
return getPropertyValueForMetaclassType(property, stereotype, umlElement, EQUAL_SEPARATOR, separator,true);
}
// property type is a stereotype
else if(propType instanceof org.eclipse.uml2.uml.Stereotype) {
return getPropertyValueForStereotypeType(property, stereotype, umlElement, EQUAL_SEPARATOR, separator,true);
}
// property is a composite class
else if((propType instanceof org.eclipse.uml2.uml.Class) && !(propType instanceof org.eclipse.uml2.uml.Stereotype) && property.isComposite()) {
return /* FIXME stProp + */property.getName() + EQUAL_SEPARATOR + property.getName() + separator;
}
// otherwise
else {
return getPropertyValue(property, stereotype, umlElement, EQUAL_SEPARATOR, separator, true);
}
}
/**
* Retrieves a property of the specified stereotype, given its name
*
* @param stereotype
* the stereotype owner of the property
* @param propertyName
* the name of the property to find
*/
public static Property getPropertyByName(Stereotype stereotype, String propertyName) {
Iterator<Property> iterPro = stereotype.getAllAttributes().iterator();
// from a string look for the property
while(iterPro.hasNext()) {
org.eclipse.uml2.uml.Property tmpProperty = iterPro.next();
String name = "";
if(tmpProperty != null) {
name = (tmpProperty.getName() != null) ? tmpProperty.getName() : "";
}
if(name.equals(propertyName)) {
return tmpProperty;
}
}
return null;
}
/**
* return string that contains value of properties of applied stereotype
*
* @param stereotypesPropertiesToDisplay
* list of properties of stereotype to display grammar=
* {<B>stereotypequalifiedName</B>'.'<B>propertyName</B>','}*
*
* @return a string with the following grammar grammar=
* {(<B>propertyName</B>'='<B>propertyValue</B>',')*
* <B>propertyName</B>'='<B>propertyValue</B>'}
*/
public static String getPropertiesValuesInBrace(String stereotypesPropertiesToDisplay, Element umlElement) {
String propertyValues = "";
HashSet<org.eclipse.uml2.uml.Stereotype> stereoSet = new HashSet<org.eclipse.uml2.uml.Stereotype>();
ArrayList<String> stPropList = new ArrayList<String>();
// fill our data structure in order to generate the string
StringTokenizer propStringTokenizer = new StringTokenizer(stereotypesPropertiesToDisplay, ",");
while(propStringTokenizer.hasMoreElements()) {
// extract property to display
String propertyQN = propStringTokenizer.nextToken();
// stereotype
String stereotypeQN = propertyQN.substring(0, propertyQN.indexOf("."));
Stereotype stereotype = umlElement.getAppliedStereotype(stereotypeQN);
if(stereotype != null) {
stereoSet.add(stereotype);
}
stPropList.add(propertyQN);
}
// Display each stereotype
Iterator<org.eclipse.uml2.uml.Stereotype> stereoIter = stereoSet.iterator();
while(stereoIter.hasNext()) {
Stereotype stereotype = stereoIter.next();
if(stereotype != null) {
propertyValues += displayPropertyValuesForStereotype(stereotype, stPropList, umlElement);
}
}
return propertyValues;
}
public static String displayPropertyValuesForStereotype(Stereotype stereotype, List<String> stPropList, Element umlElement) {
StringBuffer buffer = new StringBuffer();
// add stereotype name. For "In Brace", display nothing
buffer.append("");
// get the set of property to display
Iterator<String> stPropIter = getStereoPropertiesToDisplay(stereotype, stPropList).iterator();
// display each property
while(stPropIter.hasNext()) {
String stProp = stPropIter.next();
// get the property
org.eclipse.uml2.uml.Property currentProp = null;
Iterator<Property> iterPro = stereotype.getAllAttributes().iterator();
// from a string look for the property
while(iterPro.hasNext()) {
org.eclipse.uml2.uml.Property tmpProperty = iterPro.next();
if(stProp.equals(tmpProperty.getName())) {
currentProp = tmpProperty;
}
}
if(currentProp == null) {
return "No value";
}
org.eclipse.uml2.uml.Type propType = currentProp.getType();
// property type is an enumeration
if(propType instanceof org.eclipse.uml2.uml.Enumeration) {
buffer.append(getPropertyValueForEnumerationType(currentProp, stereotype, umlElement, EQUAL_SEPARATOR, ","));
}
// property type is a metaclass
else if((propType instanceof org.eclipse.uml2.uml.Class) && (propType.getAppliedStereotypes() != null) && (propType.getAppliedStereotypes().size() > 0) && ((org.eclipse.uml2.uml.Stereotype)propType.getAppliedStereotypes().get(0)).getName().equals("Metaclass")) {
buffer.append(getPropertyValueForMetaclassType(currentProp, stereotype, umlElement, EQUAL_SEPARATOR, ",",false));
}
// property type is a stereotype
else if(propType instanceof org.eclipse.uml2.uml.Stereotype) {
buffer.append(getPropertyValueForStereotypeType(currentProp, stereotype, umlElement, EQUAL_SEPARATOR, ",",false));
}
// property is a composite class
else if((propType instanceof org.eclipse.uml2.uml.Class) && !(propType instanceof org.eclipse.uml2.uml.Stereotype) && currentProp.isComposite()) {
buffer.append(stProp + EQUAL_SEPARATOR + currentProp.getName() + ",");
}
// otherwise
else {
buffer.append(getPropertyValue(currentProp, stereotype, umlElement, EQUAL_SEPARATOR, ",",false));
}
}// display each property
String propValues = buffer.toString();
if(propValues.endsWith(",")) {
propValues = propValues.substring(0, propValues.lastIndexOf(","));
}
return propValues;
}
/**
* return the string that represents the value of property when its type is an Enumeration
*
* @param property
* the property to display
* @param stereotype
* the stereotype that contains the property
* @param umlElement
* the umlelement on which the stereotype is applied
* @param EQUAL_SEPARATOR
* the separator between property and property value
* @param PROPERTY_VALUE_SEPARATOR
* the separator to end the exprestion
* @return String withe the following grammar propertyname EQUAL_SEPERATOR propertyValue
* PROPERTY_VALUE_SEPERATOR
*/
private static String getPropertyValueForEnumerationType(Property property, Stereotype stereotype, Element umlElement, final String EQUAL_SEPARATOR, final String PROPERTY_VALUE_SEPARATOR) {
String out = "";
if((property.getUpper() == 1) && (umlElement.getValue(stereotype, property.getName()) != null)) {
if((property.getLower() != 0) || umlElement.getValue(stereotype, property.getName()) != null) {
if(property.isSetDefault() || umlElement.getValue(stereotype, property.getName()) != null) {
Object val = umlElement.getValue(stereotype, property.getName());
if (val instanceof EnumerationLiteral)
out = property.getName() + EQUAL_SEPARATOR + ((EnumerationLiteral)val).getLabel() + PROPERTY_VALUE_SEPARATOR;
else
out = property.getName() + EQUAL_SEPARATOR + val + PROPERTY_VALUE_SEPARATOR;
} else {
out = property.getName() + PROPERTY_VALUE_SEPARATOR;
}
} else {
out = property.getName() + PROPERTY_VALUE_SEPARATOR;
}
}
// multiplicity is greater than one
else {
out = property.getName() + EQUAL_SEPARATOR + umlElement.getValue(stereotype, property.getName()) + PROPERTY_VALUE_SEPARATOR;
}
return out;
}
/**
* return the string that represents the value of property when its type is a Metaclass
*
* @param property
* the property to display
* @param stereotype
* the stereotype that contains the property
* @param umlElement
* the umlelement on which the stereotype is applied
* @param EQUAL_SEPARATOR
* the separator between property and property value
* @param PROPERTY_VALUE_SEPARATOR
* the separator to end the exprestion
* @return String withe the following grammar propertyname EQUAL_SEPERATOR propertyValue
* PROPERTY_VALUE_SEPERATOR
*/
private static String getPropertyValueForMetaclassType(Property property, Stereotype stereotype, Element umlElement, final String EQUAL_SEPARATOR, final String PROPERTY_VALUE_SEPARATOR, boolean withQualifiedName) {
String out = "";
if((property.getUpper() == 1) && (umlElement.getValue(stereotype, property.getName()) != null) && (umlElement.getValue(stereotype, property.getName()) instanceof NamedElement)) {
if(withQualifiedName){
out = property.getName() + EQUAL_SEPARATOR + ((NamedElement)(umlElement.getValue(stereotype, property.getName()))).getQualifiedName() + PROPERTY_VALUE_SEPARATOR;
}
else{
out = property.getName() + EQUAL_SEPARATOR + ((NamedElement)(umlElement.getValue(stereotype, property.getName()))).getName() + PROPERTY_VALUE_SEPARATOR;
}
}
// multiplicity greater than one
else if(property.getUpper() != 1) {
List values = (List)umlElement.getValue(stereotype, property.getName());
ArrayList elementNames = new ArrayList();
if(values != null) {
for(int count = 0; count < values.size(); count++) {
if(values.get(count) instanceof NamedElement) {
if(withQualifiedName){
elementNames.add(((NamedElement)values.get(count)).getQualifiedName());
}
else{
elementNames.add(((NamedElement)values.get(count)).getName());
}
}
}
}
out = property.getName() + EQUAL_SEPARATOR + elementNames + PROPERTY_VALUE_SEPARATOR;
}
// multiplicity = 1 and property value null
else {
out = property.getName() + EQUAL_SEPARATOR + umlElement.getValue(stereotype, property.getName()) + PROPERTY_VALUE_SEPARATOR;
}
return out;
}
/**
* return the string that represents the value of property when its type is a stereotype
*
* @param property
* the property to display
* @param stereotype
* the stereotype that contains the property
* @param umlElement
* the umlelement on which the stereotype is applied
* @param EQUAL_SEPARATOR
* the separator between property and property value
* @param PROPERTY_VALUE_SEPARATOR
* the separator to end the exprestion
* @return String withe the following grammar propertyname EQUAL_SEPERATOR propertyValue
* PROPERTY_VALUE_SEPERATOR
*/
private static String getPropertyValueForStereotypeType(Property property, Stereotype stereotype, Element umlElement, final String EQUAL_SEPARATOR, final String PROPERTY_VALUE_SEPARATOR, boolean withQualifiedName) {
String out = "";
if((property.getUpper() == 1) && (umlElement.getValue(stereotype, property.getName()) != null)) {
// retrieve the base element from the stereotype application
Object value = umlElement.getValue(stereotype, property.getName());
Element baseElement = UMLUtil.getBaseElement((EObject)value);
// display the base element's qualified name
if(withQualifiedName){
out = property.getName() + EQUAL_SEPARATOR + ((NamedElement)baseElement).getQualifiedName() + PROPERTY_VALUE_SEPARATOR;
}
else{
out = property.getName() + EQUAL_SEPARATOR + ((NamedElement)baseElement).getName() + PROPERTY_VALUE_SEPARATOR;
}
}
// multiplicity greater than one
else if(property.getUpper() != 1) {
// retrieve the base element from the stereotype application
List values = (List)umlElement.getValue(stereotype, property.getName());
ArrayList baseElements = new ArrayList();
if(values != null) {
for(int k = 0; k < values.size(); k++) {
if(withQualifiedName){
baseElements.add(((NamedElement)UMLUtil.getBaseElement((EObject)values.get(k))).getQualifiedName());
}
else{
baseElements.add(((NamedElement)UMLUtil.getBaseElement((EObject)values.get(k))).getName());
}
}
}
out = property.getName() + EQUAL_SEPARATOR + baseElements + PROPERTY_VALUE_SEPARATOR;
}
// multiplicity = 1 and property value null
else {
out = property.getName() + EQUAL_SEPARATOR + (umlElement.getValue(stereotype, property.getName())) + PROPERTY_VALUE_SEPARATOR;
}
return out;
}
/**
* return the string that represents the value of property
*
* @param property
* the property to display
* @param stereotype
* the stereotype that contains the property
* @param umlElement
* the umlelement on which the stereotype is applied
* @param EQUAL_SEPARATOR
* the separator between property and property value
* @param PROPERTY_VALUE_SEPARATOR
* the separator to end the exprestion
* @return String withe the following grammar propertyname EQUAL_SEPERATOR propertyValue
* PROPERTY_VALUE_SEPERATOR
*/
private static String getPropertyValue(Property property, Stereotype stereotype, Element umlElement, final String EQUAL_SEPARATOR, final String PROPERTY_VALUE_SEPARATOR,boolean withDelimitator) {
String out = "";
if((property.getLower() != 0) || umlElement.getValue(stereotype, property.getName()) != null) {
if(property.isSetDefault() || umlElement.getValue(stereotype, property.getName()) != null) {
if(withDelimitator){
String value= ""+umlElement.getValue(stereotype, property.getName());
out = property.getName() + EQUAL_SEPARATOR + value + PROPERTY_VALUE_SEPARATOR;
if(value.contains("[")){
out= out.replace("[", "["+QUOTE);
out= out.replace("]", QUOTE+"]");
out= out.replace(", ", QUOTE+","+QUOTE);
}
else{
out = property.getName() + EQUAL_SEPARATOR +QUOTE +value+QUOTE + PROPERTY_VALUE_SEPARATOR;
}
}
else{
out = property.getName() + EQUAL_SEPARATOR + umlElement.getValue(stereotype, property.getName()) + PROPERTY_VALUE_SEPARATOR;}
} else {
out = property.getName() + PROPERTY_VALUE_SEPARATOR;
}
} else {
out = property.getName() + PROPERTY_VALUE_SEPARATOR;
}
return out;
}
/**
* Parse the stereotype image and select those that have an "shape" kind (EAnnotation).
*
* @param stereotype
* to parse
*
* @return a EList of {@link Image}
*/
public static EList<Image> getShapes(Stereotype stereotype) {
EList<Image> shapes = new BasicEList<Image>();
Iterator<Image> it = stereotype.getIcons().iterator();
while(it.hasNext()) {
Image image = it.next();
if("shape".equals(ImageUtil.getKind(image))) {
shapes.add(image);
}
}
return shapes;
}
}