| /******************************************************************************* |
| * Copyright (c) 2005, 2018 IBM Corporation 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 |
| * Adolfo Sanchez-Barbudo Herrera (Open Canarias) - Bug 333032 |
| *******************************************************************************/ |
| |
| package org.eclipse.ocl.ecore; |
| |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EEnumLiteral; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EOperation; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EParameter; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecore.EcorePackage; |
| import org.eclipse.emf.ecore.impl.EPackageRegistryImpl; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.ocl.AbstractEnvironmentFactory; |
| import org.eclipse.ocl.Environment; |
| import org.eclipse.ocl.EnvironmentFactory; |
| import org.eclipse.ocl.EvaluationEnvironment; |
| import org.eclipse.ocl.EvaluationVisitor; |
| import org.eclipse.ocl.ecore.internal.OCLStandardLibraryImpl; |
| import org.eclipse.ocl.ecore.internal.UMLReflectionImpl; |
| import org.eclipse.ocl.ecore.internal.evaluation.TracingEvaluationVisitor; |
| import org.eclipse.ocl.ecore.opposites.EcoreEnvironmentFactoryWithHiddenOpposites; |
| import org.eclipse.ocl.ecore.opposites.OppositeEndFinder; |
| import org.eclipse.ocl.ecore.parser.OCLAnalyzer; |
| import org.eclipse.ocl.ecore.parser.OCLFactoryWithHistory; |
| import org.eclipse.ocl.ecore.parser.ValidationVisitor; |
| import org.eclipse.ocl.helper.OCLSyntaxHelper; |
| import org.eclipse.ocl.options.ParsingOptions; |
| import org.eclipse.ocl.parser.AbstractOCLParser; |
| import org.eclipse.ocl.utilities.Visitor; |
| |
| |
| |
| /** |
| * Implementation of the {@link EnvironmentFactory} for parsing OCL expressions |
| * on Ecore models. |
| * |
| * @author Christian W. Damus (cdamus) |
| */ |
| public class EcoreEnvironmentFactory |
| extends AbstractEnvironmentFactory< |
| EPackage, EClassifier, EOperation, EStructuralFeature, |
| EEnumLiteral, EParameter, |
| EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> { |
| |
| /** |
| * A convenient shared instance of the environment factory, that creates |
| * environments using the global package registry. |
| */ |
| public static EcoreEnvironmentFactory INSTANCE = new EcoreEnvironmentFactory(); |
| |
| private final EPackage.Registry registry; |
| |
| private OppositeEndFinder oppositeEndFinder = null; |
| |
| /** |
| * Initializes me. Environments that I create will use the global package |
| * registry to look up packages. |
| */ |
| public EcoreEnvironmentFactory() { |
| this(EPackage.Registry.INSTANCE); |
| } |
| |
| /** |
| * Initializes me with an <code>EPackage.Registry</code> that the |
| * environments I create will use to look up packages. |
| * |
| * @param reg |
| * my package registry (must not be <code>null</code>). Package |
| * descriptors that are not yet resolved will not be resolved for |
| * OCL package name lookups. To ensure that packages can be |
| * referenced by their name, clients shall |
| * {@link org.eclipse.emf.ecore.EPackage.Registry#getEPackage(String) EPackage.Registry.getEPackage(String)} those |
| * packages explicitly before asking OCL to look them up. See |
| * also {@link ParsingOptions#PACKAGE_LOOKUP_STRATEGY} for |
| * different package lookup strategies. Note also, that if a |
| * {@link EPackageRegistryImpl#EPackageRegistryImpl(org.eclipse.emf.ecore.EPackage.Registry) |
| * "delegating registry"} is used, packages contained only by the |
| * delegate will not be found by an OCL lookup because |
| * {@link org.eclipse.emf.ecore.EPackage.Registry#values() EPackage.Registry.values()} only enumerates the |
| * packages / descriptors contained by the outer registry. |
| */ |
| public EcoreEnvironmentFactory(EPackage.Registry reg) { |
| super(); |
| this.registry = reg; |
| } |
| |
| // implements the inherited specification |
| public Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> |
| createEnvironment() { |
| EcoreEnvironment result = new EcoreEnvironment(this, null); |
| return result; |
| } |
| |
| // implements the inherited specification |
| public Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> |
| loadEnvironment(Resource resource) { |
| EcoreEnvironment result = new EcoreEnvironment(this, resource); |
| return result; |
| } |
| |
| /** |
| * Obtains the package registry used by environment that I create to look |
| * up packages. |
| * |
| * @return my package registry |
| */ |
| public final EPackage.Registry getEPackageRegistry() { |
| return registry; |
| } |
| |
| // implements the inherited specification |
| @Override |
| protected EPackage lookupPackage(List<String> pathname) { |
| return EcoreEnvironment.findPackage(pathname, registry); |
| } |
| |
| // implements the inherited specification |
| @Override |
| protected EClassifier getClassifier(Object context) { |
| return oclType(context); |
| } |
| |
| static EClassifier oclType(Object object) { |
| EClassifier result = null; |
| |
| if (object instanceof EObject) { |
| result = ((EObject) object).eClass(); |
| } else { |
| // maybe it's an instance of an Ecore data type? |
| for (EClassifier next : EcorePackage.eINSTANCE.getEClassifiers()) { |
| if ((next != EcorePackage.Literals.EJAVA_OBJECT) && (next.isInstance(object))) { |
| result = UMLReflectionImpl.INSTANCE.asOCLType(next); |
| break; |
| } |
| } |
| |
| if (result == null) { |
| // it's just some weirdo object that we don't understand |
| result = OCLStandardLibraryImpl.INSTANCE.getOclAny(); |
| } |
| } |
| |
| return result; |
| } |
| |
| // implements the inherited specification |
| public Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> |
| createEnvironment(Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> parent) { |
| if (!(parent instanceof EcoreEnvironment)) { |
| throw new IllegalArgumentException( |
| "Parent environment must be an Ecore environment: " + parent); //$NON-NLS-1$ |
| } |
| |
| EcoreEnvironment result = new EcoreEnvironment(parent); |
| return result; |
| } |
| |
| // implements the inherited specification |
| public EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject> |
| createEvaluationEnvironment() { |
| return new EcoreEvaluationEnvironment(this); |
| } |
| |
| // implements the inherited specification |
| public EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject> |
| createEvaluationEnvironment( |
| EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject> parent) { |
| return new EcoreEvaluationEnvironment(parent); |
| } |
| |
| /** |
| * @since 3.1 |
| */ |
| @Override |
| public OCLAnalyzer createOCLAnalyzer( |
| Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> env, |
| String input) { |
| return new OCLAnalyzer(env, input); |
| } |
| |
| /** |
| * @since 3.1 |
| */ |
| @Override |
| public OCLAnalyzer createOCLAnalyzer( |
| AbstractOCLParser parser) { |
| return new OCLAnalyzer(parser); |
| } |
| |
| /** |
| * @since 3.1 |
| */ |
| public OCLFactoryWithHistory createOCLFactoryWithHistory( |
| Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> env) { |
| return new OCLFactoryWithHistory(env.getOCLFactory()); |
| } |
| |
| /** |
| * @since 3.1 |
| */ |
| @Override |
| public OCLSyntaxHelper createOCLSyntaxHelper( |
| Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> env) { |
| return new org.eclipse.ocl.ecore.internal.helper.OCLSyntaxHelper(env); |
| } |
| |
| /** |
| * @since 3.1 |
| */ |
| @Override |
| public Visitor<Boolean, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint> createValidationVisitor( |
| Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> env) { |
| return new ValidationVisitor(env); |
| } |
| |
| /** |
| * Returns a <code>null</code> opposite end finder. This means that by default no hidden opposites |
| * will be found and no CPU cycles will be used even for looking them up.<p> |
| * |
| * Subclasses can redefine this accordingly. See, e.g., {@link EcoreEnvironmentFactoryWithHiddenOpposites}. |
| * |
| * @since 3.1 |
| */ |
| protected OppositeEndFinder createOppositeEndFinder(EPackage.Registry registry) { |
| return null; |
| } |
| |
| /** |
| * @since 3.1 |
| */ |
| public OppositeEndFinder getOppositeEndFinder() { |
| if (oppositeEndFinder == null) { |
| oppositeEndFinder = createOppositeEndFinder(registry); |
| } |
| return oppositeEndFinder; |
| } |
| |
| /** |
| * @since 3.1 |
| */ |
| public EvaluationVisitor<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> createEvaluationVisitor( |
| Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> env, |
| EvaluationEnvironment<EClassifier, EOperation, EStructuralFeature, EClass, EObject> evalEnv, |
| Map<? extends EClass, ? extends Set<? extends EObject>> extentMap) { |
| EvaluationVisitor<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> result = new EvaluationVisitorImpl( |
| env, evalEnv, extentMap); |
| |
| if (isEvaluationTracingEnabled()) { |
| // decorate the evaluation visitor with tracing support |
| result = new TracingEvaluationVisitor(result); |
| } |
| return result; |
| } |
| |
| } |