/*******************************************************************************
* Copyright (c) 2007, 2015 Borland Software Corporation and others.
*
* 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.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.common.util.ECollections;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
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.EcoreFactory;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl;
import org.eclipse.m2m.internal.qvt.oml.common.project.Pair;
import org.eclipse.m2m.internal.qvt.oml.expressions.Module;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.DictionaryType;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.ImperativeOCLFactory;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.ImperativeOCLPackage;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.ListType;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.Typedef;
import org.eclipse.ocl.AbstractTypeResolver;
import org.eclipse.ocl.expressions.CollectionKind;
import org.eclipse.ocl.types.AnyType;
import org.eclipse.ocl.types.CollectionType;
import org.eclipse.ocl.types.TupleType;
import org.eclipse.ocl.util.TypeUtil;
import org.eclipse.ocl.utilities.UMLReflection;
/**
* Type resolver defining non-imperative operations in QVT style
*/
class BasicTypeResolverImpl
extends AbstractTypeResolver<EPackage, EClassifier, EOperation, EStructuralFeature, EParameter> {
private final Map<Pair<CollectionKind, EClassifier>, CollectionType<EClassifier, EOperation>> fCollectionTypes;
BasicTypeResolverImpl(QvtEnvironmentBase env, Resource resource) {
super(env, resource);
fCollectionTypes = new HashMap<Pair<CollectionKind,EClassifier>, CollectionType<EClassifier,EOperation>>();
}
@Override
public EClassifier resolve(EClassifier type) {
if(type instanceof ListType) {
return resolveListType(((ListType)type).getElementType());
} else if(type instanceof DictionaryType) {
DictionaryType dictType = (DictionaryType) type;
return resolveDictionaryType(dictType.getKeyType(), dictType.getElementType());
}
return super.resolve(type);
}
public ListType resolveListType(EClassifier elementType) {
ListType listType = findListType(elementType);
if(listType == null) {
// add this to QVT environment
ListType newList = QvtOperationalStdLibrary.INSTANCE.getStdlibFactory().createList(elementType);
getCollectionPackage().getEClassifiers().add(newList);
return newList;
}
return listType;
}
public DictionaryType resolveDictionaryType(EClassifier keyType, EClassifier elementType) {
DictionaryType dictionaryType = findDictionaryType(keyType, elementType);
if(dictionaryType == null) {
DictionaryType newDictionary = QvtOperationalStdLibrary.INSTANCE
.getStdlibFactory().createDictionary(keyType, elementType);
getCollectionPackage().getEClassifiers().add(newDictionary);
return newDictionary;
}
return dictionaryType;
}
private ListType findListType(EClassifier elementType) {
for (EClassifier next : getEnvironment().getUMLReflection().getClassifiers(getCollectionPackage())) {
if (next instanceof ListType) {
ListType type = (ListType) next;
if (exactCollectionTypeMatch(type.getElementType(), elementType)) {
return type;
}
}
}
return null;
}
private DictionaryType findDictionaryType(EClassifier keyType, EClassifier valueType) {
for (EClassifier next : getEnvironment().getUMLReflection().getClassifiers(getCollectionPackage())) {
if (next instanceof DictionaryType) {
DictionaryType type = (DictionaryType) next;
if (exactCollectionTypeMatch(type.getKeyType(), keyType)) {
if (exactCollectionTypeMatch(type.getElementType(), valueType)) {
return type;
}
}
}
}
return null;
}
@Override
protected CollectionType<EClassifier, EOperation> findCollectionType(CollectionKind kind, EClassifier elementType) {
Pair<CollectionKind, EClassifier> key = new Pair<CollectionKind, EClassifier>(kind, elementType);
CollectionType<EClassifier, EOperation> collectionType = fCollectionTypes.get(key);
if (collectionType != null) {
return collectionType;
}
for (EClassifier next : getEnvironment().getUMLReflection().getClassifiers(getCollectionPackage())) {
if (next instanceof CollectionType<?, ?>) {
if(next.eClass() == ImperativeOCLPackage.eINSTANCE.getDictionaryType() ||
next.eClass() == ImperativeOCLPackage.eINSTANCE.getListType()) {
// Note: QVT have unknown CollectionKind
continue;
}
@SuppressWarnings("unchecked")
CollectionType<EClassifier, EOperation> type = (CollectionType<EClassifier, EOperation>) next;
if (type.getKind() != kind) {
continue;
}
if (exactCollectionTypeMatch(type.getElementType(), elementType)) {
fCollectionTypes.put(key, type);
return type;
}
}
}
return null;
}
private boolean exactCollectionTypeMatch(EClassifier type1, EClassifier type2) {
if (TypeUtil.exactTypeMatch(getEnvironment(), type1, type2)) {
if (type1 instanceof AnyType<?> && type2 instanceof AnyType<?>) {
if (((AnyType<?>) type1).getName().equals(((AnyType<?>) type2).getName())) {
return true;
}
}
else {
return true;
}
}
return false;
}
@Override
protected Resource createResource() {
// Note: we need Ecore resource to serialize EAnnotations properly
return new EcoreResourceFactoryImpl().createResource(URI.createURI("ocl:///qvto.env.ecore")); //$NON-NLS-1$
}
@Override
protected EPackage createTuplePackage() {
EPackage result = super.createTuplePackage();
// Note: tuples supported by the central Module factory
// if(result instanceof Module == false) {
// result.setEFactoryInstance(new TupleFactory());
// }
return result;
}
@Override
protected EPackage createPackage(String name) {
QvtEnvironmentBase env = (QvtEnvironmentBase)getEnvironment();
Module module = env.getModuleContextType();
if(module != null) {
return module;
}
EPackage result = EcoreFactory.eINSTANCE.createEPackage();
result.setName(name);
getResource().getContents().add(result);
return result;
}
@Override
protected EPackage findPackage(String name) {
EPackage result = null;
for (EObject o : getResource().getContents()) {
if (o instanceof EPackage) {
EPackage epkg = (EPackage) o;
if (name.equals(epkg.getName())) {
if(epkg instanceof Module) {
// go on looking up, as this was
continue;
}
result = epkg;
break;
}
}
}
return result;
}
@Override
protected void addClassifier(EPackage pkg, EClassifier classifier) {
pkg.getEClassifiers().add(classifier);
}
@Override
protected void addOperation(EClassifier owner, EOperation operation) {
((EClass) owner).getEOperations().add(operation);
}
@Override
protected void addProperty(EClassifier owner, EStructuralFeature property) {
((EClass) owner).getEStructuralFeatures().add(property);
}
List<EOperation> getAllCompatibleAdditionalOperations(org.eclipse.ocl.ecore.CollectionType type) {
// List<EOperation> result = null;
// if (hasAdditionalFeatures()) {
// EPackage pkg = getAdditionalFeaturesPackage();
// if (pkg != null) {
// UMLReflection<EPackage, EClassifier, EOperation, EStructuralFeature, ?, EParameter, ?, ?, ?, ?> uml = getEnvironment().getUMLReflection();
// List<EClassifier> shadowOwners = uml.getClassifiers(pkg);
// for (EClassifier next : shadowOwners) {
// EClassifier shadowedType = getShadowedClassifier(next);
//
// if (shadowedType instanceof org.eclipse.ocl.ecore.CollectionType &&
// TypeUtil.compatibleTypeMatch(getEnvironment(), type, shadowedType)) {
//
// if(result == null) {
// result = new ArrayList<EOperation>();
// }
// result.addAll(uml.getOperations(next));
// }
// }
// }
// }
//
// return (result != null) ? Collections.<EOperation>unmodifiableList(result) : ECollections.<EOperation>emptyEList();
if (hasAdditionalFeatures()) {
UMLReflection<EPackage, EClassifier, EOperation, EStructuralFeature, ?, EParameter, ?, ?, ?, ?> uml = getEnvironment().getUMLReflection();
EClassifier eClassifier = ShadowClassAdapter.getShadowToBaseMap(getAdditionalFeaturesPackage()).get(type);
return uml.getOperations(eClassifier);
}
return ECollections.<EOperation>emptyEList();
}
@Override
protected EClass createShadowClass(EClassifier type) {
Typedef typeDef = ImperativeOCLFactory.eINSTANCE.createTypedef();
typeDef.setName(type.getName());
typeDef.setBase(type);
EPackage pkg = getAdditionalFeaturesPackage();
ShadowClassAdapter.getShadowToBaseMap(pkg).put(type, typeDef);
return typeDef;
}
@Override
protected EClassifier getShadowedClassifier(EClassifier shadow) {
if (shadow instanceof Typedef) {
Typedef typedef = (Typedef) shadow;
return typedef.getBase();
}
return null;
}
@Override
protected EClassifier findShadowClass(EClassifier type) {
if (!hasAdditionalFeatures()) {
return null;
}
EPackage pkg = getAdditionalFeaturesPackage();
if (type instanceof TupleType) {
for (EClassifier shadowedClassifier : ShadowClassAdapter.getShadowToBaseMap(pkg).keySet()) {
if (TypeUtil.exactTypeMatch(getEnvironment(), type, shadowedClassifier)) {
return ShadowClassAdapter.getShadowToBaseMap(pkg).get(shadowedClassifier);
}
}
}
return ShadowClassAdapter.getShadowToBaseMap(pkg).get(type);
}
private static class ShadowClassAdapter extends AdapterImpl {
final Map<EClassifier, EClassifier> fShadowToBase = new LinkedHashMap<EClassifier, EClassifier>();
Map<EClassifier, EClassifier> getShadowToBaseMap() {
return fShadowToBase;
}
@Override
public boolean isAdapterForType(Object type) {
if(ShadowClassAdapter.class.equals(type)) {
return true;
}
return super.isAdapterForType(type);
}
public static Map<EClassifier, EClassifier> getShadowToBaseMap(EPackage pkg) {
Adapter adapter = EcoreUtil.getAdapter(pkg.eAdapters(), ShadowClassAdapter.class);
if (adapter instanceof ShadowClassAdapter) {
return ((ShadowClassAdapter) adapter).getShadowToBaseMap();
}
ShadowClassAdapter shadowClassAdapter = new ShadowClassAdapter();
pkg.eAdapters().add(shadowClassAdapter);
return shadowClassAdapter.getShadowToBaseMap();
}
}
}