blob: 8a68e4c38539d9a194fb0fc865ac4a46d8a5a20b [file] [log] [blame]
/*******************************************************************************
* 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, 248869
* Adolfo Sanchez-Barbudo Herrera (Open Canarias) - Bug 297666
*******************************************************************************/
package org.eclipse.ocl.uml.internal;
import java.util.Collection;
import java.util.List;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.ocl.Environment;
import org.eclipse.ocl.expressions.CollectionKind;
import org.eclipse.ocl.types.AnyType;
import org.eclipse.ocl.types.ElementType;
import org.eclipse.ocl.types.InvalidType;
import org.eclipse.ocl.types.MessageType;
import org.eclipse.ocl.types.OCLStandardLibrary;
import org.eclipse.ocl.types.PrimitiveType;
import org.eclipse.ocl.types.VoidType;
import org.eclipse.ocl.uml.OCL;
import org.eclipse.ocl.uml.UMLEnvironment;
import org.eclipse.ocl.uml.UMLEnvironmentFactory;
import org.eclipse.ocl.uml.UMLFactory;
import org.eclipse.ocl.uml.UMLPackage;
import org.eclipse.ocl.util.OCLStandardLibraryUtil;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.DataType;
import org.eclipse.uml2.uml.InstanceSpecification;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Parameter;
import org.eclipse.uml2.uml.Substitution;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.resource.UMLResource;
import org.eclipse.uml2.uml.util.UMLUtil;
/**
* Implementation of the {@link OCLStandardLibrary} for the UML environment.
*
* @author Christian W. Damus (cdamus)
*/
public final class OCLStandardLibraryImpl implements OCLStandardLibrary<Classifier> {
private static final String NS_URI = UMLEnvironment.OCL_STANDARD_LIBRARY_NS_URI;
private static final String ITERATOR_KEYWORD = "iterator"; //$NON-NLS-1$
private static Classifier OCL_ANY;
private static Classifier OCL_ELEMENT;
private static Classifier OCL_BOOLEAN;
private static Classifier OCL_INTEGER;
private static Classifier OCL_UNLIMITED_NATURAL;
private static Classifier OCL_REAL;
private static Classifier OCL_STRING;
private static Classifier OCL_VOID;
private static Classifier OCL_MESSAGE;
private static Classifier OCL_TYPE;
private static Classifier OCL_INVALID;
private static Classifier OCL_T;
private static Classifier OCL_T2;
private static Classifier OCL_SET;
private static Classifier OCL_ORDERED_SET;
private static Classifier OCL_BAG;
private static Classifier OCL_SEQUENCE;
private static Classifier OCL_COLLECTION;
private static Classifier STATE;
private static Classifier OCL_EXPRESSION;
/** The shared instance of the OCL Standard Library for the UML environment. */
public static final OCLStandardLibraryImpl INSTANCE = new OCLStandardLibraryImpl();
/** The singleton instance of the <tt>OclInvalid</tt> standard library type. */
public static Object INVALID =
org.eclipse.uml2.uml.UMLFactory.eINSTANCE.createInstanceSpecification();
/** The package containing the OCL Standard Library classifiers. */
public static Package stdlibPackage = init();
// not instantiable by clients
private OCLStandardLibraryImpl() {
super();
}
public Classifier getBoolean() {
return OCL_BOOLEAN;
}
public Classifier getInteger() {
return OCL_INTEGER;
}
public Classifier getUnlimitedNatural() {
return OCL_UNLIMITED_NATURAL;
}
public Classifier getOclInvalid() {
return OCL_INVALID;
}
public Classifier getReal() {
return OCL_REAL;
}
public Classifier getString() {
return OCL_STRING;
}
public Classifier getOclAny() {
return OCL_ANY;
}
public Classifier getOclElement() {
return OCL_ELEMENT;
}
public Object getInvalid() {
return INVALID;
}
public Classifier getState() {
return STATE;
}
public Classifier getOclMessage() {
return OCL_MESSAGE;
}
public Classifier getOclType() {
return OCL_TYPE;
}
public Classifier getOclVoid() {
return OCL_VOID;
}
public Classifier getT() {
return OCL_T;
}
public Classifier getT2() {
return OCL_T2;
}
public Classifier getSet() {
return OCL_SET;
}
public Classifier getOrderedSet() {
return OCL_ORDERED_SET;
}
public Classifier getBag() {
return OCL_BAG;
}
public Classifier getSequence() {
return OCL_SEQUENCE;
}
public Classifier getCollection() {
return OCL_COLLECTION;
}
public Classifier getOclExpression() {
return OCL_EXPRESSION;
}
private static Package init() {
if (stdlibPackage != null) {
return stdlibPackage;
}
ResourceSet rset = new ResourceSetImpl();
// Ensure that a UMLResource factory is registered for the uml extension.
// Note that when running standalone, a registration in the global registry is not certain.
OCL.initialize(null);
Resource res = null;
try {
res = rset.getResource(URI.createURI(NS_URI), true);
stdlibPackage = (Package) res.getContents().get(0);
OCL_ANY = (Classifier) stdlibPackage.getOwnedType(AnyType.SINGLETON_NAME);
OCL_ELEMENT = (Classifier) stdlibPackage.getOwnedType(ElementType.SINGLETON_NAME);
OCL_BOOLEAN = (Classifier) stdlibPackage.getOwnedType(PrimitiveType.BOOLEAN_NAME);
OCL_INTEGER = (Classifier) stdlibPackage.getOwnedType(PrimitiveType.INTEGER_NAME);
OCL_UNLIMITED_NATURAL = (Classifier) stdlibPackage.getOwnedType(PrimitiveType.UNLIMITED_NATURAL_NAME);
OCL_REAL = (Classifier) stdlibPackage.getOwnedType(PrimitiveType.REAL_NAME);
OCL_STRING = (Classifier) stdlibPackage.getOwnedType(PrimitiveType.STRING_NAME);
OCL_VOID = (Classifier) stdlibPackage.getOwnedType(VoidType.SINGLETON_NAME);
OCL_MESSAGE = (Classifier) stdlibPackage.getOwnedType(MessageType.SINGLETON_NAME);
OCL_INVALID = (Classifier) stdlibPackage.getOwnedType(InvalidType.SINGLETON_NAME);
OCL_T = (Classifier) stdlibPackage.getOwnedType("T"); //$NON-NLS-1$
OCL_T2 = (Classifier) stdlibPackage.getOwnedType("T2"); //$NON-NLS-1$
OCL_TYPE = (Classifier) EcoreUtil.getObjectByType(
stdlibPackage.getOwnedTypes(),
UMLPackage.Literals.TYPE_TYPE);
OCL_SET = (Classifier) EcoreUtil.getObjectByType(
stdlibPackage.getOwnedTypes(),
UMLPackage.Literals.SET_TYPE);
OCL_ORDERED_SET = (Classifier) EcoreUtil.getObjectByType(
stdlibPackage.getOwnedTypes(),
UMLPackage.Literals.ORDERED_SET_TYPE);
OCL_BAG = (Classifier) EcoreUtil.getObjectByType(
stdlibPackage.getOwnedTypes(),
UMLPackage.Literals.BAG_TYPE);
OCL_SEQUENCE = (Classifier) EcoreUtil.getObjectByType(
stdlibPackage.getOwnedTypes(),
UMLPackage.Literals.SEQUENCE_TYPE);
// don't use EcoreUtil because the other collection types would match
OCL_COLLECTION = (Classifier) stdlibPackage.getOwnedType("Collection(T)"); //$NON-NLS-1$
STATE = (Classifier) stdlibPackage.getOwnedType("State"); //$NON-NLS-1$
OCL_EXPRESSION = (Classifier) stdlibPackage.getOwnedType("OclExpression"); //$NON-NLS-1$
((InstanceSpecification) INVALID).getClassifiers().add(OCL_INVALID);
((InstanceSpecification) INVALID).setName("invalid"); //$NON-NLS-1$
addToPackageRegistry(stdlibPackage);
return stdlibPackage;
} catch (Exception e) {
// normal case: the library file isn't there because we are
// generating it on the fly. Let's do that, then
return build();
} finally {
if (res != null) {
// don't want this resource to be in a resource set
rset.getResources().remove(res);
}
}
}
// this method is used to build the standard library when not loading it
// from file
private static Package build() {
if (stdlibPackage != null) {
return stdlibPackage;
}
stdlibPackage = org.eclipse.uml2.uml.UMLFactory.eINSTANCE.createPackage();
stdlibPackage.setName("oclstdlib"); //$NON-NLS-1$
Resource res = UMLResource.Factory.INSTANCE.createResource(
URI.createURI("http://www.eclipse.org/ocl/1.1.0/oclstdlib.uml")); //$NON-NLS-1$
res.getContents().add(stdlibPackage);
Environment<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?> old = Environment.Registry.INSTANCE.getEnvironmentFor(
EcorePackage.Literals.ECLASS);
Environment.Registry.INSTANCE.deregisterEnvironment(old);
UMLEnvironment env =
(UMLEnvironment) new UMLEnvironmentFactory().loadEnvironment(res);
Environment.Registry.INSTANCE.registerEnvironment(env);
OCL_ANY = UMLFactory.eINSTANCE.createAnyType();
OCL_ELEMENT = UMLFactory.eINSTANCE.createElementType();
OCL_BOOLEAN = UMLFactory.eINSTANCE.createPrimitiveType();
OCL_BOOLEAN.setName(PrimitiveType.BOOLEAN_NAME);
OCL_INTEGER = UMLFactory.eINSTANCE.createPrimitiveType();
OCL_INTEGER.setName(PrimitiveType.INTEGER_NAME);
OCL_UNLIMITED_NATURAL = UMLFactory.eINSTANCE.createPrimitiveType();
OCL_UNLIMITED_NATURAL.setName(PrimitiveType.UNLIMITED_NATURAL_NAME);
OCL_REAL = UMLFactory.eINSTANCE.createPrimitiveType();
OCL_REAL.setName(PrimitiveType.REAL_NAME);
OCL_STRING = UMLFactory.eINSTANCE.createPrimitiveType();
OCL_STRING.setName(PrimitiveType.STRING_NAME);
OCL_VOID = UMLFactory.eINSTANCE.createVoidType();
OCL_MESSAGE = UMLFactory.eINSTANCE.createMessageType();
OCL_INVALID = UMLFactory.eINSTANCE.createInvalidType();
OCL_T = UMLFactory.eINSTANCE.createAnyType();
OCL_T.setName("T"); //$NON-NLS-1$
OCL_T2 = UMLFactory.eINSTANCE.createAnyType();
OCL_T2.setName("T2"); //$NON-NLS-1$
OCL_TYPE = (Classifier) OCLFactoryImpl.INSTANCE.createTypeType(OCL_T);
OCL_SET = (Classifier) OCLFactoryImpl.INSTANCE.createSetType(OCL_T);
OCL_ORDERED_SET = (Classifier) OCLFactoryImpl.INSTANCE.createOrderedSetType(OCL_T);
OCL_BAG = (Classifier) OCLFactoryImpl.INSTANCE.createBagType(OCL_T);
OCL_SEQUENCE = (Classifier) OCLFactoryImpl.INSTANCE.createSequenceType(OCL_T);
OCL_COLLECTION = (Classifier) OCLFactoryImpl.INSTANCE.createCollectionType(OCL_T);
STATE = UMLFactory.eINSTANCE.createElementType();
STATE.setName("State"); //$NON-NLS-1$
OCL_EXPRESSION = UMLFactory.eINSTANCE.createElementType();
OCL_EXPRESSION.setName("OclExpression"); //$NON-NLS-1$
((InstanceSpecification) INVALID).getClassifiers().add(OCL_INVALID);
((InstanceSpecification) INVALID).setName("invalid"); //$NON-NLS-1$
register(OCL_ANY).addAll(
OCLStandardLibraryUtil.createAnyTypeOperations(env));
register(OCL_VOID).addAll(
OCLStandardLibraryUtil.createAnyTypeOperations(env));
register(OCL_INVALID).addAll(
OCLStandardLibraryUtil.createAnyTypeOperations(env));
register(OCL_BOOLEAN).addAll(
OCLStandardLibraryUtil.createBooleanOperations(env));
register(OCL_INTEGER).addAll(
OCLStandardLibraryUtil.createIntegerOperations(env));
register(OCL_UNLIMITED_NATURAL).addAll(
OCLStandardLibraryUtil.createUnlimitedNaturalOperations(env));
register(OCL_REAL).addAll(
OCLStandardLibraryUtil.createRealOperations(env));
register(OCL_STRING).addAll(
OCLStandardLibraryUtil.createStringOperations(env));
register(OCL_TYPE).addAll(
OCLStandardLibraryUtil.createTypeTypeOperations(env));
register(OCL_MESSAGE).addAll(
OCLStandardLibraryUtil.createMessageTypeOperations(env));
register(OCL_ELEMENT);
register(STATE);
register(OCL_EXPRESSION);
List<Operation> operations;
List<Operation> iterators;
operations = register(OCL_COLLECTION);
operations.addAll(OCLStandardLibraryUtil.createCollectionOperations(env));
iterators = OCLStandardLibraryUtil.createCollectionIterators(env);
stereotypeAsIterator(iterators);
operations.addAll(iterators);
operations = register(OCL_SET);
operations.addAll(OCLStandardLibraryUtil.createSetOperations(env));
iterators = OCLStandardLibraryUtil.createSetIterators(env);
stereotypeAsIterator(iterators);
operations.addAll(iterators);
operations = register(OCL_ORDERED_SET);
operations.addAll(OCLStandardLibraryUtil.createOrderedSetOperations(env));
iterators = OCLStandardLibraryUtil.createOrderedSetIterators(env);
stereotypeAsIterator(iterators);
operations.addAll(iterators);
operations = register(OCL_BAG);
operations.addAll(OCLStandardLibraryUtil.createBagOperations(env));
iterators = OCLStandardLibraryUtil.createBagIterators(env);
stereotypeAsIterator(iterators);
operations.addAll(iterators);
operations = register(OCL_SEQUENCE);
operations.addAll(OCLStandardLibraryUtil.createSequenceOperations(env));
iterators = OCLStandardLibraryUtil.createSequenceIterators(env);
stereotypeAsIterator(iterators);
operations.addAll(iterators);
register(OCL_T); // operations already defined by OclAny
register(OCL_T2); // operations already defined by OclAny
addToPackageRegistry(stdlibPackage);
Environment.Registry.INSTANCE.registerEnvironment(old);
return stdlibPackage;
}
private static void addToPackageRegistry(Package pkg) {
// ensure that this package is registered in the EPackage registry so
// that looking up the OCL Standard Library resource's URI finds
// it there (common behaviour of all resource sets)
EAnnotation ann = pkg.createEAnnotation(Environment.OCL_NAMESPACE_URI);
Collection<EPackage> ecore = UMLUtil.convertToEcore(pkg, null);
ann.getContents().addAll(ecore);
if (!ecore.isEmpty()) {
EPackage epackage = ecore.iterator().next();
epackage.setNsURI(pkg.eResource().getURI().toString());
EPackage.Registry.INSTANCE.put(epackage.getNsURI(), epackage);
}
}
private static List<Operation> register(Classifier stdType) {
List<Operation> result = null;
if (stdType instanceof DataType) {
result = ((DataType) stdType).getOwnedOperations();
} else if (stdType instanceof org.eclipse.ocl.uml.AnyType) {
result = ((org.eclipse.ocl.uml.AnyType) stdType).getOwnedOperations();
} else if (stdType instanceof org.eclipse.ocl.uml.InvalidType) {
result = ((org.eclipse.ocl.uml.InvalidType) stdType).getOwnedOperations();
} else if (stdType instanceof org.eclipse.ocl.uml.VoidType) {
result = ((org.eclipse.ocl.uml.VoidType) stdType).getOwnedOperations();
} else if (stdType instanceof org.eclipse.ocl.uml.MessageType) {
result = ((org.eclipse.ocl.uml.MessageType) stdType).getOwnedOperations();
} else if (stdType instanceof org.eclipse.ocl.uml.TypeType) {
result = ((org.eclipse.ocl.uml.TypeType) stdType).getOwnedOperations();
}
// add the type to the standard library package
stdlibPackage.getOwnedTypes().add(stdType);
return result;
}
/**
* Finds the shadow class to contain features defined for the
* specified OCL <code>type</code>, if it already exists.
*
* @param classifier an Ecore classifier
* @param pkg the package in which to look for the shadow class
*
* @return the class containing its features, or <code>null</code> if not
* found
*/
public static Class findShadowClass(Classifier classifier, Package pkg) {
for (Type next : pkg.getOwnedTypes()) {
if (next instanceof Class) {
Class clazz = (Class) next;
if (getRealClassifier(clazz) == classifier) {
return clazz;
}
}
}
return null;
}
public static Classifier getRealClassifier(Class shadow) {
Substitution sub = shadow.getSubstitution("realOwner", null); //$NON-NLS-1$
return (sub == null)? null : sub.getContract();
}
/**
* Marks the specified operations as being collection iterators (as distinct
* from ordinary operations).
*
* @param operations operations to designate as iterators
*/
public static void stereotypeAsIterator(Collection<Operation> operations) {
for (Operation oper : operations) {
oper.addKeyword("iterator"); //$NON-NLS-1$
}
}
/**
* Selects from the specified operations those that are collection iterators.
*
* @param operations operations
* @return the subset that are stereotyped as iterators
*/
public static EList<Operation> selectIterators(Collection<Operation> operations) {
EList<Operation> result = new BasicEList.FastCompare<Operation>();
for (Operation oper : operations) {
if (oper.hasKeyword(ITERATOR_KEYWORD)) {
result.add(oper);
}
}
return result;
}
public static Collection<Operation> createCollectionTypeOperations(
Environment<?, Classifier, Operation, ?, ?, Parameter, ?, ?, ?, ?, ?, ?> env,
CollectionKind kind) {
Collection<Operation> operations;
Collection<Operation> iterators;
switch (kind) {
case BAG_LITERAL:
operations = OCLStandardLibraryUtil.createBagOperations(env);
iterators = OCLStandardLibraryUtil.createBagIterators(env);
break;
case SET_LITERAL:
operations = OCLStandardLibraryUtil.createSetOperations(env);
iterators = OCLStandardLibraryUtil.createSetIterators(env);
break;
case ORDERED_SET_LITERAL:
operations = OCLStandardLibraryUtil.createOrderedSetOperations(env);
iterators = OCLStandardLibraryUtil.createOrderedSetIterators(env);
break;
case SEQUENCE_LITERAL:
operations = OCLStandardLibraryUtil.createSequenceOperations(env);
iterators = OCLStandardLibraryUtil.createSequenceIterators(env);
break;
default:
operations = OCLStandardLibraryUtil.createCollectionOperations(env);
iterators = OCLStandardLibraryUtil.createCollectionIterators(env);
break;
}
for (Operation next : iterators) {
next.addKeyword(ITERATOR_KEYWORD);
}
Collection<Operation> result = new java.util.ArrayList<Operation>(
operations.size() + iterators.size());
result.addAll(operations);
result.addAll(iterators);
return result;
}
}