blob: 396a70902ada041273d963f20e6136c2f4975404 [file] [log] [blame]
/*******************************************************************************
* 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;
}
}