From 7b40388ea6bb96ab3adacf338b1bc30d06474df4 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Wed, 24 Jan 2018 11:42:29 +0100 Subject: Loading services --- .../application/execution/Context.xtend | 4 - .../application/execution/MetamodelLoader.xtend | 220 ++++++++------------- .../application/execution/QueryLoader.xtend | 124 ++++++++++-- .../execution/validation/MetamodelValidator.xtend | 76 +++++++ .../validation/QueryAndMetamodelValidator.xtend | 53 +++++ 5 files changed, 327 insertions(+), 150 deletions(-) create mode 100644 Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/validation/MetamodelValidator.xtend create mode 100644 Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/validation/QueryAndMetamodelValidator.xtend (limited to 'Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme') diff --git a/Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/Context.xtend b/Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/Context.xtend index 8f72caed..c00c0d31 100644 --- a/Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/Context.xtend +++ b/Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/Context.xtend @@ -1,9 +1,5 @@ package hu.bme.mit.inf.dslreasoner.application.execution -import java.io.OutputStream -import java.util.LinkedList -import java.util.List -import java.io.FileWriter import org.eclipse.xtend.lib.annotations.Accessors class Context { diff --git a/Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/MetamodelLoader.xtend b/Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/MetamodelLoader.xtend index 126dbb7d..e554cc69 100644 --- a/Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/MetamodelLoader.xtend +++ b/Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/MetamodelLoader.xtend @@ -1,15 +1,10 @@ package hu.bme.mit.inf.dslreasoner.application.execution -import hu.bme.mit.inf.dslreasoner.application.applicationConfiguration.ClassElement -import hu.bme.mit.inf.dslreasoner.application.applicationConfiguration.FeatureElement -import hu.bme.mit.inf.dslreasoner.application.applicationConfiguration.MetamodelEntry import hu.bme.mit.inf.dslreasoner.application.applicationConfiguration.MetamodelSpecification import hu.bme.mit.inf.dslreasoner.ecore2logic.EcoreMetamodelDescriptor import java.util.ArrayList -import java.util.HashMap import java.util.LinkedList import java.util.List -import java.util.Map import java.util.Set import org.eclipse.emf.common.util.URI import org.eclipse.emf.ecore.EAttribute @@ -24,13 +19,11 @@ import org.eclipse.emf.ecore.EcorePackage import org.eclipse.emf.ecore.resource.Resource import org.eclipse.emf.ecore.resource.ResourceSet import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl -import org.eclipse.xtend.lib.annotations.Data - -@Data -class Metamodel { - List packages - EcoreMetamodelDescriptor descriptor -} +import hu.bme.mit.inf.dslreasoner.application.applicationConfiguration.AllPackageEntry +import hu.bme.mit.inf.dslreasoner.application.applicationConfiguration.MetamodelElement +import org.eclipse.xtext.xbase.lib.Functions.Function1 +import hu.bme.mit.inf.dslreasoner.application.applicationConfiguration.MetamodelEntry +import java.util.LinkedHashSet class MetamodelLoader { @@ -41,138 +34,97 @@ class MetamodelLoader { public new() { init } - def loadMetamodel(List specification, ResourceSet rs, Context context) { - - } - - def loadMetamodel(MetamodelSpecification specification, ResourceSet rs, Context context) { - val Map> entry2Packages = new HashMap + def loadMetamodel(MetamodelSpecification specification, ResourceSet rs) throws IllegalArgumentException { + + val Set classes = new LinkedHashSet + val Set enums = new LinkedHashSet + val Set literals = new LinkedHashSet + val Set references = new LinkedHashSet + val Set attributes = new LinkedHashSet + /** Add all included types */ for(entry : specification.entries) { - val packagesInEntry = entry.path.path.loadPackageFromPath(rs,context) - entry2Packages.put(entry,packagesInEntry) + classes+=entry.classes + enums+=entry.enums + literals+=entry.literals + references+=entry.references + attributes+=entry.attributes } - return entry2Packages + return new EcoreMetamodelDescriptor(classes.toList, emptySet, false, enums.toList, literals.toList, references.toList, attributes.toList) } - public def pruneMetamodel(Map> specification, ResourceSet rs, Context context) { - val List classes = new LinkedList - val List enums = new LinkedList - val List literals = new LinkedList - val List references = new LinkedList - val List attributes = new LinkedList - - - /** Add all included types */ - for(entry : specification.entrySet) { - val metamodelEntry = entry.key - val packages = entry.value - - /** Excluted types */ - val excludedTypeNames = metamodelEntry.excluding.filter(ClassElement).map[name].toSet - /** Excluded features */ - val excludedFeatureNames = metamodelEntry.excluding.filter(FeatureElement).map[it.container.name -> it.name].toSet - - /** Load the types */ - for(package : packages) { - for(class : package.EClassifiers.filter(EClass)) { - classes.addIfNotExcluded(class,excludedTypeNames) - } - for(enum : package.EClassifiers.filter(EEnum)) { - val added = enums.addIfNotExcluded(enum,excludedTypeNames) - if(added) { - for(literal : enum.ELiterals) { - literals.addIfNotExcluded(literal,enum,excludedFeatureNames) - } - } - } - } - } - - /** Add all included references and attributes*/ - for(entry : specification.entrySet) { - val metamodelEntry = entry.key - val packages = entry.value - - /** Excluded features */ - val excludedFeatureNames = metamodelEntry.excluding.filter(FeatureElement).map[it.container.name -> it.name].toSet - - /** See if type is included */ - for(package : packages) { - for(class : package.EClassifiers.filter(EClass)) { - if(classes.contains(class)) { - for(reference : class.EReferences) { - if(classes.contains(reference.EType)) { - references.addIfNotExcluded(reference,class,excludedFeatureNames) - } - } - for(attribute : class.EAttributes) { - val type = attribute.EType - if(type instanceof EEnum) { - if(enums.contains(type)) { - attributes.addIfNotExcluded(attribute,class,excludedFeatureNames) - } else if(type == EcorePackage.Literals) { - if(enums.contains(type)) { - attributes.addIfNotExcluded(attribute,class,excludedFeatureNames) - } - } - } else if(supportedEDataType(type as EDataType)) { - attributes.addIfNotExcluded(attribute,class,excludedFeatureNames) - } - } - } - } - } - } + def List extractElements(MetamodelEntry entry, Function1> packageEntryExtractor, Function1> metamodelElementExtractor) { + if(entry instanceof MetamodelElement) { + return metamodelElementExtractor.apply(entry).toList + } else if(entry instanceof AllPackageEntry) { + val excluded = entry.exclusion.map[metamodelElementExtractor.apply(it)].flatten.toSet + return packageEntryExtractor.apply(entry).filter[!excluded.contains(it)].toList + } else throw new IllegalArgumentException('''Unsupported entry type: "«entry.class.simpleName»"!''') } - private def supportedEDataType(EDataType dataType) { - val extension l = EcorePackage.eINSTANCE - return #[EInt, EBoolean, EString, EDouble, EFloat].contains(dataType) + def getClasses(MetamodelEntry entry) { + return entry.extractElements( + [package.EClassifiers.filter(EClass)], + [val classifier = it.classifier + if(classifier instanceof EClass){ if(it.feature === null) { return #[classifier]} } + return emptyList + ] + ) } - - private def addIfNotExcluded( - List target, - T element, - Set excluded) - { - if(excluded.contains(element.name)) { - target += element - return true - } else { - return false - } + def getEnums(MetamodelEntry entry) { + return entry.extractElements( + [package.EClassifiers.filter(EEnum)], + [val classifier = it.classifier + if(classifier instanceof EEnum){ if(it.feature === null) { return #[classifier]} } + return emptyList + ] + ) } - private def addIfNotExcluded( - List target, - T1 element, - ENamedElement container, - Set> excluded) - { - val pair = (container.name) -> (element.name) - - if(excluded.contains(pair)) { - target += element - } + def getLiterals(MetamodelEntry entry) { + return entry.extractElements( + [package.EClassifiers.filter(EEnum).map[ELiterals].flatten], + [val feature = it.feature + if(feature instanceof EEnumLiteral){ return #[feature] } + return emptyList + ] + ) } - - private def List loadPackageFromPath(String path, ResourceSet rs, Context context) throws RuntimeException { - var Resource resource; - try{ - resource = rs.getResource(URI.createURI(path),true) - } catch(RuntimeException e) { - context.writeError('''Unable to load EPackage: Error in path "«path»"!''') - return #[] - } - val res = new ArrayList(resource.contents.size) - for(content: resource.contents) { - if(content instanceof EPackage) { - res += content - } else { - context.writeError('''Unable to load EPackage: The content of "«path»" is not an EPackage, but "«content.eClass.name»"!''') - } - } - return res + def getReferences(MetamodelEntry entry) { + return entry.extractElements( + [package.EClassifiers.filter(EClass).map[EReferences].flatten], + [val feature = it.feature + if(feature instanceof EReference) { return #[feature] } + return emptyList + ] + ) } + def getAttributes(MetamodelEntry entry) { + return entry.extractElements( + [package.EClassifiers.filter(EClass).map[EAttributes].flatten], + [val feature = it.feature + if(feature instanceof EAttribute) {return #[feature]} + return emptyList + ] + ) + } + +// public def List loadPackageFromPath(String path, ResourceSet rs, Context context) throws RuntimeException { +// var Resource resource; +// try{ +// resource = rs.getResource(URI.createURI(path),true) +// } catch(RuntimeException e) { +// context.writeError('''Unable to load EPackage: Error in path "«path»"!''') +// return #[] +// } +// val res = new ArrayList(resource.contents.size) +// for(content: resource.contents) { +// if(content instanceof EPackage) { +// res += content +// } else { +// context.writeError('''Unable to load EPackage: The content of "«path»" is not an EPackage, but "«content.eClass.name»"!''') +// } +// } +// return res +// } } \ No newline at end of file diff --git a/Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/QueryLoader.xtend b/Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/QueryLoader.xtend index 8c064cd3..6e725086 100644 --- a/Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/QueryLoader.xtend +++ b/Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/QueryLoader.xtend @@ -1,28 +1,128 @@ package hu.bme.mit.inf.dslreasoner.application.execution +import hu.bme.mit.inf.dslreasoner.application.applicationConfiguration.AllPatternEntry +import hu.bme.mit.inf.dslreasoner.application.applicationConfiguration.ConfigurationScript +import hu.bme.mit.inf.dslreasoner.application.applicationConfiguration.PatternElement +import hu.bme.mit.inf.dslreasoner.application.applicationConfiguration.PatternEntry import hu.bme.mit.inf.dslreasoner.application.applicationConfiguration.PatternSpecification -import hu.bme.mit.inf.dslreasoner.application.execution.util.VQLParser -import java.util.LinkedHashMap -import org.eclipse.emf.ecore.resource.ResourceSet +import hu.bme.mit.inf.dslreasoner.application.applicationConfiguration.ViatraImport +import hu.bme.mit.inf.dslreasoner.viatra2logic.ViatraQuerySetDescriptor +import java.util.HashMap +import java.util.LinkedHashSet +import java.util.List +import java.util.Set +import org.eclipse.emf.ecore.EClass +import org.eclipse.emf.ecore.EPackage +import org.eclipse.viatra.query.patternlanguage.emf.eMFPatternLanguage.PatternModel +import org.eclipse.viatra.query.patternlanguage.emf.specification.SpecificationBuilder +import org.eclipse.viatra.query.patternlanguage.patternLanguage.Pattern +import org.eclipse.viatra.query.patternlanguage.patternLanguage.PatternCompositionConstraint +import org.eclipse.viatra.query.runtime.api.IQuerySpecification +import org.eclipse.xtext.EcoreUtil2 import static extension hu.bme.mit.inf.dslreasoner.util.CollectionsUtil.* class QueryLoader { - val parser = new VQLParser + //val parser = new VQLParser + val builder = new SpecificationBuilder - def loadQueries(PatternSpecification specification, ResourceSet rs, Context context) { - val uris = specification.entries.map[path].toList - val models = parser.parse(uris,rs,context) + def loadQueries(PatternSpecification specification) { + val patterns = new LinkedHashSet - val res = new LinkedHashMap - for(entry : specification.entries) { - res.put(entry,entry.path.lookup(models)) + for(entry: specification.entries) { + patterns += getPatterns(entry) } - return res + val allConcernedPatterns = patterns.allReferredPatterns + val pattern2Specification = allConcernedPatterns.translatePatterns() + + val List> patternsToTranslate = + pattern2Specification.values.toList + val Set> validationPatterns = + patterns.filter[it.annotations.exists[it.name.equals("Constraint")]] + .map[lookup(pattern2Specification)] + .toSet + val derivedFeatures = calculateDerivedFeatures(patterns.referredEcoreModels,patterns.map[it.lookup(pattern2Specification)]) + + return new ViatraQuerySetDescriptor( + patternsToTranslate, + validationPatterns, + derivedFeatures + ) -> allConcernedPatterns } - def pruneQueries(PatternSpecification specification, ResourceSet rs, Context context) { + def dispatch List getPatterns(AllPatternEntry entry) { + val excluded = entry.exclusuion.map[getPatterns] + val referredPatternModels = allPatternsWithSamePackage(entry,entry.package as PatternModel).toSet + val patterns = referredPatternModels.map[patterns].flatten + return patterns.filter[!excluded.contains(it)].toList + } + + def dispatch List getPatterns(PatternElement entry) { + return #[entry.pattern] + } + + def private allPatternsWithSamePackage(PatternEntry entry, PatternModel model) { + val packageURI = model.packageName + val document = EcoreUtil2.getContainerOfType(entry,ConfigurationScript) + val viatraImportsWithSamePackage = document.imports + .filter(ViatraImport) + .map[it.importedViatra] + .filterNull + .filter[packageName.equals(packageURI)] + return viatraImportsWithSamePackage + } + + /** + * Adds all referred patterns to a given set of patterns. + */ + def private Set allReferredPatterns(Set patterns) { + val res = new LinkedHashSet + res+=patterns + var boolean changed + do{ + changed = false + val newElements = res.map[directlyReferredPatterns].flatten.filter[!res.contains(it)] + if(!newElements.empty) { + changed = true + res.addAll(newElements) + } + } while(changed) + + return res + } + + def private directlyReferredPatterns(Pattern pattern) { + return pattern + .bodies + .map[constraints] + .flatten + .filter(PatternCompositionConstraint) + .map[call.patternRef].toSet + } + + def private referredEcoreModels(Set patterns) { + patterns.map[eContainer as PatternModel].map[it.importPackages.packageImport.map[it.EPackage].filterNull].flatten.toSet + } + + def private translatePatterns(Set xtextPattern) { + xtextPattern.toInvertedMap[builder.getOrCreateSpecification(it) as IQuerySpecification] + } + + def private calculateDerivedFeatures(Set packages, Iterable> patterns) { + val features = packages.map[EClassifiers].flatten.filter(EClass).map[it.EStructuralFeatures].flatten + val res = new HashMap + for(feature : features) { + val QBFAnnotation = feature.EAnnotations.filter[it.source.equals("org.eclipse.viatra.query.querybasedfeature")].head + if(QBFAnnotation !== null) { + val targetFQN = QBFAnnotation.details.get("patternFQN") + val referredPattern = patterns.filter[it.fullyQualifiedName.equals(targetFQN)].head + if(referredPattern!== null) { + res.put(referredPattern, feature) + } + } + } + return res } } \ No newline at end of file diff --git a/Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/validation/MetamodelValidator.xtend b/Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/validation/MetamodelValidator.xtend new file mode 100644 index 00000000..aae47c83 --- /dev/null +++ b/Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/validation/MetamodelValidator.xtend @@ -0,0 +1,76 @@ +package hu.bme.mit.inf.dslreasoner.application.execution.validation + +import hu.bme.mit.inf.dslreasoner.ecore2logic.EcoreMetamodelDescriptor +import java.util.LinkedList +import java.util.List +import org.eclipse.emf.ecore.EAttribute +import org.eclipse.emf.ecore.EClass +import org.eclipse.emf.ecore.EDataType +import org.eclipse.emf.ecore.EEnum +import org.eclipse.emf.ecore.EEnumLiteral +import org.eclipse.emf.ecore.EReference +import org.eclipse.emf.ecore.EcorePackage + +class MetamodelValidator { + def validateMetamodel(EcoreMetamodelDescriptor descriptor) { + val errors = new LinkedList + this.allSupertypesAreIncluded(descriptor.classes,errors) + this.allEnumTypesareIncluded(descriptor.enums,descriptor.literals,errors) + this.referenceEndpointsAreIncluded(descriptor.classes,descriptor.references,errors) + this.attributeSourcePontIsIncluded(descriptor.classes,descriptor.attributes,errors) + this.attributeTargetIsSupported(descriptor.attributes,errors) + return errors + } + + + private def supportedEDataType(EDataType dataType) { + val extension l = EcorePackage.eINSTANCE + return #[EInt, EBoolean, EString, EDouble, EFloat].contains(dataType) + } + + def allSupertypesAreIncluded(List classes, List errors) { + for(c : classes) { + for(s : c.ESuperTypes) { + if(!classes.contains(s)) { + errors.add('''Metamodel contains "«c.name»" but not contains its supertype "«s.name»"!''') + } + } + } + } + def allEnumTypesareIncluded(List enums, List literals, List errors) { + for(l: literals) { + if(!enums.contains(l.EEnum)) { + errors.add('''Metamodel contains literal "«l.name»" but does not contains enum "«l.EEnum.name»"!''') + } + } + } + def referenceEndpointsAreIncluded(List classes, List references, List errors) { + for(reference : references) { + val src = reference.EContainingClass + if(!classes.contains(src)) { + errors.add('''Metamodel contains reference "«reference.name»" but does not contains its source type "«src.name»"!''') + } + + val trg = reference.EReferenceType + if(!classes.contains(trg)) { + errors.add('''Metamodel contains reference "«reference.name»" but does not contains its target type "«trg.name»"!''') + } + } + } + def attributeSourcePontIsIncluded(List classes, List attributes, List errors) { + for(attribute : attributes) { + val src = attribute.containerClass + if(!classes.contains(src)) { + errors.add('''Metamodel contains attribute "«attribute.name»" but does not contains its source type "«src.name»"!''') + } + } + } + def attributeTargetIsSupported(List attributes, List errors) { + for(attribute: attributes) { + val trg = attribute.EAttributeType + if(!supportedEDataType(trg)) { + errors.add('''Metamodels contains attribute "«attribute.name»" with unsupported type "«trg.name»"!''') + } + } + } +} \ No newline at end of file diff --git a/Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/validation/QueryAndMetamodelValidator.xtend b/Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/validation/QueryAndMetamodelValidator.xtend new file mode 100644 index 00000000..e1a20ffd --- /dev/null +++ b/Application/hu.bme.mit.inf.dslreasoner.application/src/hu/bme/mit/inf/dslreasoner/application/execution/validation/QueryAndMetamodelValidator.xtend @@ -0,0 +1,53 @@ +package hu.bme.mit.inf.dslreasoner.application.execution.validation + +import hu.bme.mit.inf.dslreasoner.ecore2logic.EcoreMetamodelDescriptor +import hu.bme.mit.inf.dslreasoner.viatra2logic.ViatraQuerySetDescriptor +import java.util.List +import java.util.Set +import org.eclipse.emf.ecore.ENamedElement +import org.eclipse.viatra.query.patternlanguage.patternLanguage.Pattern +import org.eclipse.viatra.query.runtime.api.IQuerySpecification +import java.util.LinkedList + +class QueryAndMetamodelValidator { + + def public validateQueryAndMetamodel( + EcoreMetamodelDescriptor metamodel, + Pair> viatra) + { + val patterns = viatra.value + val elementsInMetamodel = + (metamodel.classes + + metamodel.enums + + metamodel.literals+ + metamodel.attributes + + metamodel.references) + .toSet + val errors = new LinkedList + for(pattern : patterns) { + val elements = getReferredNamedElements(pattern) + for(element : elements) { + if(!elementsInMetamodel.contains(element)) { + errors+='''Pattern "«pattern.name»" refers to an element "«element»" that is not included to the selected metamodel!''' + } + } + } + return errors + } + + def getReferredNamedElements(Pattern pattern) { + val elements = pattern.eAllContents.toList + return elements.map[element| + val references = element.eClass.EAllReferences + return references.map[r | + if(r.isMany) { + return (element.eGet(r) as List).filter(ENamedElement) + } else { + val value = element.eGet(r) + if(value instanceof ENamedElement) return #[value] + else return #[] + } + ].flatten.filter(ENamedElement) + ].flatten + } +} \ No newline at end of file -- cgit v1.2.3-54-g00ecf