/******************************************************************************* * Copyright (c) 2010-2012, Zoltan Ujhelyi, Istvan Rath and Daniel Varro * 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: * Zoltan Ujhelyi - initial API and implementation *******************************************************************************/ package org.eclipse.incquery.tooling.core.generator.genmodel; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.emf.codegen.ecore.genmodel.GenModel; import org.eclipse.emf.codegen.ecore.genmodel.GenPackage; import org.eclipse.emf.common.util.URI; 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.incquery.patternlanguage.emf.scoping.MetamodelProviderService; import org.eclipse.incquery.tooling.core.project.IncQueryNature; import org.eclipse.incquery.tooling.generator.model.generatorModel.GeneratorModelFactory; import org.eclipse.incquery.tooling.generator.model.generatorModel.GeneratorModelReference; import org.eclipse.incquery.tooling.generator.model.generatorModel.IncQueryGeneratorModel; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.xtext.common.types.access.jdt.IJavaProjectProvider; import org.eclipse.xtext.naming.IQualifiedNameConverter; import org.eclipse.xtext.naming.QualifiedName; import org.eclipse.xtext.resource.EObjectDescription; import org.eclipse.xtext.resource.IEObjectDescription; import org.eclipse.xtext.scoping.IScope; import org.eclipse.xtext.scoping.impl.FilteringScope; import org.eclipse.xtext.scoping.impl.SimpleScope; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.inject.Inject; public class GenModelMetamodelProviderService extends MetamodelProviderService implements IEiqGenmodelProvider { private static final class NameTransformerFunction implements Function<IEObjectDescription, QualifiedName> { @Override public QualifiedName apply(IEObjectDescription desc) { Preconditions.checkNotNull(desc); return desc.getQualifiedName(); } } private static final class ParentScopeFilter implements Predicate<IEObjectDescription> { private final Iterable<IEObjectDescription> referencedPackages; public ParentScopeFilter(Iterable<IEObjectDescription> referencedPackages) { super(); this.referencedPackages = referencedPackages; } @Override public boolean apply(IEObjectDescription desc) { Preconditions.checkNotNull(desc); return !Iterables.contains(Iterables.transform(referencedPackages, new NameTransformerFunction()), desc.getQualifiedName()); } } @Inject private IJavaProjectProvider projectProvider; @Inject private IQualifiedNameConverter qualifiedNameConverter; private URI getGenmodelURI(IProject project) { IFile file = project.getFile(IncQueryNature.IQGENMODEL); return URI.createPlatformResourceURI(file.getFullPath().toString(), false); } @Override public IScope getAllMetamodelObjects(EObject ctx) { Preconditions.checkNotNull(ctx, "Context is required"); Iterable<IEObjectDescription> referencedPackages = Lists.newArrayList(); IncQueryGeneratorModel generatorModel = getGeneratorModel(ctx); if (generatorModel != null) { for (GeneratorModelReference generatorModelReference : generatorModel.getGenmodels()) { Iterable<IEObjectDescription> packages = Iterables.transform( getAllGenPackages(generatorModelReference.getGenmodel()), new Function<GenPackage, IEObjectDescription>() { @Override public IEObjectDescription apply(GenPackage from) { Preconditions.checkNotNull(from); EPackage ePackage = from.getEcorePackage(); QualifiedName qualifiedName = qualifiedNameConverter.toQualifiedName(ePackage .getNsURI()); return EObjectDescription.create(qualifiedName, ePackage, Collections.singletonMap("nsURI", "true")); } }); referencedPackages = Iterables.concat(referencedPackages, packages); } } // The FilteringScope is used to ensure elements in eiq genmodel are not accidentally found in the parent // version return new SimpleScope(new FilteringScope(super.getAllMetamodelObjects(ctx), new ParentScopeFilter( referencedPackages)), referencedPackages); } @Override public Collection<EPackage> getAllMetamodelObjects(IProject project) throws CoreException { Preconditions.checkArgument(project.exists() && project.hasNature(IncQueryNature.NATURE_ID), "Only works for EMF-IncQuery projects"); Set<EPackage> referencedPackages = Sets.newLinkedHashSet(); IncQueryGeneratorModel generatorModel = getGeneratorModel(project); for (GeneratorModelReference generatorModelReference : generatorModel.getGenmodels()) { referencedPackages.addAll(Lists.transform(getAllGenPackages(generatorModelReference.getGenmodel()), new Function<GenPackage, EPackage>() { @Override public EPackage apply(GenPackage desc) { Preconditions.checkNotNull(desc); return desc.getEcorePackage(); } })); } referencedPackages.addAll(getMetamodelMap().values()); return referencedPackages; } @Override public EPackage loadEPackage(final String packageUri, ResourceSet set) { EPackage ePackage = super.loadEPackage(packageUri, set); if (ePackage != null) { return ePackage; } GenPackage loadedPackage = findGenPackage(set, packageUri, false); if (loadedPackage != null) { return loadedPackage.getEcorePackage(); } return null; } @Override public boolean isGeneratedCodeAvailable(EPackage ePackage, ResourceSet set) { return (findGenPackage(set, ePackage) != null) || super.isGeneratedCodeAvailable(ePackage, set); } @Override public IncQueryGeneratorModel getGeneratorModel(EObject pattern) { Resource res = pattern.eResource(); if (res != null && projectProvider != null) { ResourceSet set = res.getResourceSet(); return getGeneratorModel(set); } throw new IllegalArgumentException("The project of the context cannot be determined."); } public IncQueryGeneratorModel getGeneratorModel(IProject project) { return getGeneratorModel(project, new ResourceSetImpl()); } public IncQueryGeneratorModel getGeneratorModel(ResourceSet set) { if (projectProvider != null) { IJavaProject javaProject = projectProvider.getJavaProject(set); if (javaProject != null) { return getGeneratorModel(javaProject.getProject(), set); } } return null; } @Override public IncQueryGeneratorModel getGeneratorModel(IProject project, ResourceSet set) { IFile file = project.getFile(IncQueryNature.IQGENMODEL); if (file.exists()) { URI uri = URI.createPlatformResourceURI(file.getFullPath().toString(), false); Resource resource = set.getResource(uri, true); if (!resource.getContents().isEmpty()) { return (IncQueryGeneratorModel) resource.getContents().get(0); } } return GeneratorModelFactory.eINSTANCE.createIncQueryGeneratorModel(); } @Override public void saveGeneratorModel(IProject project, IncQueryGeneratorModel generatorModel) throws IOException { Resource eResource = generatorModel.eResource(); if (eResource != null) { eResource.save(Maps.newHashMap()); } else { URI uri = getGenmodelURI(project); ResourceSet set = new ResourceSetImpl(); Resource resource = set.createResource(uri); resource.getContents().add(generatorModel); resource.save(Maps.newHashMap()); } } @Override public GenPackage findGenPackage(EObject ctx, final EPackage ePackage) { if (ePackage == null) { return null; } return findGenPackage(ctx, ePackage.getNsURI()); } @Override public GenPackage findGenPackage(EObject ctx, final String packageNsUri) { IncQueryGeneratorModel eiqGenModel = getGeneratorModel(ctx); return findGenPackage(eiqGenModel, ctx.eResource().getResourceSet(), packageNsUri, true); } @Override public GenPackage findGenPackage(ResourceSet set, final EPackage ePackage) { return findGenPackage(set, ePackage.getNsURI()); } @Override public GenPackage findGenPackage(ResourceSet set, final String packageNsUri) { IncQueryGeneratorModel eiqGenModel = getGeneratorModel(set); return findGenPackage(eiqGenModel, set, packageNsUri, true); } private GenPackage findGenPackage(ResourceSet set, final String packageNsUri, boolean fallbackToPackageRegistry) { IncQueryGeneratorModel eiqGenModel = getGeneratorModel(set); return findGenPackage(eiqGenModel, set, packageNsUri, fallbackToPackageRegistry); } private GenPackage findGenPackage(IncQueryGeneratorModel eiqGenModel, ResourceSet set, final String packageNsUri, boolean fallbackToPackageRegistry) { // eiqGenModel is null if loading a pattern from the registry // in this case only fallback to package Registry works if (eiqGenModel != null) { Iterable<GenPackage> genPackageIterable = Lists.newArrayList(); for (GeneratorModelReference generatorModelReference : eiqGenModel.getGenmodels()) { genPackageIterable = Iterables.concat(genPackageIterable, getAllGenPackages(generatorModelReference.getGenmodel())); } Iterable<GenPackage> genPackages = Iterables.filter(genPackageIterable, new Predicate<GenPackage>() { @Override public boolean apply(GenPackage genPackage) { Preconditions.checkNotNull(genPackage, "Checked genpackage must not be null"); return packageNsUri.equals(genPackage.getEcorePackage().getNsURI()); } }); Iterator<GenPackage> it = genPackages.iterator(); if (it.hasNext()) { return it.next(); } } if (fallbackToPackageRegistry) { return getGenmodelRegistry().findGenPackage(packageNsUri, set); } return null; } private List<GenPackage> getAllGenPackages(GenModel genModel) { List<GenPackage> resultList = new ArrayList<GenPackage>(); for (GenPackage genPackage : genModel.getGenPackages()) { resultList.add(genPackage); resultList.addAll(getAllNestedGenPackages(genPackage)); } return resultList; } private List<GenPackage> getAllNestedGenPackages(GenPackage outerGenPackage) { List<GenPackage> resultList = new ArrayList<GenPackage>(); for (GenPackage innerGenPackage : outerGenPackage.getNestedGenPackages()) { resultList.add(innerGenPackage); resultList.addAll(getAllNestedGenPackages(innerGenPackage)); } return resultList; } public boolean isGeneratorModelDefined(IProject project) { IFile file = getGeneratorModelFile(project); return file.exists(); } public IFile getGeneratorModelFile(IProject project) { return project.getFile(IncQueryNature.IQGENMODEL); } @Override public IPath getGeneratorModelPath(IProject project) { return getGeneratorModelFile(project).getFullPath(); } /** * Initializes and returns the IncQuery generator model for the selected project. If the model is already * initialized, it returns the existing model. * * @param project * @return */ public IncQueryGeneratorModel initializeGeneratorModel(IProject project, ResourceSet set) { IFile file = getGeneratorModelFile(project); if (file.exists()) { return getGeneratorModel(project, set); } else { URI uri = URI.createPlatformResourceURI(file.getFullPath().toString(), false); Resource resource = set.createResource(uri); IncQueryGeneratorModel model = GeneratorModelFactory.eINSTANCE.createIncQueryGeneratorModel(); resource.getContents().add(model); return model; } } }