blob: ad1867d22b6154b1d8dced6e42fb8e0129492334 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006 - 2013 CEA LIST.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* CEA LIST - initial API and implementation
*******************************************************************************/
package org.eclipse.papyrus.designer.languages.common.base;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.UniqueEList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.papyrus.designer.languages.common.profile.Codegen.Project;
import org.eclipse.papyrus.uml.tools.utils.PackageUtil;
import org.eclipse.uml2.uml.AggregationKind;
import org.eclipse.uml2.uml.Behavior;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Comment;
import org.eclipse.uml2.uml.Dependency;
import org.eclipse.uml2.uml.DirectedRelationship;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Namespace;
import org.eclipse.uml2.uml.OpaqueBehavior;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Parameter;
import org.eclipse.uml2.uml.ParameterDirectionKind;
import org.eclipse.uml2.uml.ParameterableElement;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.TemplateBinding;
import org.eclipse.uml2.uml.TemplateParameter;
import org.eclipse.uml2.uml.TemplateParameterSubstitution;
import org.eclipse.uml2.uml.TemplateSignature;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.TypedElement;
import org.eclipse.uml2.uml.util.UMLUtil;
/**
* Some utilities: a set of static methods for code generation
*/
public class GenUtils {
public static final String NL = System.getProperties().getProperty("line.separator"); //$NON-NLS-1$
/**
* Enumeration to filter the inclusion of the types of abstract operations
*/
public enum IncludeAbstract {
ONLY_ABSTRACT, ONLY_NON_ABSTRACT, ALL_OPERATIONS
}
/**
* Returns the required types, if a property uses the TemplateBinding stereotype or
* its type is a bound template type
* In any case, it will add the type of the passed element itself
*
* @param propertyOrParameter
* a typed element, typically a property or parameter
* @return the required types
*/
public static List<Type> getTemplateRequiredTypes(TypedElement propertyOrParameter) {
List<Type> requiredTypes = getTemplateRequiredTypes(propertyOrParameter.getType());
org.eclipse.papyrus.designer.languages.common.profile.Codegen.TemplateBinding binding = UMLUtil.getStereotypeApplication(propertyOrParameter, org.eclipse.papyrus.designer.languages.common.profile.Codegen.TemplateBinding.class);
if (binding != null) {
requiredTypes.addAll(binding.getActuals());
}
return requiredTypes;
}
/**
* Returns the required types of a specialization class of a template class
*/
public static List<Type> getTemplateRequiredTypes(Type type) {
List<Type> types = new ArrayList<Type>();
if (type instanceof Classifier && !((Classifier) type).getTemplateBindings().isEmpty()) { // TODO template stereotype
TemplateBinding templateBinding = ((Classifier) type).getTemplateBindings().get(0);
TemplateSignature signature = templateBinding.getSignature();
if (signature != null && signature.getTemplate() instanceof Classifier) {
types.add((Classifier) signature.getTemplate());
List<TemplateParameter> templateParameters = signature.getOwnedParameters();
Map<TemplateParameter, NamedElement> parameterToClassMap = new HashMap<TemplateParameter, NamedElement>();
List<TemplateParameterSubstitution> substitutions = templateBinding.getParameterSubstitutions();
for (TemplateParameterSubstitution substitution : substitutions) {
if (substitution.getFormal() != null
&& templateParameters.contains(substitution.getFormal())
&& substitution.getActual() instanceof NamedElement) {
parameterToClassMap.put(substitution.getFormal(), (NamedElement) substitution.getActual());
}
}
if (parameterToClassMap.size() == templateParameters.size()) {
for (TemplateParameter templateParameter : templateParameters) {
NamedElement substitutionType = parameterToClassMap.get(templateParameter);
if (substitutionType instanceof Type) {
types.add((Type) substitutionType);
}
}
}
}
return types;
}
types.add(type);
return types;
}
/**
* Retrieve first template binding from list of template bindings, if
* exactly one exists. Return null otherwise.
*
* @param current
* Class on which the template binding is searched
* @return the template binding of current Class
*/
public static TemplateBinding getTemplateBinding(Classifier current) {
TemplateBinding binding = null;
if (current.getTemplateBindings().size() == 1) {
binding = current.getTemplateBindings().get(0);
}
return binding;
}
/**
* Check whether the passed classifier has a template binding with itself as bound element
*
* @param cl
* a classifier
* @return true, if the passed classifier is has template bindings
*/
public static boolean isTemplateBoundElement(Classifier cl) {
boolean result = false;
EList<TemplateBinding> tbs = cl.getTemplateBindings();
if (tbs.size() > 0) {
for (TemplateBinding tb : tbs) {
// TODO: will only work for single element in template binding list
result = tb.getBoundElement() == cl;
}
}
return result;
}
/**
* Get the name of a template parameter or undefined, if it is not set
*
* @param templateParam
* a template parameter
* @return the name of the parametered element, if defined
*/
public static String getTemplateName(TemplateParameter templateParam) {
String name = ""; //$NON-NLS-1$
ParameterableElement pElt = templateParam.getParameteredElement();
if ((pElt != null) && (pElt instanceof NamedElement)) {
name = ((NamedElement) pElt).getName();
} else {
name = "undefined"; //$NON-NLS-1$
}
return name;
}
/**
*
* @param classifier
* a classifier owning a template signature
* @return the list of (formal) parameters defined within a template signature
*/
public static Collection<TemplateParameter> getTemplateParameters(Classifier classifier) {
Collection<TemplateParameter> params = new ArrayList<TemplateParameter>();
TemplateSignature ts = classifier.getOwnedTemplateSignature();
if (ts != null) {
params.addAll(ts.getOwnedParameters());
}
return params;
}
/**
* @param classifier
* a classifier
* @return a collection of parameterable elements that are owned by the template signature of
* this classifier (empty collection, if the classifier does not have a signature)
*/
public static Collection<ParameterableElement> getTemplateParameteredElements(Classifier classifier) {
Collection<ParameterableElement> params = new ArrayList<ParameterableElement>();
TemplateSignature ts = classifier.getOwnedTemplateSignature();
if (ts != null) {
for (TemplateParameter tp : ts.getOwnedParameters()) {
if (tp != null) {
params.add(tp.getParameteredElement());
}
}
}
return params;
}
/**
* Retrieve a list of types of attributes that belong to the current classifier.
*
* @param current
* Class on which the attributes are searched
* @return Collection of classifiers which are the types of the attributes
*/
public static EList<Classifier> getTypesViaAttributes(Classifier current) {
EList<Classifier> result = new UniqueEList<Classifier>();
for (Property currentAttribute : current.getAttributes()) {
List<Type> requiredTypes = getTemplateRequiredTypes(currentAttribute);
for (Type requiredType : requiredTypes) {
addFarthestOwnerType(requiredType, result);
}
}
return result;
}
/**
* Retrieve a list of types of attributes that belong to the current classifier. Filter by stereotypes.
*
* @param current
* Class on which the attributes are searched
* @param excludedStereotypes
* List of ALL stereotypes that must no be applied
* @param includedStereotypes
* List of ANY stereotype that must no be applied (at least one)
* @param bypassForInnerClassifiers
* Always include inner classifier types or not
* @param noSharedAggregation
* Always exclude attributes with a shared aggregation kind
* @return Collection of classifiers which are the types of the attributes
*/
public static EList<Classifier> getTypesViaAttributes(Classifier current, EList<Class<? extends EObject>> excludedStereotypes, EList<Class<? extends EObject>> includedStereotypes, boolean bypassForInnerClassifiers, boolean noSharedAggregation) {
EList<Classifier> result = new UniqueEList<Classifier>();
for (Property currentAttribute : current.getAttributes()) {
Type type = currentAttribute.getType();
if (type != null) {
// Check type is inner classifier
if (bypassForInnerClassifiers && !(type.getOwner() instanceof Package)) { // if we force inner class types to be processed
addFarthestOwnerType(type, result);
} else {
// Check other conditions
boolean ok = true;
// Check attribute is shared aggregation
if (noSharedAggregation && currentAttribute.getAggregation() == AggregationKind.SHARED_LITERAL) {
ok = false;
}
// Check attribute does not have an excluded stereotype
if (ok) {
if (excludedStereotypes != null && GenUtils.hasAnyStereotype(currentAttribute, excludedStereotypes)) {
ok = false;
}
}
// Check attribute has an included stereotype
if (ok) {
if (includedStereotypes != null && !GenUtils.hasAnyStereotype(currentAttribute, includedStereotypes)) {
ok = false;
}
}
// All ok
if (ok) {
addFarthestOwnerType(type, result);
}
}
}
}
return result;
}
/**
* Retrieve a list of types of attributes, with SHARED aggregation, that belong to the current classifier.
*
* @param current
* Class on which the attributes are searched
* @return Collection of classifiers which are the types of the attributes
*/
public static EList<Classifier> getTypesViaSharedAggregationAttributes(Classifier current) {
EList<Classifier> result = new UniqueEList<Classifier>();
Iterator<Property> attributes;
attributes = current.getAttributes().iterator();
while (attributes.hasNext()) {
Property currentAttribute = attributes.next();
Type type = currentAttribute.getType();
if (type != null) {
if (currentAttribute.getAggregation() == AggregationKind.SHARED_LITERAL) {
addFarthestOwnerType(type, result);
}
}
}
return result;
}
/**
* Retrieve the operations in the current classifier. For each
* operation, collect types of its parameters.
* This method thus finds types, on
* which the signature depends.
*
* @param current
* Classifier on which the operations are searched for
* @return Collection of classifiers which are the types of the operation parameters
*/
public static EList<Classifier> getTypesViaOperations(Classifier current) {
return getTypesViaOperations(current, IncludeAbstract.ALL_OPERATIONS);
}
/**
* Get a list of types that are referenced via an operation
*
* @param current
* Classifier on which the operations are searched for
* @param abstractFilter
* Include only operations depending on its abstract status
* @return
*/
public static EList<Classifier> getTypesViaOperations(Classifier current, IncludeAbstract abstractFilter) {
EList<Classifier> result = new UniqueEList<Classifier>();
for (Operation operation : current.getOperations()) {
if (filterAbstract(operation.isAbstract(), abstractFilter)) {
for (Parameter param : operation.getOwnedParameters()) {
List<Type> requiredTypes = getTemplateRequiredTypes(param);
for (Type requiredType : requiredTypes) {
addFarthestOwnerType(requiredType, result);
}
}
for (Type type : operation.getRaisedExceptions()) {
List<Type> requiredTypes = getTemplateRequiredTypes(type);
for (Type requiredType : requiredTypes) {
addFarthestOwnerType(requiredType, result);
}
}
}
}
return result;
}
/**
* Retrieve the operations in the current classifier. For each
* operation, collect types of its parameters.
* This method thus finds types, on which the signature depends.
* We check if operations and parameters must have or not have some stereotypes.
*
* @param current
* Classifier on which the operations are searched for
* @param excludedOperationStereotypes
* List of ALL stereotypes that must not be applied to an operation
* @param includedOperationStereotypes
* List of ANY stereotype that must be applied to an operation (at least one)
* @param excludedParameterStereotypes
* List of ALL stereotypes that must not be applied to a parameter
* @param includedParameterStereotypes
* List of ANY stereotype that must be applied to a parameter (at least one)
* @param bypassForInnerClassifiers
* Always include types that are inner classifiers
* @return Collection of classifiers which are the types of the operation parameters
*/
public static EList<Classifier> getTypesViaOperations(Classifier current,
EList<Class<? extends EObject>> excludedOperationStereotypes,
EList<Class<? extends EObject>> includedOperationStereotypes,
EList<Class<? extends EObject>> excludedParameterStereotypes,
EList<Class<? extends EObject>> includedParameterStereotypes,
boolean bypassForInnerClassifiers) {
EList<Classifier> result = new UniqueEList<Classifier>();
for (Operation operation : current.getOperations()) {
boolean ok = true;
if (excludedOperationStereotypes != null && GenUtils.hasAnyStereotype(operation, excludedOperationStereotypes)) {
ok = false;
}
if (includedOperationStereotypes != null && !GenUtils.hasAnyStereotype(operation, includedOperationStereotypes)) {
ok = false;
}
boolean operationOk = ok;
if (operationOk || bypassForInnerClassifiers) {
for (Parameter param : operation.getOwnedParameters()) {
Type type = param.getType();
if (type != null) {
if (bypassForInnerClassifiers && !(type.getOwner() instanceof Package)) { // if we force inner class types to be processed
addFarthestOwnerType(type, result);
} else if (operationOk) {
ok = true;
if (excludedParameterStereotypes != null && GenUtils.hasAnyStereotype(param, excludedParameterStereotypes)) {
ok = false;
}
if (includedParameterStereotypes != null && !GenUtils.hasAnyStereotype(param, includedParameterStereotypes)) {
ok = false;
}
if (ok) {
addFarthestOwnerType(type, result);
}
}
}
}
}
}
return result;
}
/**
* Retrieve the opaque behaviors in the current classifier, without specification.
* For each opaque behavior, collect types of its parameters.
* This method thus finds types, on
* which the signature depends.
*
* @param current
* Classifier on which the opaque behaviors are searched for
* @return Collection of classifiers which are the types of the opaque behavior parameters
*/
public static EList<Classifier> getTypesViaOpaqueBehaviors(Classifier current) {
EList<Classifier> result = new UniqueEList<Classifier>();
for (Element element : current.getOwnedElements()) {
if (element instanceof OpaqueBehavior) {
OpaqueBehavior opaqueBehavior = (OpaqueBehavior) element;
if (opaqueBehavior.getSpecification() == null) {
for (Parameter param : opaqueBehavior.getOwnedParameters()) {
Type type = param.getType();
addFarthestOwnerType(type, result);
}
}
}
}
return result;
}
/**
* Retrieve the opaque behaviors in the current classifier, without specification.
* For each opaque behavior, collect types of its parameters.
* This method thus finds types, on
* which the signature depends.
* We check if opaque behavior and parameters must have or not have some stereotypes.
*
* @param current
* Classifier on which the opaque behaviors are searched for
* @param excludedOperationStereotypes
* List of ALL stereotypes that must not be applied to an opaque behavior
* @param includedOperationStereotypes
* List of ANY stereotype that must be applied to an opaque behavior (at least one)
* @param excludedParameterStereotypes
* List of ALL stereotypes that must not be applied to a parameter
* @param includedParameterStereotypes
* List of ANY stereotype that must be applied to a parameter (at least one)
* @param bypassForInnerClassifiers
* Always include types that are inner classifiers
* @return Collection of classifiers which are the types of the opaque behavior parameters
*/
public static EList<Classifier> getTypesViaOpaqueBehaviors(Classifier current,
EList<Class<? extends EObject>> excludedOperationStereotypes,
EList<Class<? extends EObject>> includedOperationStereotypes,
EList<Class<? extends EObject>> excludedParameterStereotypes,
EList<Class<? extends EObject>> includedParameterStereotypes,
boolean bypassForInnerClassifiers) {
EList<Classifier> result = new UniqueEList<Classifier>();
for (Element element : current.getOwnedElements()) {
if (element instanceof OpaqueBehavior) {
OpaqueBehavior opaqueBehavior = (OpaqueBehavior) element;
if (opaqueBehavior.getSpecification() == null) {
boolean ok = true;
if (excludedOperationStereotypes != null && GenUtils.hasAnyStereotype(opaqueBehavior, excludedOperationStereotypes)) {
ok = false;
}
if (includedOperationStereotypes != null && !GenUtils.hasAnyStereotype(opaqueBehavior, includedOperationStereotypes)) {
ok = false;
}
if (ok) {
for (Parameter param : opaqueBehavior.getOwnedParameters()) {
Type type = param.getType();
if (type != null) {
if (bypassForInnerClassifiers && !(type.getOwner() instanceof Package)) { // if we force inner class types to be processed
addFarthestOwnerType(type, result);
} else {
ok = true;
if (excludedParameterStereotypes != null && GenUtils.hasAnyStereotype(param, excludedParameterStereotypes)) {
ok = false;
}
if (includedParameterStereotypes != null && !GenUtils.hasAnyStereotype(param, includedParameterStereotypes)) {
ok = false;
}
if (ok) {
addFarthestOwnerType(type, result);
}
}
}
}
}
}
}
}
return result;
}
/**
* Retrieves a list of types of attributes of inner classifiers of the current classifier
*
* @param current
* Class on which the attributes are searched
* @return collection of classes which are the types of the operations parameters
*/
public static EList<Classifier> getInnerClassifierTypes(Classifier current) {
EList<Classifier> result = new UniqueEList<Classifier>();
result.addAll(getInnerClassifierTypesViaAttributes(current));
result.addAll(getInnerClassifierTypesViaOperations(current));
return result;
}
/**
* Retrieve a list of types of attributes of inner classifiers that belong to the current classifier.
*
* @param current
* Class on which the attributes are searched
* @return Collection of classifiers which are the type of the attributes of inner classifiers
*/
public static EList<Classifier> getInnerClassifierTypesViaAttributes(Classifier current) {
EList<Classifier> result = new UniqueEList<Classifier>();
for (Element ownedElement : current.allOwnedElements()) {
if (ownedElement instanceof Classifier) {
result.addAll(getTypesViaAttributes((Classifier) ownedElement));
}
}
return result;
}
/**
* Retrieve a list of types of attributes of inner classifiers that belong to the current classifier. Filter by stereotypes.
*
* @param current
* Class on which the attributes are searched
* @param excludedStereotypes
* List of ALL stereotypes that must no be applied
* @param includedStereotypes
* List of ANY stereotype that must no be applied (at least one)
* @param bypassForInnerClassifiers
* Always include types that are inner classifiers
* @param noSharedAggregation
* Always exclude attributes with a shared aggregation kind
* @return Collection of classifiers which are the types of the attributes of inner classifiers
*/
public static EList<Classifier> getInnerClassifierTypesViaAttributes(Classifier current, EList<Class<? extends EObject>> excludedStereotypes, EList<Class<? extends EObject>> includedStereotypes, boolean bypassForInnerClassifiers,
boolean noSharedAggregation) {
EList<Classifier> result = new UniqueEList<Classifier>();
for (Element ownedElement : current.allOwnedElements()) {
if (ownedElement instanceof Classifier) {
result.addAll(getTypesViaAttributes((Classifier) ownedElement, excludedStereotypes, includedStereotypes, bypassForInnerClassifiers, noSharedAggregation));
}
}
return result;
}
/**
* Retrieve a list of types of attributes, of shared aggregation, of inner classifiers that belong to the current classifier.
*
* @param current
* Class on which the attributes are searched
* @return Collection of classifiers which are the types of the attributes of inner classifiers
*/
public static EList<Classifier> getInnerClassifierTypesViaSharedAggregationAttributes(Classifier current) {
EList<Classifier> result = new UniqueEList<Classifier>();
for (Element ownedElement : current.allOwnedElements()) {
if (ownedElement instanceof Classifier) {
result.addAll(getTypesViaSharedAggregationAttributes((Classifier) ownedElement));
}
}
return result;
}
/**
* Retrieve the operations of inner classifiers of the current classifier. For each
* operation, collect types of its parameters.
* This method thus finds types, on
* which the signature depends.
*
* @param current
* Classifier on which the operations are searched for
* @return Collection of classifiers which are the types of the parameters of inner classifiers
*/
public static EList<Classifier> getInnerClassifierTypesViaOperations(Classifier current) {
EList<Classifier> result = new UniqueEList<Classifier>();
for (Element ownedElement : current.allOwnedElements()) {
if (ownedElement instanceof Classifier) {
result.addAll(getTypesViaOperations((Classifier) ownedElement));
}
}
return result;
}
/**
* Retrieve the operations of inner classifiers of the current classifier. For each
* operation, collect types of its parameters.
* This method thus finds types, on
* which the signature depends.
* We check if operations and parameters must have or not have some stereotypes.
*
* @param current
* Classifier on which the operations are searched for
* @param excludedOperationStereotypes
* List of ALL stereotypes that must not be applied to an operation
* @param includedOperationStereotypes
* List of ANY stereotype that must be applied to an operation (at least one)
* @param excludedParameterStereotypes
* List of ALL stereotypes that must not be applied to a parameter
* @param includedParameterStereotypes
* List of ANY stereotype that must be applied to a parameter (at least one)
* @return Collection of classifiers which are the types of the parameters of inner classifiers
*/
public static EList<Classifier> getInnerClassifierTypesViaOperations(Classifier current,
EList<Class<? extends EObject>> excludedOperationStereotypes,
EList<Class<? extends EObject>> includedOperationStereotypes,
EList<Class<? extends EObject>> excludedParameterStereotypes,
EList<Class<? extends EObject>> includedParameterStereotypes,
boolean bypassForInnerClassifiers) {
EList<Classifier> result = new UniqueEList<Classifier>();
for (Element ownedElement : current.allOwnedElements()) {
if (ownedElement instanceof Classifier) {
result.addAll(getTypesViaOperations((Classifier) ownedElement,
excludedOperationStereotypes,
includedOperationStereotypes,
excludedParameterStereotypes,
includedParameterStereotypes,
bypassForInnerClassifiers));
}
}
return result;
}
/**
* Retrieve the opaque behaviors of inner classifiers of the current classifier, without specification.
* For each opaque behavior, collect types of its parameters.
* This method thus finds types, on
* which the signature depends.
*
* @param current
* Classifier on which the opaque behaviors are searched for
* @return Collection of classifiers which are the types of the parameters of inner classifiers
*/
public static EList<Classifier> getInnerClassifierTypesViaOpaqueBehaviors(Classifier current) {
EList<Classifier> result = new UniqueEList<Classifier>();
for (Element ownedElement : current.allOwnedElements()) {
if (ownedElement instanceof Classifier) {
result.addAll(getTypesViaOpaqueBehaviors((Classifier) ownedElement));
}
}
return result;
}
/**
* Retrieve the opaque behaviors of inner classifiers of the current classifier, without specification.
* For each opaque behavior, collect types of its parameters.
* This method thus finds types, on
* which the signature depends.
* We check if opaque behavior and parameters must have or not have some stereotypes.
*
* @param current
* Classifier on which the opaque behaviors are searched for
* @param excludedOperationStereotypes
* List of ALL stereotypes that must not be applied to an opaque behavior
* @param includedOperationStereotypes
* List of ANY stereotype that must be applied to an opaque behavior (at least one)
* @param excludedParameterStereotypes
* List of ALL stereotypes that must not be applied to a parameter
* @param includedParameterStereotypes
* List of ANY stereotype that must be applied to a parameter (at least one)
* @return Collection of classifiers which are the types of the opaque behavior parameters of inner classifiers
*/
public static EList<Classifier> getInnerClassifierTypesViaOpaqueBehaviors(Classifier current,
EList<Class<? extends EObject>> excludedOperationStereotypes,
EList<Class<? extends EObject>> includedOperationStereotypes,
EList<Class<? extends EObject>> excludedParameterStereotypes,
EList<Class<? extends EObject>> includedParameterStereotypes,
boolean bypassForInnerClassifiers) {
EList<Classifier> result = new UniqueEList<Classifier>();
for (Element ownedElement : current.allOwnedElements()) {
if (ownedElement instanceof Classifier) {
result.addAll(getTypesViaOpaqueBehaviors((Classifier) ownedElement,
excludedOperationStereotypes,
includedOperationStereotypes,
excludedParameterStereotypes,
includedParameterStereotypes,
bypassForInnerClassifiers));
}
}
return result;
}
/**
* Return a list of classifiers that are referenced by relationships, i.e.
* dependencies or associations
*
* @param current
* a classifier
* @return a list of referenced classifiers
*/
public static EList<Classifier> getTypesViaRelationships(Classifier current) {
EList<Classifier> classifiers = new UniqueEList<Classifier>();
for (DirectedRelationship relationship : current.getSourceDirectedRelationships()) {
if (relationship.getTargets().size() > 0) {
// there should always be at least one element in the target
// list and it should be a classifier, but better check.
Element element = relationship.getTargets().get(0);
addFarthestOwnerType(element, classifiers);
}
}
return classifiers;
}
/**
* Return a list of classifiers that are referenced via dependencies
*
* @param current
* a classifier
* @return a list of referenced classifiers
*/
public static EList<Classifier> getTypesViaDependencies(Classifier current) {
EList<Classifier> classifiers = new UniqueEList<Classifier>();
for (DirectedRelationship relationship : current.getSourceDirectedRelationships()) {
if (relationship instanceof Dependency) {
if (relationship.getTargets().size() > 0) {
// there should always be at least one element in the target
// list and it should be a classifier, but better check.
Element element = relationship.getTargets().get(0);
addFarthestOwnerType(element, classifiers);
}
}
}
for (Element owned : current.getOwnedElements()) {
if (owned instanceof Classifier) {
classifiers.addAll(getTypesViaDependencies((Classifier) owned));
}
}
return classifiers;
}
/**
* Return a list of classifiers that are referenced via all kinds of relations except
* dependencies
*
* @param current
* a classifier
* @return a list of referenced classifiers
*/
public static EList<Classifier> getTypesViaRelationshipsNoDeps(Classifier current) {
EList<Classifier> classifiers = new UniqueEList<Classifier>();
for (DirectedRelationship relationship : current.getSourceDirectedRelationships()) {
if (!(relationship instanceof Dependency)) {
if (relationship.getTargets().size() > 0) {
// there should always be at least one element in the target
// list and it should be a classifier, but better check.
Element element = relationship.getTargets().get(0);
addFarthestOwnerType(element, classifiers);
}
}
}
for (Element owned : current.getOwnedElements()) {
if (owned instanceof Classifier) {
classifiers.addAll(getTypesViaRelationshipsNoDeps((Classifier) owned));
}
}
return classifiers;
}
/**
* Return the qualified name of a named element, but use "_" instead of "::" as separator
*
* @param ne
* a named element
* @return the fully qualified name with "_" as separator character
*/
public static String getFullName(NamedElement ne) {
return ne.getQualifiedName().replace("::", "_"); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Return the qualified name of a named element, but use separator instead of "::" as separator
*
* @param ne
* a named element
* @return the fully qualified name with separator character
*/
public static String getFullName(NamedElement ne, String separator) {
return ne.getQualifiedName().replace("::", separator); //$NON-NLS-1$
}
/**
* Return the qualified name of a named element, but use separator instead of "::" as separator, and check if project name should be considered
*
* @param ne
* a named element
* @return the fully qualified name with separator character, without the project name optionally
*/
public static String getFullName(NamedElement ne, String separator, boolean withProjectName) {
checkProxy(ne);
String qName = getFullName(ne, separator);
if (!withProjectName) {
return getQualifiedNameWithoutProject(ne, qName, separator);
}
return qName;
}
/**
* return the full name in upper case
*
* @param ne
* a named UML element
* @return full name in upper case
*/
public static String getFullNameUC(NamedElement ne) {
return ne.getQualifiedName().replace("::", "_").toUpperCase(); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Retrieve the comments associated with an element
* TODO: check whether comment's annotated element link belongs to element in question
*
* @param element
* a UML element
* @return the comment text (concatenation of comments)
*/
public static String getComments(Element element) {
String commentText = ""; //$NON-NLS-1$
for (Comment comment : element.getOwnedComments()) {
// remove eventual CRs
commentText += cleanCR(comment.getBody());
}
return commentText;
}
/**
* Return a list of dependent package (the list of dependent
* elements filtered for packages)
*
* @param pkg
* a UML package
* @return a list of packages to which this packages has a dependency
*/
public static EList<Package> getUsedPackages(Package pkg) {
EList<Package> result = new UniqueEList<Package>();
for (Element depElement : pkg.getClientDependencies()) {
if (depElement instanceof Package) {
result.add((Package) depElement);
}
}
return result;
}
/**
* Return a list of dependent classifiers (the list of dependent
* elements filtered for classifiers)
*
* @param cls
* a classifier
* @return the list of classifiers on which the passed classifier depends
*/
public static EList<Classifier> getUsedClassifiers(Classifier cls) {
EList<Classifier> result = new BasicEList<Classifier>();
for (Element depElement : cls.getClientDependencies()) {
addFarthestOwnerType(depElement, result);
}
return result;
}
/**
* Adds the first element owned by a package in a classifier's namespace
*
* @param element
* a UML element
* @result a list of classifiers (must be initialized by caller)
*/
public static void addFarthestOwnerType(Element element, EList<Classifier> result) {
if (element == null || result == null) {
return;
}
if ((element.getOwner() instanceof Package || element.getOwner() instanceof TemplateParameterSubstitution) && element instanceof Classifier) {
result.add((Classifier) element);
} else { // Type is an inner class. We want to return a classifier C directly owned by a package since it is "C.h" that should be included
addFarthestOwnerType(element.getOwner(), result);
}
}
/**
* Adds the first element that is a classifier
*
* @param element
* a UML element
* @param result
* a list of classifiers (must be initialized by caller)
*/
public static void addClosestOwnerType(Element element, EList<Classifier> result) {
if (element == null || result == null) {
return;
}
if (element instanceof Classifier) {
result.add((Classifier) element);
} else {
addClosestOwnerType(element.getOwner(), result);
}
}
/**
* Get the name-space of the farthest classifier owner that owns an operation
*
* @param op
* @return a string with the name-space path
*/
public static String getNestedOperationFarthestClassifierOwnerNamespace(Operation op) {
StringBuffer buffer = new StringBuffer(""); //$NON-NLS-1$
if (op != null && op.getOwner() instanceof Classifier) {
getFarthestOwnerNamespace(op.getOwner(), buffer);
}
return buffer.toString();
}
/**
* Get the name-space of the farthest classifier owner that owns an opaque behavior
*
* @param behavior
* @return a string with the name-space path
*/
public static String getNestedBehaviorFarthestClassifierOwnerNamespace(OpaqueBehavior behavior) {
StringBuffer buffer = new StringBuffer(""); //$NON-NLS-1$
if (behavior != null && behavior.getOwner() instanceof Classifier) {
getFarthestOwnerNamespace(behavior.getOwner(), buffer);
}
return buffer.toString();
}
/**
* Build a namespace to the farthest owner (i.e. owned by a package) of some element
*
* @param element
* @param result
*/
private static void getFarthestOwnerNamespace(Element element, StringBuffer result) {
if (element == null || result == null) {
return;
}
if (element.getOwner() instanceof Package) {
result.insert(0, ((Classifier) element).getName());
} else {
result.insert(0, "::" + ((Classifier) element).getName()); //$NON-NLS-1$
getFarthestOwnerNamespace(element.getOwner(), result);
}
}
/**
* Return the qualified name of a package, but use "/" instead of "::" as separator
*
* @param pkg
* @return the full path
*/
public static String getFullPath(Package pkg) {
return pkg.getQualifiedName().replace("::", "/"); //$NON-NLS-1$//$NON-NLS-2$
}
/**
* Return the qualified name of a package, but use passed separator instead of "::" as separator
*
* @param pkg
* @return the fully qualified name with separator character, without the project name optionally
*/
public static String getFullPath(Package pkg, String seperator) {
return pkg.getQualifiedName().replace("::", seperator); //$NON-NLS-1$
}
/**
* Return the qualified name of a package, but use separator instead of "::" as separator, and check if project name should be considered
*
* @param pkg
* @return the fully qualified name with separator character, without the project name optionally
*/
public static String getFullPath(Package pkg, String separator, boolean withProjectName) {
String qName = getFullPath(pkg, separator);
if (!withProjectName) {
return getQualifiedNameWithoutProject(pkg, qName, separator);
}
return qName;
}
private static String getQualifiedNameWithoutProject(NamedElement ne, String qName, String separator) {
org.eclipse.uml2.uml.Package root = PackageUtil.getRootPackage(ne);
if (qName != null && root != null && GenUtils.hasStereotype(root, Project.class)) {
if (qName.equals(root.getName())) {
return ""; //$NON-NLS-1$
}
if (qName.startsWith(root.getName())) {
return qName.replaceFirst(root.getName() + separator, ""); //$NON-NLS-1$
}
}
return qName;
}
/**
* Is a certain stereotype applied?
*
* @param element
* a UML element
* @param stereotName
* qualified name of stereotype
* fully qualified stereotype name
* @return true, if stereotype is applied
*/
public static boolean hasStereotype(Element element, String stereotName) {
return element.getAppliedStereotype(stereotName) != null;
}
/**
* Is a certain stereotype applied?
*
* @param element
* a UML element
* @param clazz
* The stereotype in form of a class (static profile)
* @return true, if stereotype is applied
*/
public static boolean hasStereotype(Element element, java.lang.Class<? extends EObject> clazz) {
for (EObject stereoApplication : element.getStereotypeApplications()) {
// check whether the stereotype is a super-class of the passed parameter clazz
if (clazz.isAssignableFrom(stereoApplication.getClass())) {
return true;
}
}
return false;
}
/**
* Is a any stereotype in a list applied?
*
* @param element
* a UML element
* @param stereotypes
* The list of stereotypes in form of classes (static profile)
* @return true, if one of the stereotypes is applied
*/
public static boolean hasAnyStereotype(Element element, EList<java.lang.Class<? extends EObject>> stereotypes) {
for (EObject stereoApplication : element.getStereotypeApplications()) {
// check whether the stereotype is a super-class of the passed parameter clazz
for (Class<? extends EObject> stereotype : stereotypes) {
if (stereotype.isAssignableFrom(stereoApplication.getClass())) {
return true;
}
}
}
return false;
}
/**
* Is a certain stereotype applied?
* In case of Java, we use the class above (without the A) prefix. In case of Acceleo, a stereotype
* such as C_Cpp::Include is passed as EClass and we therefore use this operation from Acceleo.
*
* @param element
* a UML element
* @param definition
* The eClass associated with the stereotype name (its definition)
* @return true, if stereotype is applied
*/
public static boolean hasStereotypeA(Element element, EClass definition) {
if (element == null) {
// make query more robust
return false;
}
for (EObject stereoApplication : element.getStereotypeApplications()) {
// check whether the stereotype application has the right eClass
if (stereoApplication.eClass() == definition) {
return true;
}
}
return false;
}
/**
* Verify if an Element or its parent Elements have a stereotype. Pass the class associated with a stereotype
*
* @param element
* a UML element
* @param clazz
* The stereotype in form of a class (static profile)
*
* @return true if found. false otherwise
*/
public static boolean hasStereotypeTree(Element element, java.lang.Class<? extends EObject> clazz) {
if (hasStereotype(element, clazz)) {
return true;
} else {
Element owner = element.getOwner();
if (owner != null) {
return hasStereotypeTree(owner, clazz);
} else {
return false;
}
}
}
/**
* Verify if an Element or its parent Elements have a stereotype. Pass the definition of the stereotype
*
* @param element
* a UML element
* @param definition
* The stereotype definition
* @return true if found. false otherwise
*/
public static boolean hasStereotypeTree(Element element, EClass definition) {
Element owner;
if (hasStereotypeA(element, definition)) {
return true;
} else if ((owner = element.getOwner()) != null) {
return hasStereotypeTree(owner, definition);
} else {
return false;
}
}
/**
* return the first occurrence of a stereotype application in the ownership tree
*
* @param element
* a UML element
* @param clazz
* The stereotype in form of a class (static profile)
* @return the stereotype application
*/
@SuppressWarnings("unchecked")
public static <T extends EObject> T getApplicationTree(Element element, java.lang.Class<T> clazz) {
EObject application = UMLUtil.getStereotypeApplication(element, clazz);
if (application != null) {
return (T) application;
} else {
Element owner = element.getOwner();
if (owner != null) {
return getApplicationTree(owner, clazz);
} else {
return null;
}
}
}
/**
* return the first occurrence of a stereotype application in the ownership tree
* Variant of @see getApplicationTree that is useful for Acceleo
*
* @param element
* a UML element
* @param definition
* the definition of a stereotype (its eClass)
* @return the stereotype application
*/
public static EObject getApplicationTreeA(Element element, EClass definition) {
EObject application = getApplicationA(element, definition);
if (application != null) {
return application;
} else {
Element owner = element.getOwner();
if (owner != null) {
return getApplicationTreeA(owner, definition);
} else {
return null;
}
}
}
/**
* Return a stereotype application when given the eClass of that application.
* In case of Java, we use the class above (without the A) prefix. In case of Acceleo, a stereotype
* such as C_Cpp::Include is passed as EClass and we therefore use this operation from Acceleo.
*
* @param element
* the UML model element
* @param eClass
* the eClass of the stereotype application
* @return the stereotype application
*/
public static EObject getApplicationA(Element element, EClass eClass) {
for (EObject stereoApplication : element.getStereotypeApplications()) {
// check whether the stereotype is an instance of the passed parameter clazz
if (stereoApplication.eClass() == eClass) {
return stereoApplication;
}
}
return null;
}
/**
* @param operation
* the operation
* @param selectedLanguages
* a pattern containing one or more languages
* @return Return the first body of a selected language that is provided by
* one of the operation's methods
*/
public static String getBody(Operation operation, Pattern selectedLanguages) {
for (Behavior behavior : operation.getMethods()) {
if (behavior instanceof OpaqueBehavior) {
return getBodyFromOB((OpaqueBehavior) behavior, selectedLanguages);
}
}
return ""; //$NON-NLS-1$
}
/**
* @param ob
* an opaque behavior
* @param selectedLanguages
* a pattern containing one or more languages
* @return Return the first body of a selected language that is provided by
* one of the operation's methods
*/
public static String getBodyFromOB(OpaqueBehavior ob, Pattern selectedLanguages) {
Iterator<String> bodies = ob.getBodies().iterator();
for (String language : ob.getLanguages()) {
// additional sanity check: number of languages and number of bodies should be synchronized,
// but there is no guarantee that this is the case
if (bodies.hasNext()) {
String body = bodies.next();
Matcher matcher = selectedLanguages.matcher(language);
if (matcher.matches()) {
// additional "\r" confuses Acceleo
return cleanCR(body);
}
}
}
return ""; //$NON-NLS-1$
}
/**
* Remove <CR> from a String. These confuse Acceleo's indentation
*
* @param str
* a string
* @return the passed string without carriage returns
*/
public static String cleanCR(String str) {
if (str == null) {
return "// <null>"; //$NON-NLS-1$
}
return str.replace("\r", ""); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Avoid null strings, i.e. replace null strings by empty strings
*
* @param str
* a string
* @return the string, if not null.
*/
public static String maskNull(String str) {
if (str == null) {
return ""; //$NON-NLS-1$
}
return str;
}
public static void checkProxy(EObject element) {
if (element.eIsProxy()) {
String msg = Messages.GenUtils_ElementIsProxy;
if (element instanceof InternalEObject) {
msg += " " + ((InternalEObject) element).eProxyURI(); //$NON-NLS-1$
}
throw new RuntimeException(msg);
}
}
/**
* Return the relative path of ne2 as seen from ne1
* (might not always be useful, if includes are always done from a common root)
* TODO: incomplete, currently unused
*
* @param ne1
* a named element
* @param ne2
* a named element
* @return the relative path
*/
public static String getRelativePath(NamedElement ne1, NamedElement ne2) {
// get common prefix
EList<Namespace> ne1namespaces = ne1.allNamespaces();
String path = ""; //$NON-NLS-1$
for (Namespace ns : ne2.allNamespaces()) {
if (ne1namespaces.contains(ns)) {
// ns is a common prefix
return ne2.getName();
}
path += "../"; //$NON-NLS-1$
}
return path;
}
/**
* Return the type of a behavior, i.e. the type of the first parameter with
* "return" direction
*
* @param behavior
* a behavior
* @return the associated type
*/
public static Parameter returnResult(Behavior behavior) {
for (Parameter parameter : behavior.getOwnedParameters()) {
if (parameter.getDirection() == ParameterDirectionKind.RETURN_LITERAL) {
return parameter;
}
}
return null;
}
/**
* @param element
* An element of the model
* @return the source folder from the Project stereotype, that is eventually applied to the
* model root.
*/
public static String getSourceFolder(Element element) {
Package rootPkg = element != null ? PackageUtil.getRootPackage(element) : null;
if (rootPkg != null) {
org.eclipse.papyrus.designer.languages.common.profile.Codegen.Project projectStereo = UMLUtil.getStereotypeApplication(rootPkg, org.eclipse.papyrus.designer.languages.common.profile.Codegen.Project.class);
if (projectStereo != null) {
return projectStereo.getSourceFolder() + "/"; //$NON-NLS-1$
}
}
// default folder for generated code
return "src-gen/"; //$NON-NLS-1$
}
/**
* Helper function that returns true, if a element should be
* included in a list depending on its abstract state.
*
* @param isAbstract
* whether an element is abstract
* @param ia
* filtering enumeration
* @return true, if element should be include
*/
private static boolean filterAbstract(boolean isAbstract, IncludeAbstract ia) {
if (ia == IncludeAbstract.ONLY_ABSTRACT) {
return isAbstract;
} else if (ia == IncludeAbstract.ONLY_NON_ABSTRACT) {
return !isAbstract;
}
return true;
}
}