| /******************************************************************************* |
| * Copyright (c) 2006, 2018 IBM Corporation, Zeligsoft Inc., and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v2.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v20.html |
| * |
| * Contributors: |
| * IBM - Initial API and implementation |
| * Zeligsoft - Bugs 252600, 251808 |
| *******************************************************************************/ |
| |
| package org.eclipse.ocl.uml; |
| |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.emf.common.util.BasicEList; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.ecore.EAnnotation; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EModelElement; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.ocl.AbstractEnvironment; |
| import org.eclipse.ocl.Environment; |
| import org.eclipse.ocl.EnvironmentFactory; |
| import org.eclipse.ocl.TypeResolver; |
| import org.eclipse.ocl.expressions.Variable; |
| import org.eclipse.ocl.lpg.FormattingHelper; |
| import org.eclipse.ocl.types.OCLStandardLibrary; |
| import org.eclipse.ocl.uml.internal.OCLFactoryImpl; |
| import org.eclipse.ocl.uml.internal.OCLStandardLibraryImpl; |
| import org.eclipse.ocl.uml.internal.UMLForeignMethods; |
| import org.eclipse.ocl.uml.internal.UMLReflectionImpl; |
| import org.eclipse.ocl.uml.util.OCLUMLUtil; |
| import org.eclipse.ocl.utilities.OCLFactory; |
| import org.eclipse.ocl.utilities.UMLReflection; |
| import org.eclipse.uml2.uml.Association; |
| import org.eclipse.uml2.uml.Behavior; |
| import org.eclipse.uml2.uml.BehavioredClassifier; |
| import org.eclipse.uml2.uml.CallOperationAction; |
| import org.eclipse.uml2.uml.Class; |
| import org.eclipse.uml2.uml.Classifier; |
| import org.eclipse.uml2.uml.Constraint; |
| import org.eclipse.uml2.uml.EnumerationLiteral; |
| import org.eclipse.uml2.uml.Feature; |
| import org.eclipse.uml2.uml.Namespace; |
| 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.ParameterEffectKind; |
| import org.eclipse.uml2.uml.Profile; |
| import org.eclipse.uml2.uml.Property; |
| import org.eclipse.uml2.uml.Region; |
| import org.eclipse.uml2.uml.SendSignalAction; |
| import org.eclipse.uml2.uml.State; |
| import org.eclipse.uml2.uml.StateMachine; |
| import org.eclipse.uml2.uml.Type; |
| import org.eclipse.uml2.uml.UMLFactory; |
| import org.eclipse.uml2.uml.UMLPackage; |
| import org.eclipse.uml2.uml.Vertex; |
| |
| /** |
| * Implementation of the {@link Environment} for parsing OCL expressions on UML |
| * models. The <code>UMLEnvironment</code> uses a client-supplied resource set |
| * to look up UML {@link Package}s in UML resources. It also uses an |
| * {@link EPackage} registry to find the corresponding Ecore definitions of |
| * packages when evaluating expressions on instances of the UML model (in the |
| * case of evaluation on UML2-generated API objects). |
| * |
| * @author Christian W. Damus (cdamus) |
| */ |
| public class UMLEnvironment |
| extends |
| AbstractEnvironment<Package, Classifier, Operation, Property, EnumerationLiteral, Parameter, State, CallOperationAction, SendSignalAction, Constraint, Class, EObject> { |
| |
| /** |
| * The namespace URI of the UML representation of the OCL Standard Library. |
| * |
| * @since 2.0 |
| */ |
| public static final String OCL_STANDARD_LIBRARY_NS_URI = "http://www.eclipse.org/ocl/1.1.0/oclstdlib.uml"; //$NON-NLS-1$ |
| |
| static final String ANNOTATION_SOURCE = org.eclipse.ocl.uml.UMLPackage.eNS_URI; |
| |
| private static OCLStandardLibraryImpl standardLibrary; |
| |
| private UMLReflection<Package, Classifier, Operation, Property, EnumerationLiteral, Parameter, State, CallOperationAction, SendSignalAction, Constraint> reflection; |
| |
| /** The resource set for package lookups. */ |
| private ResourceSet resourceSet; |
| |
| /** The package registry for Ecore definition lookups. */ |
| private EPackage.Registry registry; |
| |
| private EnvironmentFactory<Package, Classifier, Operation, Property, EnumerationLiteral, Parameter, State, CallOperationAction, SendSignalAction, Constraint, Class, EObject> factory; |
| |
| private TypeResolver<Classifier, Operation, Property> typeResolver; |
| |
| private Package umlMetamodel; |
| |
| private Map<List<String>, Classifier> classifierCache = new java.util.HashMap<List<String>, Classifier>(); |
| |
| private Map<List<String>, Package> packageCache = new java.util.HashMap<List<String>, Package>(); |
| |
| /** |
| * Initializes me with a package registry for looking up the Ecore |
| * representations of UML packages and a resource set for looking up UML |
| * packages in UML resources. |
| * |
| * @param registry |
| * the Ecore package registry to use |
| * @param rset |
| * the resource set to use |
| */ |
| protected UMLEnvironment(EPackage.Registry registry, ResourceSet rset) { |
| this.registry = registry; |
| resourceSet = rset; |
| |
| typeResolver = createTypeResolver(); |
| } |
| |
| /** |
| * Initializes me with a package registry for looking up the Ecore |
| * representations of UML packages, a resource set for looking up UML |
| * packages in UML resources, and a resource from which to load myself. |
| * |
| * @param registry |
| * the Ecore package registry to use |
| * @param rset |
| * the resource set to use |
| * @param resource |
| * my resource for persistence |
| */ |
| protected UMLEnvironment(EPackage.Registry registry, ResourceSet rset, |
| Resource resource) { |
| this.registry = registry; |
| resourceSet = rset; |
| |
| typeResolver = createTypeResolver(resource); |
| } |
| |
| /** |
| * Initializes me with a parent environment. I inherit my package registry, |
| * resource set, and resource from it. |
| * |
| * @param parent |
| * my parent environment |
| */ |
| protected UMLEnvironment( |
| Environment<Package, Classifier, Operation, Property, EnumerationLiteral, Parameter, State, CallOperationAction, SendSignalAction, Constraint, Class, EObject> parent) { |
| |
| super((UMLEnvironment) parent); |
| |
| UMLEnvironment uparent = (UMLEnvironment) parent; |
| |
| if (uparent != null) { |
| this.registry = uparent.registry; |
| resourceSet = uparent.resourceSet; |
| typeResolver = uparent.getTypeResolver(); |
| } else { |
| this.registry = (EPackage.Registry.INSTANCE); |
| resourceSet = new ResourceSetImpl(); |
| typeResolver = createTypeResolver(); |
| } |
| } |
| |
| // implements the inherited specification |
| public EnvironmentFactory<org.eclipse.uml2.uml.Package, Classifier, Operation, Property, EnumerationLiteral, Parameter, State, CallOperationAction, SendSignalAction, Constraint, org.eclipse.uml2.uml.Class, EObject> getFactory() { |
| if (factory != null) { |
| return factory; |
| } |
| |
| if (getInternalParent() != null) { |
| factory = getInternalParent().getFactory(); |
| if (factory != null) { |
| return factory; |
| } |
| } |
| |
| // obtain a reasonable default factory |
| factory = new UMLEnvironmentFactory(getResourceSet()); |
| |
| return factory; |
| } |
| |
| /** |
| * Sets the factory that created me. This method should only be invoked by |
| * that factory. |
| * |
| * @param factory |
| * my originating factory |
| */ |
| protected void setFactory( |
| EnvironmentFactory<Package, Classifier, Operation, Property, EnumerationLiteral, Parameter, State, CallOperationAction, SendSignalAction, Constraint, Class, EObject> factory) { |
| this.factory = factory; |
| } |
| |
| /** |
| * Looks up the Ecore definition of the specified UML classifier, using the |
| * specified <code>element</code> as a context for finding profile |
| * applications in the case that the classifier is a stereotype or some |
| * other type in a {@link Profile}. Finding the Ecore definition of a profile |
| * type requires finding the actual applied version of the profile. |
| * |
| * @param type a UML classifier |
| * @param element an element in the context of which the OCL evaluation |
| * is being performed |
| * @return the corresponding Ecore classifier, or <code>null</code> if not |
| * found |
| * @since 3.0 |
| */ |
| public EClassifier getEClassifier(Classifier type, Object element) { |
| return OCLUMLUtil.getEClassifier(type, element, registry); |
| } |
| |
| // /** |
| // * Obtains my EPackage registry, for looking up the Ecore correspondents |
| // * of UML metamodel elements when working with instances of generated Java |
| // * types. |
| // * |
| // * @return my EPackage registry |
| // */ |
| // EPackage.Registry getEPackageRegistry() { |
| // return registry; |
| // } |
| |
| // implements the inherited specification |
| public void setParent( |
| Environment<Package, Classifier, Operation, Property, EnumerationLiteral, Parameter, State, CallOperationAction, SendSignalAction, Constraint, Class, EObject> env) { |
| super.setParent((UMLEnvironment) env); |
| } |
| |
| // implements the inherited specification |
| public OCLStandardLibrary<Classifier> getOCLStandardLibrary() { |
| if (standardLibrary == null) { |
| standardLibrary = OCLStandardLibraryImpl.INSTANCE; |
| } |
| |
| return standardLibrary; |
| } |
| |
| /** |
| * Obtains the resource set in which I look for UML packages when resolving |
| * package names. |
| * |
| * @return my resource set |
| */ |
| protected final ResourceSet getResourceSet() { |
| return resourceSet; |
| } |
| |
| /** |
| * Obtains the UML metamodel library, loaded in my resource set. |
| * |
| * @return the UML metamodel |
| */ |
| protected Package getUMLMetamodel() { |
| if (umlMetamodel == null) { |
| if (getFactory() instanceof UMLEnvironmentFactory) { |
| umlMetamodel = ((UMLEnvironmentFactory) getFactory()) |
| .getUMLMetamodel(); |
| } else { |
| umlMetamodel = OCLUMLUtil.getUMLMetamodel(getResourceSet()); |
| } |
| } |
| |
| return umlMetamodel; |
| } |
| |
| // implements the inherited specification |
| public TypeResolver<Classifier, Operation, Property> getTypeResolver() { |
| return typeResolver; |
| } |
| |
| // implements the inherited specification |
| public OCLFactory getOCLFactory() { |
| return OCLFactoryImpl.INSTANCE; |
| } |
| |
| // implements the inherited specification |
| public UMLReflection<Package, Classifier, Operation, Property, EnumerationLiteral, Parameter, State, CallOperationAction, SendSignalAction, Constraint> getUMLReflection() { |
| if (reflection == null) { |
| reflection = new UMLReflectionImpl(this); |
| } |
| |
| return reflection; |
| } |
| |
| /** |
| * Creates a new type resolver for use with this environment, persisted |
| * in a default resource. |
| * |
| * @return a new type resolver |
| * |
| * @deprecated Override the {@link #createTypeResolver(Resource)} method, |
| * instead, handling the case where the resource is <code>null</code> |
| */ |
| @Deprecated |
| protected TypeResolver<Classifier, Operation, Property> createTypeResolver() { |
| return createTypeResolver(null); |
| } |
| |
| /** |
| * <p> |
| * Creates a new type resolver for use with this environment. |
| * </p><p> |
| * Subclasses may override. |
| * </p> |
| * |
| * @param resource the resource for the type resolver's persistence |
| * @return a new type resolver |
| * |
| * @since 1.2 |
| */ |
| protected TypeResolver<Classifier, Operation, Property> createTypeResolver(Resource resource) { |
| return new TypeResolverImpl(this, resource); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * <p> |
| * Implements the inherited specification by looking in my resource set for |
| * a resource containing the specified package. |
| * </p> |
| */ |
| public org.eclipse.uml2.uml.Package lookupPackage(List<String> path) { |
| Package tryCache = packageCache.get(path); |
| if (tryCache != null) { |
| return tryCache; |
| } |
| |
| Package pkg = null; |
| Package currPkg = getContextPackage(); |
| |
| // Check whether this package is in the default package |
| if (currPkg != null) { |
| List<String> lookup = path; |
| |
| while (currPkg != null) { |
| pkg = currPkg; |
| |
| for (int i = 0; i < lookup.size(); i++) { |
| String name = lookup.get(i); |
| pkg = UMLForeignMethods.getNestedPackage(pkg, name); |
| |
| if (pkg == null) { |
| break; |
| } |
| } |
| |
| if (pkg != null) { |
| packageCache.put(path, pkg); |
| return pkg; |
| } |
| |
| if ((currPkg == getContextPackage()) && (lookup.size() > 0) |
| && UMLForeignMethods.isNamed(lookup.get(0), currPkg)) { |
| // handle the case where the first part of the qualified |
| // name matches the context package name |
| lookup = lookup.subList(1, lookup.size()); |
| } else { |
| lookup = path; |
| currPkg = currPkg.getNestingPackage(); |
| } |
| } |
| } |
| |
| // Check whether this package exists in the resource set |
| Package result = OCLUMLUtil.findPackage(path, getResourceSet()); |
| packageCache.put(path, result); |
| return result; |
| } |
| |
| // implements the inherited specification |
| public Classifier lookupClassifier(List<String> names) { |
| Classifier tryCache = classifierCache.get(names); |
| if (tryCache != null) { |
| return tryCache; |
| } |
| |
| Namespace ns = null; |
| Namespace currNs = getContextPackage(); |
| |
| if (names.size() > 1) { |
| List<String> lookup = names; |
| |
| // Check whether this package is in the default package |
| if (currNs != null) { |
| while (currNs != null) { |
| |
| ns = currNs; |
| int last = lookup.size() - 1; |
| |
| for (int i = 0; i < last; i++) { |
| String name = lookup.get(i); |
| ns = (Namespace) UMLForeignMethods.getMember(ns, name, |
| UMLPackage.Literals.NAMESPACE); |
| |
| if (ns == null) { |
| break; |
| } |
| } |
| |
| if (ns != null) { |
| String name = lookup.get(last); |
| |
| Classifier member = (Classifier) UMLForeignMethods |
| .getMember(ns, name, UMLPackage.Literals.CLASSIFIER); |
| |
| if (member != null) { |
| classifierCache.put(names, member); |
| return member; |
| } |
| } |
| |
| if ((currNs == getContextPackage()) && (lookup.size() > 1) |
| && UMLForeignMethods.isNamed(lookup.get(0), currNs)) { |
| // handle the case where the first part of the qualified |
| // name matches the context package name |
| lookup = lookup.subList(1, lookup.size()); |
| } else { |
| lookup = names; |
| currNs = currNs.getNamespace(); |
| } |
| } |
| } |
| |
| // Check whether this package exists |
| List<String> newNames = names.subList(0, names.size() - 1); |
| ns = OCLUMLUtil.findNamespace(newNames, getResourceSet()); |
| if (ns == null) { |
| return null; |
| } |
| |
| String name = names.get(names.size() - 1); |
| Classifier member = (Classifier) UMLForeignMethods.getMember(ns, |
| name, UMLPackage.Literals.CLASSIFIER); |
| |
| if (member != null) { |
| classifierCache.put(names, member); |
| return member; |
| } |
| |
| return member; |
| } else if (getContextPackage() != null) { |
| String name = names.get(0); |
| Classifier result = null; |
| while (currNs != null) { |
| result = (Classifier) UMLForeignMethods.getMember(currNs, name, |
| UMLPackage.Literals.CLASSIFIER); |
| |
| if (result != null) { |
| classifierCache.put(names, result); |
| return result; |
| } |
| |
| currNs = currNs.getNamespace(); |
| } |
| } |
| |
| return null; |
| } |
| |
| @Override |
| protected void findNonNavigableAssociationEnds(Classifier classifier, |
| String name, List<Property> ends) { |
| |
| EList<Association> associations = UMLForeignMethods.getAllAssociations(classifier); |
| |
| // search for non-navigable, named ends |
| for (Association next : associations) { |
| if (next.isBinary()) { |
| Property end = next.getMemberEnd(name, null); |
| |
| if ((end != null) |
| && OCLUMLUtil |
| .isNonNavigableAssocationEndOf(end, classifier)) { |
| |
| ends.add(end); |
| } |
| } |
| } |
| } |
| |
| @Override |
| protected void findUnnamedAssociationEnds(Classifier classifier, String name, |
| List<Property> ends) { |
| |
| EList<Association> associations = UMLForeignMethods.getAllAssociations(classifier); |
| |
| for (Association next : associations) { |
| if (next.isBinary()) { |
| for (Property end : next.getMemberEnds()) { |
| if (isUnnamed(end)) { |
| Type type = end.getType(); |
| if ((type != null) |
| && initialLower(type).equals(name) |
| && OCLUMLUtil.isNonNavigableAssocationEndOf(end, |
| classifier)) { |
| |
| ends.add(end); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Queries whether the specified association end has no name. |
| * |
| * @param associationEnd an association end |
| * |
| * @return whether it is unnamed |
| */ |
| protected boolean isUnnamed(Property associationEnd) { |
| return associationEnd.getName() == null; |
| } |
| |
| // implements the inherited specification |
| public List<State> getStates(Classifier owner, List<String> pathPrefix) { |
| EList<State> result = new BasicEList.FastCompare<State>(); |
| |
| collectStates(owner, pathPrefix, result); |
| |
| // search supertypes |
| for (Classifier general : owner.allParents()) { |
| collectStates(general, pathPrefix, result); |
| } |
| |
| // now, filter out redefinitions, in case our prefix match found |
| // states that are redefined by other matches (as an instance of the |
| // owner type cannot be in a state that is redefined by a more |
| // specific state) |
| Set<State> redefinitions = new java.util.HashSet<State>(); |
| for (State s : result) { |
| State redef = s.getRedefinedState(); |
| |
| while (redef != null) { |
| redefinitions.add(redef); |
| redef = redef.getRedefinedState(); |
| } |
| } |
| |
| result.removeAll(redefinitions); |
| |
| return result; |
| } |
| |
| /** |
| * Finds all states in the specified owner type that match the given path |
| * name prefix and add them to the accumulator list. |
| * |
| * @param owner |
| * the owner type |
| * @param pathPrefix |
| * partial qualified name, specifying the parent of the states to |
| * be collected |
| * @param states |
| * a list of states directly owned by the namespace indicated by |
| * path prefix, within the owner type |
| */ |
| private void collectStates(Classifier owner, List<String> pathPrefix, |
| List<State> states) { |
| if (owner instanceof BehavioredClassifier) { |
| List<Behavior> behaviors = ((BehavioredClassifier) owner) |
| .getOwnedBehaviors(); |
| |
| for (Behavior b : behaviors) { |
| if (b instanceof StateMachine) { |
| collectStates((StateMachine) b, pathPrefix, states); |
| } |
| } |
| } |
| } |
| |
| private void collectStates(StateMachine machine, List<String> pathPrefix, |
| List<State> states) { |
| if (pathPrefix.isEmpty()) { |
| for (Region r : machine.getRegions()) { |
| collectStates(r, pathPrefix, states); |
| } |
| } else { |
| String firstName = pathPrefix.get(0); |
| |
| if (UMLForeignMethods.isNamed(firstName, machine)) { |
| // we are allowed to qualify the states by machine name |
| pathPrefix = pathPrefix.subList(1, pathPrefix.size()); |
| } |
| |
| for (Region r : machine.getRegions()) { |
| collectStates(r, pathPrefix, states); |
| } |
| } |
| } |
| |
| private void collectStates(Region region, List<String> pathPrefix, |
| List<State> states) { |
| if (pathPrefix.isEmpty()) { |
| // terminus of the recursion: get all the states in this region |
| for (Vertex v : region.getSubvertices()) { |
| if (v instanceof State) { |
| states.add((State) v); |
| } |
| } |
| } else { |
| String firstName = pathPrefix.get(0); |
| |
| Vertex v = UMLForeignMethods.getSubvertex(region, firstName); |
| if (v instanceof State) { |
| State state = (State) v; |
| |
| if (state.isComposite()) { |
| // recursively search the regions of this composite state |
| pathPrefix = pathPrefix.subList(1, pathPrefix.size()); |
| |
| for (Region r : state.getRegions()) { |
| collectStates(r, pathPrefix, states); |
| } |
| } |
| } |
| } |
| } |
| |
| // implements the inherited specification |
| public Property defineAttribute(Classifier owner, |
| Variable<Classifier, Parameter> variable, Constraint constraint) { |
| resetTypeCaches(); |
| Property result; |
| |
| String name = variable.getName(); |
| Classifier type = variable.getType(); |
| |
| result = UMLFactory.eINSTANCE.createProperty(); |
| |
| result.addKeyword(UMLReflection.OCL_HELPER); |
| |
| result.setName(name); |
| result.setType(type); |
| |
| annotate(result, constraint); |
| |
| addHelperProperty(owner, result); |
| |
| return result; |
| } |
| |
| // implements the inherited specification |
| public Operation defineOperation(Classifier owner, String name, |
| Classifier type, List<Variable<Classifier, Parameter>> params, |
| Constraint constraint) { |
| resetTypeCaches(); |
| Operation result = UMLFactory.eINSTANCE.createOperation(); |
| |
| result.addKeyword(UMLReflection.OCL_HELPER); |
| |
| result.setName(name); |
| result.setType(type == null ? getOCLStandardLibrary().getOclVoid() |
| : type); |
| result.setIsQuery(true); // OCL can only define queries |
| |
| for (Variable<Classifier, Parameter> next : params) { |
| Parameter param = UMLFactory.eINSTANCE.createParameter(); |
| param.setName(next.getName()); |
| param.setType(next.getType() == null ? getOCLStandardLibrary() |
| .getOclVoid() |
| : next.getType()); |
| |
| param.setDirection(ParameterDirectionKind.IN_LITERAL); |
| param.setEffect(ParameterEffectKind.READ_LITERAL); |
| |
| result.getOwnedParameters().add(param); |
| } |
| |
| annotate(result, constraint); |
| |
| addHelperOperation(owner, result); |
| |
| return result; |
| } |
| |
| private void annotate(Feature feature, Constraint definition) { |
| EAnnotation annotation = feature.getEAnnotation(ANNOTATION_SOURCE); |
| |
| if (annotation == null) { |
| annotation = feature.createEAnnotation(ANNOTATION_SOURCE); |
| } |
| |
| annotation.getReferences().add(definition); |
| } |
| |
| // implements the inherited specification |
| public void undefine(Object feature) { |
| Constraint definition = getDefinition(feature); |
| |
| if (definition == null) { |
| throw new IllegalArgumentException( |
| "not an additional feature: " + feature); //$NON-NLS-1$ |
| } |
| |
| EcoreUtil.remove((EObject) feature); |
| EcoreUtil.remove(definition); |
| |
| definition.getConstrainedElements().clear(); |
| resetTypeCaches(); |
| } |
| |
| // implements the inherited specification |
| public Constraint getDefinition(Object feature) { |
| Constraint result = null; |
| Feature umlFeature = (Feature) feature; |
| |
| Classifier owner = (Classifier) umlFeature.getOwner(); |
| |
| if (owner instanceof Class) { |
| Classifier shadowed = ((TypeResolverImpl) getTypeResolver()) |
| .getShadowedClassifier(owner); |
| |
| if (shadowed != null) { |
| owner = shadowed; |
| } |
| } |
| |
| if (owner != null) { |
| if (feature instanceof EModelElement) { |
| EAnnotation annotation = ((EModelElement) feature).getEAnnotation( |
| ANNOTATION_SOURCE); |
| if (annotation != null) { |
| result = (Constraint) EcoreUtil.getObjectByType( |
| annotation.getReferences(), |
| UMLPackage.Literals.CONSTRAINT); |
| } |
| } |
| |
| if (result == null) { |
| // backward compatibility for existing serializations |
| for (Constraint ct : owner.getOwnedRules()) { |
| if (ct.getKeywords().contains(UMLReflection.DEFINITION) |
| && ct.getConstrainedElements().contains(umlFeature)) { |
| result = ct; |
| break; |
| } |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| // implements the inherited specification |
| public boolean isInPostcondition( |
| org.eclipse.ocl.expressions.OCLExpression<Classifier> exp) { |
| |
| Constraint constraint = null; |
| EObject parent = exp; |
| while (parent != null) { |
| if (parent instanceof Constraint) { |
| constraint = (Constraint) parent; |
| break; |
| } |
| |
| parent = parent.eContainer(); |
| } |
| |
| return (constraint != null) |
| && (!constraint.getKeywords().isEmpty()) |
| && UMLReflection.POSTCONDITION.equals(constraint.getKeywords().get( |
| 0)); |
| } |
| |
| /** |
| * I provide a custom formatting helper for UML metamodel. |
| * |
| * @since 1.2 |
| */ |
| @Override |
| public FormattingHelper getFormatter() { |
| return UMLFormattingHelper.INSTANCE; |
| } |
| } |