/** * Copyright (c) 2014 committers of YAKINDU 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: * committers of YAKINDU - initial API and implementation * */ package org.yakindu.base.types.typesystem; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.impl.ResourceImpl; import org.eclipse.emf.ecore.util.EcoreUtil; import org.yakindu.base.types.ComplexType; import org.yakindu.base.types.Operation; import org.yakindu.base.types.PrimitiveType; import org.yakindu.base.types.Property; import org.yakindu.base.types.Type; import org.yakindu.base.types.TypesFactory; import org.yakindu.base.types.annotations.TypeAnnotations; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; /** * Abstract base implementation if {@link ITypeSystem}. Provides convenience * methods to determine type compatibility. * * @author andreas muelder - Initial contribution and API * */ public abstract class AbstractTypeSystem implements ITypeSystem { protected Map<String, Type> typeRegistry = new HashMap<String, Type>(); protected ListMultimap<Type, Type> extendsRegistry = ArrayListMultimap.create(); protected ListMultimap<Type, Operation> extensionOperationRegistry = ArrayListMultimap.create(); protected ListMultimap<Type, Property> extensionPropertyRegistry = ArrayListMultimap.create(); protected Map<Type, Type> conversionRegistry = new HashMap<Type, Type>(); protected abstract void initRegistries(); protected Resource resource; protected TypeAnnotations typeAnnotations; public AbstractTypeSystem() { resource = new ResourceImpl(URI.createURI("types")); typeAnnotations = new TypeAnnotations(); initRegistries(); } protected void reset() { typeRegistry.clear(); extendsRegistry.clear(); conversionRegistry.clear(); } public Type getType(String type) { Type result = typeRegistry.get(type); return result; } public List<Type> getSuperTypes(Type type) { List<Type> superTypes = new ArrayList<Type>(); for (Entry<Type, Type> entry : extendsRegistry.entries()) { if (isSame(type, entry.getKey())) { superTypes.add(entry.getValue()); } } if (type instanceof ComplexType) { ComplexType complexType = (ComplexType) type; superTypes.addAll(complexType.getSuperTypes()); } return superTypes; } public boolean isSuperType(Type subtype, Type supertype) { List<Type> typehierachy = new ArrayList<Type>(); typehierachy.add(subtype); collectSupertypes(subtype, typehierachy); for (Type eObject : typehierachy) { if (isSame(eObject, supertype)) return true; } return false; } private void collectSupertypes(Type subtypeClass, List<Type> typeHierachy) { if (subtypeClass == null) return; List<Type> superTypes = getSuperTypes(subtypeClass); for (Type superType : superTypes) { typeHierachy.add(superType); collectSupertypes(superType, typeHierachy); } } public Collection<Type> getTypes() { return Collections.unmodifiableCollection(typeRegistry.values()); } public Collection<Type> getConcreteTypes() { List<Type> result = new ArrayList<Type>(); for (Type type : getTypes()) { if (!type.isAbstract()) result.add(type); } return result; } protected Type declarePrimitive(String name) { PrimitiveType primitive = TypesFactory.eINSTANCE.createPrimitiveType(); primitive.setName(name); declareType(primitive, name); resource.getContents().add(primitive); return primitive; } public void declareType(Type type, String name) { typeRegistry.put(name, type); } public void removeType(String name) { Type type = typeRegistry.get(name); if (type != null) { extendsRegistry.removeAll(type); resource.getContents().remove(type); typeRegistry.remove(type); } } public void declareSuperType(Type subType, Type superType) { extendsRegistry.put(subType, superType); } public void declareConversion(Type baseType, Type targetType) { conversionRegistry.put(baseType, targetType); } public boolean haveCommonType(Type type1, Type type2) { return getCommonType(type1, type2) != null; } public boolean isSame(Type type1, Type type2) { return EcoreUtil.equals(type1, type2); } public Type getCommonType(Type type1, Type type2) { Type result = getCommonTypeInternal(type1, type2); if (result != null) return result; return null; } @Override public boolean haveCommonTypeWithConversion(Type type1, Type type2) { return getCommonTypeWithConversion(type1, type2) != null; } public Type getCommonTypeWithConversion(Type type1, Type type2) { Type result = getCommonType(type1, type2); if (result != null) return result; Type conversionType1 = getConversionType(type1); if (conversionType1 != null) { result = getCommonTypeInternal(conversionType1, type2); if (result != null) return result; } Type conversionType2 = getConversionType(type2); if (conversionType2 != null) return getCommonTypeInternal(type1, conversionType2); return null; } private Type getCommonTypeInternal(Type type1, Type type2) { if (isSame(type1, type2)) return type1; if (isSuperType(type1, type2)) { return type2; } if (isSuperType(type2, type1)) return type1; List<Type> typehierachy1 = new ArrayList<Type>(); collectSupertypes(type1, typehierachy1); List<Type> typehierachy2 = new ArrayList<Type>(); collectSupertypes(type2, typehierachy2); for (Type type : typehierachy1) { if (typehierachy2.contains(type)) { return type; } } for (Type type : typehierachy2) { if (typehierachy1.contains(type)) { return type; } } return null; } protected Type getConversionType(Type sourceType) { return conversionRegistry.get(sourceType); } public Resource getResource() { return resource; } @Override public boolean isBuiltInType(Type type) { return typeAnnotations.hasBuiltInTypeAnnotation(type); } @Override public List<Operation> getOperationExtensions(Type type) { List<Operation> result = new ArrayList<>(); result.addAll(extensionOperationRegistry.get(type)); List<Type> superTypes = getSuperTypes(type); for (Type superType : superTypes) { result.addAll(extensionOperationRegistry.get(superType)); } return result; } @Override public boolean isExtensionOperation(Operation op) { return extensionOperationRegistry.containsValue(op); } @Override public List<Property> getPropertyExtensions(Type type) { List<Property> result = new ArrayList<>(); result.addAll(extensionPropertyRegistry.get(type)); List<Type> superTypes = getSuperTypes(type); for (Type superType : superTypes) { result.addAll(extensionPropertyRegistry.get(superType)); } return result; } @Override public boolean isExtensionProperty(Property prop) { return extensionPropertyRegistry.containsValue(prop); } }