blob: 2e7e7a9d614efb2fcc567e5a84481d3d028c2165 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 Borland Software Corporation
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Borland Software Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.m2m.internal.qvt.oml.ast.env;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.util.EList;
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.resource.Resource;
import org.eclipse.m2m.internal.qvt.oml.ast.parser.HiddenElementAdapter;
import org.eclipse.m2m.internal.qvt.oml.expressions.ContextualProperty;
import org.eclipse.m2m.internal.qvt.oml.expressions.DictionaryType;
import org.eclipse.m2m.internal.qvt.oml.expressions.ImperativeOperation;
import org.eclipse.m2m.internal.qvt.oml.expressions.ListType;
import org.eclipse.m2m.internal.qvt.oml.expressions.Module;
import org.eclipse.ocl.TypeResolver;
import org.eclipse.ocl.ecore.CallOperationAction;
import org.eclipse.ocl.ecore.Constraint;
import org.eclipse.ocl.ecore.SendSignalAction;
import org.eclipse.ocl.expressions.CollectionKind;
import org.eclipse.ocl.types.CollectionType;
import org.eclipse.ocl.types.MessageType;
import org.eclipse.ocl.types.TupleType;
import org.eclipse.ocl.types.TypeType;
import org.eclipse.ocl.util.TypeUtil;
import org.eclipse.ocl.utilities.TypedElement;
import org.eclipse.ocl.utilities.UMLReflection;
/**
* QVT implementation of the {@link TypeResolver} interface.<p>
* This type of resolver takes into account element resolutions with sibling environments to
* this owning environment. (sibling fEnv, stands for imported one)
*/
public class QvtTypeResolverImpl implements QVTOTypeResolver {
private BasicTypeResolverImpl fDelegate;
private QvtEnvironmentBase fOwner;
private boolean fdefinesOclAnyFeatures;
private Map<EClassifier, List<ImperativeOperation>> fCtx2OperationMap;
private Set<EClassifier> fAdditionalTypes;
private Resource fResource;
QvtTypeResolverImpl(QvtEnvironmentBase owningEnv, Resource resource) {
if(owningEnv == null) {
throw new IllegalArgumentException();
}
fOwner = owningEnv;
fdefinesOclAnyFeatures = false;
fResource = resource;
}
protected BasicTypeResolverImpl getDelegate() {
if(fDelegate == null) {
fDelegate = createDelegate();
}
return fDelegate;
}
protected BasicTypeResolverImpl createDelegate() {
return new BasicTypeResolverImpl(getOwner(), fResource);
}
QvtEnvironmentBase getOwner() {
return fOwner;
}
/* (non-Javadoc)
* @see org.eclipse.m2m.internal.qvt.oml.ast.env.QVTOTypeResolver#resolveListType(org.eclipse.emf.ecore.EClassifier)
*/
public ListType resolveListType(EClassifier elementType) {
return getDelegate().resolveListType(elementType);
}
public DictionaryType resolveDictionaryType(EClassifier keyType, EClassifier elementType) {
return getDelegate().resolveDictionaryType(keyType, elementType);
}
public void collectAdditionalOperationsInTypeHierarchy(EClassifier type, boolean subTypesOnly, Collection<EOperation> result) {
if(fAdditionalTypes != null) {
for (EClassifier nextType : fAdditionalTypes) {
boolean isPartOfHierarchy = TypeUtil.getRelationship(fOwner, type, nextType) == UMLReflection.STRICT_SUPERTYPE;
if(type != nextType && isPartOfHierarchy) {
getLocalAdditionalOperations(nextType, result);
}
}
}
// continue in imported environments
for (QvtEnvironmentBase nextSiblingEnv : fOwner.getSiblings()) {
nextSiblingEnv.getQVTTypeResolver().collectAdditionalOperationsInTypeHierarchy(type, subTypesOnly, result);
}
}
public List<EStructuralFeature> getAdditionalAttributes(EClassifier owner) {
List<EStructuralFeature> result = new ArrayList<EStructuralFeature>();
getLocalAdditionalAttributes(owner, result);
for (QvtEnvironmentBase nextSiblingEnv : fOwner.getSiblings()) {
nextSiblingEnv.getQVTTypeResolver().getLocalAdditionalAttributes(owner, result);
}
return result;
}
protected void getLocalAdditionalAttributes(EClassifier owner, List<EStructuralFeature> result) {
extractIntermediateProperties(owner, result);
result.addAll(getDelegate().getAdditionalAttributes(owner));
}
public List<EOperation> getAdditionalOperations(EClassifier owner) {
List<EOperation> result = new ArrayList<EOperation>();
getLocalAdditionalOperations(owner, result);
for (QvtEnvironmentBase nextSiblingEnv : fOwner.getSiblings()) {
List<EOperation> ops = nextSiblingEnv.getAdditionalOperations(owner);
if(ops !=null) {
result.addAll(ops);
}
}
return result;
}
private void extractContextualOperations(EClassifier context, Collection<EOperation> result) {
if(fCtx2OperationMap == null) {
return;
}
for (EClassifier ctx : fCtx2OperationMap.keySet()) {
if (TypeUtil.exactTypeMatch(fOwner, ctx, context)) {
List<ImperativeOperation> operList = fCtx2OperationMap.get(ctx);
if(operList != null) {
result.addAll(operList);
return;
}
}
}
}
private void extractIntermediateProperties(EClassifier context, Collection<EStructuralFeature> result) {
if(context instanceof EClass) {
Module moduleType = fOwner.getModuleContextType();
if(moduleType == null) {
return;
}
for(EStructuralFeature property : moduleType.getEStructuralFeatures()) {
if(property instanceof ContextualProperty) {
if(HiddenElementAdapter.isMarkedAsHidden(property)) {
continue;
}
ContextualProperty ctxProperty = (ContextualProperty) property;
EClass nextContext = ctxProperty.getContext();
if(nextContext != null && nextContext == context) {
result.add(ctxProperty);
}
}
}
}
}
protected void getLocalAdditionalOperations(EClassifier owner, Collection<EOperation> result) {
extractContextualOperations(owner, result);
final boolean isCollectionTypeOwner = owner instanceof CollectionType;
if(fdefinesOclAnyFeatures && (isCollectionTypeOwner == false) && (owner instanceof TupleType == false)) {
extractContextualOperations(fOwner.getOCLStandardLibrary().getOclAny(), result);
}
result.addAll(getDelegate().getAdditionalOperations(owner));
if(fdefinesOclAnyFeatures && (isCollectionTypeOwner == false) && (owner instanceof TupleType == false)) {
result.addAll(getDelegate().getAdditionalOperations(fOwner.getOCLStandardLibrary().getOclAny()));
}
if(owner == fOwner.getOCLStandardLibrary().getInteger()) {
EClassifier oclReal = fOwner.getOCLStandardLibrary().getReal();
this.getLocalAdditionalOperations(oclReal, result);
} else if(isCollectionTypeOwner) {
getLocalCollectionAdditionalOperations((org.eclipse.ocl.ecore.CollectionType)owner, result, false);
}
}
public Resource getResource() {
if(fResource != null) {
return fResource;
}
return getDelegate().getResource();
}
public EClassifier resolve(EClassifier type) {
return getDelegate().resolve(type);
}
public EStructuralFeature resolveAdditionalAttribute(EClassifier owner, EStructuralFeature property) {
return getDelegate().resolveAdditionalAttribute(owner, property);
}
public EOperation resolveAdditionalOperation(EClassifier owner, EOperation operation) {
if(!fdefinesOclAnyFeatures && owner == fOwner.getOCLStandardLibrary().getOclAny()) {
// operations defined on OclAny;
fdefinesOclAnyFeatures = true;
}
if(operation instanceof ImperativeOperation) {
if(fCtx2OperationMap == null) {
fCtx2OperationMap = new HashMap<EClassifier, List<ImperativeOperation>>();
}
List<ImperativeOperation> operList = fCtx2OperationMap.get(owner);
if(operList == null) {
operList = new ArrayList<ImperativeOperation>();
fCtx2OperationMap.put(owner, operList);
}
addAdditionalType(owner);
operList.add((ImperativeOperation)operation);
return operation;
}
EOperation resolve = getDelegate().resolveAdditionalOperation(owner, operation);
if(resolve != null) {
addAdditionalType(owner);
}
return resolve;
}
public CollectionType<EClassifier, EOperation> resolveCollectionType(
CollectionKind kind, EClassifier elementType) {
return getDelegate().resolveCollectionType(kind, elementType);
}
public MessageType<EClassifier, EOperation, EStructuralFeature> resolveOperationMessageType(
EOperation operation) {
return getDelegate().resolveOperationMessageType(operation);
}
public MessageType<EClassifier, EOperation, EStructuralFeature> resolveSignalMessageType(
EClassifier signal) {
return getDelegate().resolveSignalMessageType(signal);
}
public TupleType<EOperation, EStructuralFeature> resolveTupleType(
EList<? extends TypedElement<EClassifier>> parts) {
return getDelegate().resolveTupleType(parts);
}
public TypeType<EClassifier, EOperation> resolveTypeType(EClassifier type) {
return getDelegate().resolveTypeType(type);
}
UMLReflection<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint> uml() {
return fOwner.getUMLReflection();
}
private void addAdditionalType(EClassifier type) {
if(fAdditionalTypes == null) {
fAdditionalTypes = new HashSet<EClassifier>();
}
fAdditionalTypes.add(type);
}
void getLocalCollectionAdditionalOperations(org.eclipse.ocl.ecore.CollectionType collectionType, Collection<EOperation> result, boolean includeSuperTypes) {
if(fAdditionalTypes == null) {
return;
}
for (EClassifier nextType : fAdditionalTypes) {
if(nextType instanceof org.eclipse.ocl.ecore.CollectionType) {
boolean isMatchingType = (includeSuperTypes) ?
TypeUtil.compatibleTypeMatch(fOwner, collectionType, nextType) :
TypeUtil.exactTypeMatch(fOwner, collectionType, nextType);
if(isMatchingType) {
extractContextualOperations(nextType, result);
result.addAll(fDelegate.getAllCompatibleAdditionalOperations(
(org.eclipse.ocl.ecore.CollectionType)nextType));
}
}
}
}
@Override
public String toString() {
return getClass().getSimpleName() + " : " + fOwner.toString();
}
}