/**
* Copyright (c) 2011-2012 Eclipse contributors 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
*/
package org.eclipse.emf.ecore.xcore.resource;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
import org.eclipse.emf.codegen.ecore.genmodel.GenClassifier;
import org.eclipse.emf.codegen.ecore.genmodel.GenModel;
import org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage;
import org.eclipse.emf.codegen.ecore.genmodel.GenPackage;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
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.EPackage;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.xcore.XcorePackage;
import org.eclipse.emf.ecore.xcore.scoping.LazyCreationProxyURIConverter;
import org.eclipse.xtext.common.types.JvmDeclaredType;
import org.eclipse.xtext.common.types.JvmMember;
import org.eclipse.xtext.common.types.TypesPackage;
import org.eclipse.xtext.naming.IQualifiedNameProvider;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.IScopeProvider;
import org.eclipse.xtext.util.Pair;
import org.eclipse.xtext.xbase.resource.XbaseResource;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
public class XcoreResource extends XbaseResource
{
@Inject
private LazyCreationProxyURIConverter proxyConverter;
@Inject
private IQualifiedNameProvider nameProvider;
@Inject
private IScopeProvider scopeProvider;
private LinkedHashSet<Pair<EClass, QualifiedName>> resolving = Sets.newLinkedHashSet();
protected class FragmentCache extends AdapterImpl
{
protected Map<String, EObject> map;
protected int expectedSize;
public FragmentCache(XcoreResource xcoreResource)
{
XcoreResource.this.eAdapters.add(this);
}
public EObject get(String uriFragment)
{
int actualSize = XcoreResource.this.getContents().size();
if (map != null && expectedSize != actualSize)
{
clear();
}
if (map == null)
{
map = Maps.newHashMap();
for (EObject eObject : XcoreResource.this.getContents())
{
buildEntry(eObject);
}
expectedSize = actualSize;
}
return map.get(uriFragment);
}
protected void buildEntry(EObject eObject)
{
eObject.eAdapters().add(this);
map.put(getURIFragment(eObject), eObject);
if (eObject instanceof GenModel)
{
for (GenPackage genPackage : ((GenModel)eObject).getGenPackages())
{
buildEntry(genPackage);
for (GenClassifier genClassifier : genPackage.getGenClassifiers())
{
buildEntry(genClassifier);
}
}
}
else if (eObject instanceof EPackage)
{
for (EClassifier eClassifier : ((EPackage)eObject).getEClassifiers())
{
buildEntry(eClassifier);
}
}
else if (eObject instanceof JvmDeclaredType)
{
for (JvmMember jvmMember : ((JvmDeclaredType)eObject).getMembers())
{
if (jvmMember instanceof JvmDeclaredType)
{
buildEntry(jvmMember);
}
}
}
}
@Override
public void notifyChanged(Notification notification)
{
if (map != null)
{
Object feature = notification.getFeature();
if (feature == null ||
feature == EcorePackage.Literals.ENAMED_ELEMENT__NAME ||
feature == TypesPackage.Literals.JVM_MEMBER__SIMPLE_NAME ||
feature == TypesPackage.Literals.JVM_DECLARED_TYPE__PACKAGE_NAME)
{
clear();
}
}
}
public void clear()
{
Collection<EObject> values = map.values();
map = null;
for (EObject eObject : values)
{
eObject.eAdapters().remove(this);
}
}
}
protected FragmentCache fragmentCache;
@Override
public synchronized EObject getEObject(String uriFragment)
{
if (fragmentCache == null)
{
fragmentCache = new FragmentCache(this);
}
EObject result = fragmentCache.get(uriFragment);
if (result != null)
{
return result;
}
else
{
Pair<EClass, QualifiedName> fragmentInfo = proxyConverter.decodeFragment(uriFragment);
if (fragmentInfo != null)
{
try
{
return
resolving.add(fragmentInfo) ?
findEObject(fragmentInfo.getFirst(), fragmentInfo.getSecond(), uriFragment) :
null;
}
finally
{
resolving.remove(fragmentInfo);
}
}
else
{
return super.getEObject(uriFragment);
}
}
}
/**
* Finds the EObject of the given type and the given {@link QualifiedName}.
*/
protected EObject findEObject(EClass eClass, QualifiedName name, String uriFragment)
{
if (eClass == TypesPackage.Literals.JVM_TYPE ||
eClass == GenModelPackage.Literals.GEN_CLASS ||
eClass == GenModelPackage.Literals.GEN_DATA_TYPE ||
eClass == GenModelPackage.Literals.GEN_ENUM)
{
IScope scope =
scopeProvider.getScope
(getContents().get(0),
eClass == TypesPackage.Literals.JVM_TYPE ?
TypesPackage.Literals.JVM_PARAMETERIZED_TYPE_REFERENCE__TYPE :
XcorePackage.Literals.XGENERIC_TYPE__TYPE);
final IEObjectDescription eObjectDescription = scope.getSingleElement(name);
if (eObjectDescription != null)
{
URI uri = eObjectDescription.getEObjectURI();
if (!uriFragment.equals(uri.fragment()) || !uri.trimFragment().equals(getURI()))
{
return eObjectDescription.getEObjectOrProxy();
}
}
}
return null;
}
@Override
public String getURIFragment(EObject object)
{
EClass eClass = object.eClass();
if (eClass == TypesPackage.Literals.JVM_ENUMERATION_TYPE || eClass == GenModelPackage.Literals.GEN_CLASS
|| eClass == GenModelPackage.Literals.GEN_DATA_TYPE || eClass == GenModelPackage.Literals.GEN_ENUM
|| eClass == TypesPackage.Literals.JVM_GENERIC_TYPE)
{
QualifiedName qualifiedName = nameProvider.getFullyQualifiedName(object);
if (qualifiedName != null)
{
return proxyConverter.encodeFragment(eClass, qualifiedName);
}
}
return super.getURIFragment(object);
}
@Override
protected String getURIFragmentRootSegment(EObject eObject)
{
if (eObject instanceof EPackage)
{
return "EPackage";
}
else
{
return super.getURIFragmentRootSegment(eObject);
}
}
@Override
protected EObject getEObjectForURIFragmentRootSegment(String uriFragmentRootSegment)
{
if ("EPackage".equals(uriFragmentRootSegment))
{
return (EObject)EcoreUtil.getObjectByType(getContents(), EcorePackage.Literals.EPACKAGE);
}
else
{
return super.getEObjectForURIFragmentRootSegment(uriFragmentRootSegment);
}
}
}