| /******************************************************************************* |
| * 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; |
| } |
| } |