/**
* Copyright (c) 2011 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.sct.model.stext.scoping;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.naming.IQualifiedNameProvider;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.impl.DefaultGlobalScopeProvider;
import org.eclipse.xtext.scoping.impl.FilteringScope;
import org.eclipse.xtext.scoping.impl.ImportUriGlobalScopeProvider;
import org.eclipse.xtext.scoping.impl.SimpleScope;
import org.eclipse.xtext.util.IAcceptor;
import org.eclipse.xtext.util.IResourceScopeCache;
import org.yakindu.base.types.Package;
import org.yakindu.base.types.TypesPackage;
import org.yakindu.base.types.typesystem.ITypeSystem;
import org.yakindu.sct.domain.extension.DomainRegistry;
import org.yakindu.sct.model.sgraph.SGraphPackage;
import org.yakindu.sct.model.sgraph.Statechart;
import org.yakindu.sct.model.sgraph.util.ContextElementAdapter;
import org.yakindu.sct.model.stext.stext.ImportScope;
import org.yakindu.sct.model.stext.stext.StatechartSpecification;
import org.yakindu.sct.model.stext.stext.StextPackage;
import com.google.common.base.Predicate;
import com.google.inject.Inject;
import com.google.inject.Provider;
/**
* @author andreas muelder - Initial contribution and API
*
*/
public class STextGlobalScopeProvider extends ImportUriGlobalScopeProvider {
public static final URI STEXT_LIB = URI
.createURI("platform:/plugin/org.yakindu.sct.model.stext.lib/lib/STextLib.xmi");
@Inject
private ITypeSystem typeSystem;
@Inject
private IQualifiedNameProvider qualifiedNameProvider;
@Inject
private IResourceScopeCache cache;
@Inject
private DefaultGlobalScopeProvider delegate;
@Inject
private STextLibraryGlobalScopeProvider libraryScope;
public void setCache(IResourceScopeCache cache) {
this.cache = cache;
}
public static final String FILE_EXTENSION = "sct";
public IScope getScope(Resource context, EReference reference, Predicate<IEObjectDescription> filter) {
if (reference.getEReferenceType() == TypesPackage.Literals.PACKAGE) {
return delegate.getScope(context, reference, filter);
}
IScope parentScope = super.getScope(context, reference, filter);
parentScope = new SimpleScope(parentScope, delegate.getScope(context, reference, filter).getAllElements());
parentScope = filterExternalDeclarations(context, parentScope);
parentScope = new SimpleScope(parentScope, libraryScope.getScope(context, reference, filter).getAllElements());
final Statechart statechart = getStatechart(context);
parentScope = new TypeSystemAwareScope(parentScope, typeSystem, qualifiedNameProvider,
reference.getEReferenceType());
return new FilteringScope(parentScope, new Predicate<IEObjectDescription>() {
@Override
public boolean apply(IEObjectDescription input) {
String userData = input.getUserData(DomainRegistry.DOMAIN_ID);
if (userData == null)
return true;
return statechart.getDomainID().equals(userData);
}
});
}
@Override
public IScope getScope(Resource resource, EReference reference) {
if (reference.getEReferenceType() == TypesPackage.Literals.PACKAGE) {
return delegate.getScope(resource, reference);
}
return super.getScope(resource, reference);
}
protected LinkedHashSet<URI> getImportedUris(final Resource resource) {
return cache.get(ImportUriGlobalScopeProvider.class.getName(), resource, new Provider<LinkedHashSet<URI>>() {
@Override
public LinkedHashSet<URI> get() {
final LinkedHashSet<URI> uniqueImportURIs = new LinkedHashSet<URI>(5);
IAcceptor<String> collector = createURICollector(resource, uniqueImportURIs);
Collection<ImportScope> importScopes = getImportScopes(resource);
for (ImportScope object : importScopes) {
EList<Package> imports = object.getImports();
for (Package package1 : imports) {
collectPackageImports(package1, collector, uniqueImportURIs);
}
}
Iterator<URI> uriIter = uniqueImportURIs.iterator();
while (uriIter.hasNext()) {
if (!EcoreUtil2.isValidUri(resource, uriIter.next()))
uriIter.remove();
}
return uniqueImportURIs;
}
private Collection<ImportScope> getImportScopes(final Resource resource) {
StatechartSpecification specification = (StatechartSpecification) EcoreUtil
.getObjectByType(resource.getContents(), StextPackage.Literals.STATECHART_SPECIFICATION);
if (specification != null) {
return EcoreUtil.getObjectsByType(specification.getScopes(), StextPackage.Literals.IMPORT_SCOPE);
} else {
Statechart statechart = getStatechart(resource);
return EcoreUtil.getObjectsByType(statechart.getScopes(), StextPackage.Literals.IMPORT_SCOPE);
}
}
});
}
protected void collectPackageImports(Package package1, IAcceptor<String> acceptor,
LinkedHashSet<URI> uniqueImportURIs) {
EcoreUtil.resolveAll(package1);
if (package1.eIsProxy())
return;
String uri = EcoreUtil.getURI(package1).trimFragment().toString();
acceptor.accept(uri);
}
protected Statechart getStatechart(Resource context) {
final ContextElementAdapter provider = (ContextElementAdapter) EcoreUtil.getExistingAdapter(context,
ContextElementAdapter.class);
if (provider == null) {
return (Statechart) EcoreUtil2.getObjectByType(context.getContents(), SGraphPackage.Literals.STATECHART);
} else {
return (Statechart) EcoreUtil.getObjectByType(provider.getElement().eResource().getContents(),
SGraphPackage.Literals.STATECHART);
}
}
/**
* Filter all Elements that are part of an SCT file from other resources to
* avoid cross document referencing
*/
protected IScope filterExternalDeclarations(Resource context, IScope parentScope) {
final ContextElementAdapter provider = (ContextElementAdapter) EcoreUtil.getExistingAdapter(context,
ContextElementAdapter.class);
final URI resourceURI = provider != null ? provider.getElement().eResource().getURI() : context.getURI();
parentScope = new FilteringScope(parentScope, new Predicate<IEObjectDescription>() {
public boolean apply(IEObjectDescription input) {
if (FILE_EXTENSION.equals(input.getEObjectURI().fileExtension())) {
URI sourceURI = input.getEObjectURI().trimFragment();
return sourceURI.equals(resourceURI);
}
return true;
}
});
return parentScope;
}
}