blob: a19d83770e6055e7bcd2f560d36b2342cbc30878 [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
*******************************************************************************/
package org.eclipse.ocl.uml;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.ecore.EClass;
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.ocl.AbstractEnvironmentFactory;
import org.eclipse.ocl.Environment;
import org.eclipse.ocl.EnvironmentFactory;
import org.eclipse.ocl.EvaluationEnvironment;
import org.eclipse.ocl.helper.OCLHelper;
import org.eclipse.ocl.uml.internal.OCLStandardLibraryImpl;
import org.eclipse.ocl.uml.util.OCLUMLUtil;
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.InstanceSpecification;
import org.eclipse.uml2.uml.InstanceValue;
import org.eclipse.uml2.uml.LiteralBoolean;
import org.eclipse.uml2.uml.LiteralInteger;
import org.eclipse.uml2.uml.LiteralString;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Parameter;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.SendSignalAction;
import org.eclipse.uml2.uml.State;
import org.eclipse.uml2.uml.ValueSpecification;
/**
* Implementation of the {@link EnvironmentFactory} for parsing OCL expressions
* on UML models.
* <p>
* The parser environments created by the UML environment factory support OCL
* expressions at both the metamodel (M2) and user model (M1) levels. For
* user model constraints, use the classifier in the model as the context
* classifier in invocations of an {@link OCL} or an {@link OCLHelper}
* created by it. For metamodel OCL (used, for example, to query the user
* model, itself) use the metaclass of any element in the user model as the
* context classifier. A convenient way to obtain this metaclass is via the
* {@link OCLUMLUtil#getMetaclass(org.eclipse.uml2.uml.Element)} method.
* </p>
*
* @author Christian W. Damus (cdamus)
*/
public class UMLEnvironmentFactory
extends AbstractEnvironmentFactory<
Package, Classifier, Operation, Property,
EnumerationLiteral, Parameter,
State, CallOperationAction, SendSignalAction, Constraint,
Class, EObject> {
private final EPackage.Registry registry;
private final ResourceSet resourceSet;
private Package umlMetamodel;
// cache of EClass to UML Classfier
private Map<EClass, Classifier> eclassToClassifierMap =
new java.util.HashMap<EClass, Classifier>();
private Map<List<String>, Package> packageCache =
new java.util.HashMap<List<String>, Package>();
/**
* Initializes me. Environments that I create will use a private resource
* set and its package registry to look up UML packages and their Ecore
* definitions.
*/
public UMLEnvironmentFactory() {
this(new ResourceSetImpl());
}
/**
* Initializes me with a resource set that the environments I create
* will use (along with its package registry) to look up UML packages and
* their Ecore definitions.
*
* @param rset my resource set (must not by <code>null</code>)
*/
public UMLEnvironmentFactory(ResourceSet rset) {
this(rset.getPackageRegistry(), rset);
}
/**
* Initializes me with a resource set and package registry that the
* environments I create will use to look up UML packages and
* their Ecore definitions.
*
* @param registry my package registry (must not be <code>null</code>)
* @param rset my resource set (must not be <code>null</code>)
*/
public UMLEnvironmentFactory(EPackage.Registry registry, ResourceSet rset) {
super();
this.registry = registry;
this.resourceSet = rset;
}
// implements the inherited specification
public UMLEnvironment createEnvironment() {
UMLEnvironment result = new UMLEnvironment(registry, resourceSet);
result.setFactory(this);
return result;
}
// implements the inherited specification
public Environment<Package, Classifier, Operation, Property, EnumerationLiteral, Parameter, State, CallOperationAction, SendSignalAction, Constraint, Class, EObject> loadEnvironment(
Resource resource) {
UMLEnvironment result = new UMLEnvironment(registry, resourceSet, resource);
result.setFactory(this);
return result;
}
/**
* Obtains the package registry that the environment I create will use to
* look up the Ecore definitions of UML packages.
*
* @return my package registry
*/
public final EPackage.Registry getEPackageRegistry() {
return registry;
}
/**
* Obtains the resource set that the environment I create will use to
* find UML packages.
*
* @return my resource set
*/
public 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) {
umlMetamodel = OCLUMLUtil.getUMLMetamodel(getResourceSet());
}
return umlMetamodel;
}
// implements the inherited specification
@Override
protected Package lookupPackage(List<String> pathname) {
Package result = packageCache.get(pathname);
if (result == null) {
result = OCLUMLUtil.findPackage(pathname, resourceSet);
packageCache.put(pathname, result);
}
return result;
}
// implements the inherited specification
@Override
protected Classifier getClassifier(Object context) {
Classifier result;
if (context instanceof InstanceSpecification) {
InstanceSpecification instance = (InstanceSpecification) context;
if (!instance.getClassifiers().isEmpty()) {
result = instance.getClassifiers().get(0);
} else {
// unclassified instance specification
result = OCLStandardLibraryImpl.INSTANCE.getOclAny();
}
} else if (context instanceof ValueSpecification) {
if (context instanceof InstanceValue) {
result = getClassifier(((InstanceValue) context).getInstance());
} else if (context instanceof LiteralBoolean) {
result = OCLStandardLibraryImpl.INSTANCE.getBoolean();
} else if (context instanceof LiteralString) {
result = OCLStandardLibraryImpl.INSTANCE.getString();
} else if (context instanceof LiteralInteger) {
result = OCLStandardLibraryImpl.INSTANCE.getInteger();
} else { // TODO: Should OCL add a LiteralReal value specification?
result = OCLStandardLibraryImpl.INSTANCE.getOclAny();
}
} else if (context instanceof EObject) {
// an instance of a metaclass that was modeled in UML and
// generated to code?
EClass eclass = ((EObject) context).eClass();
result = eclassToClassifierMap.get(eclass);
if (result == null) {
result = OCLUMLUtil.getClassifier(eclass, resourceSet);
if (result == null) {
// cache the failed lookup for next time
result = OCLStandardLibraryImpl.INSTANCE.getOclAny();
}
eclassToClassifierMap.put(eclass, result);
}
} else {
// maybe it's an instance of a standard data type?
if (context instanceof String) {
result = OCLStandardLibraryImpl.INSTANCE.getString();
} else if (context instanceof Boolean) {
result = OCLStandardLibraryImpl.INSTANCE.getBoolean();
} else if (context instanceof Integer) {
result = OCLStandardLibraryImpl.INSTANCE.getInteger();
} else if (context instanceof Double) {
result = OCLStandardLibraryImpl.INSTANCE.getReal();
} else {
// it's just some weirdo object that we don't understand
result = OCLStandardLibraryImpl.INSTANCE.getOclAny();
}
}
return result;
}
// implements the inherited specification
public Environment<Package, Classifier, Operation, Property, EnumerationLiteral, Parameter, State, CallOperationAction, SendSignalAction, Constraint, Class, EObject>
createEnvironment(
Environment<Package, Classifier, Operation, Property, EnumerationLiteral, Parameter, State, CallOperationAction, SendSignalAction, Constraint, Class, EObject> parent) {
if (!(parent instanceof UMLEnvironment)) {
throw new IllegalArgumentException(
"Parent environment must be a UML environment: " + parent); //$NON-NLS-1$
}
UMLEnvironment result = new UMLEnvironment(parent);
result.setFactory(this);
return result;
}
// implements the inherited specification
public EvaluationEnvironment<Classifier, Operation, Property, Class, EObject> createEvaluationEnvironment() {
return new UMLEvaluationEnvironment(this);
}
// implements the inherited specification
public EvaluationEnvironment<Classifier, Operation, Property, Class, EObject>
createEvaluationEnvironment(
EvaluationEnvironment<Classifier, Operation, Property, Class, EObject> parent) {
return new UMLEvaluationEnvironment(parent);
}
}