package de.hub.emffrag.fragmentation; import java.io.IOException; import java.util.Iterator; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.xmi.XMLHelper; import org.eclipse.emf.ecore.xmi.XMLResource; import org.eclipse.emf.ecore.xmi.XMLSave; import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; import org.eclipse.emf.ecore.xmi.impl.XMISaveImpl; import org.eclipse.emf.ecore.xmi.impl.XMLHelperImpl; import com.google.common.base.Throwables; import de.hub.emffrag.EmfFragActivator; import de.hub.emffrag.util.EMFFragUtil; import de.hub.emffrag.util.EMFFragUtil.FragmentationType; public class XMIFragmentImpl extends XMIResourceImpl implements Fragment { private final FragmentedModel model; public XMIFragmentImpl(URI uri, FragmentedModel model) { super(uri); this.model = model; } @Override public FragmentedModel getFragmentedModel() { return model; } @Override public void detached(EObject eObject) { super.detached(eObject); if (getContents().isEmpty()) { try { delete(null); } catch (IOException e) { Throwables.propagate(e); } } } @Override protected void unloaded(InternalEObject internalEObject) { super.unloaded(internalEObject); EmfFragActivator.instance.globalEventListener.onUnloadInternalObject((FInternalObjectImpl)internalEObject); } /** * This custom {@link XMLHelperImpl} allows us to determine the form of used * HREF URIs in XMI. This is necessary to point cross references towards * cross reference entries in the data-base rather then the objects * themselves. This requires each cross-referenced object to have an * ID. But EMF exports HREFs towards objects with IDs as * a URI that uses these IDs. We don't want that. This * implementation uses regular URI-fragments for containment references and * URIs pointing at cross-reference entries in the data-store for cross * references. */ private class MyXMLHelper extends XMLHelperImpl { private EStructuralFeature currentFeature = null; public MyXMLHelper(XMLResource resource) { super(resource); } @Override public String getID(EObject obj) { // Ensure that URIs in the id // index are saved, when the object is saved. EmfFragActivator.instance.idSemantics.onObjectSaved((FInternalObjectImpl)obj); return super.getID(obj); } @Override protected URI getHREF(Resource otherResource, EObject obj) { FInternalObjectImpl internalObject = (FInternalObjectImpl)obj; if (otherResource instanceof Fragment) { if (currentFeature instanceof EReference && !((EReference) currentFeature).isContainment()) { FragmentedModel fragmentedModel = ((Fragment) otherResource).getFragmentedModel(); URI uri = EmfFragActivator.instance.idSemantics.getURI(internalObject, fragmentedModel, false, null); if (uri != null) { return uri; } } else if (EMFFragUtil.getFragmentationType(currentFeature) != FragmentationType.None) { return otherResource.getURI().appendFragment("/"); } } URI href2 = super.getHREF(otherResource, obj); return href2; } } @Override protected XMLHelper createXMLHelper() { return new MyXMLHelper(this); } @Override protected XMLSave createXMLSave() { return new XMISaveImpl(createXMLHelper()) { @Override protected void saveHref(EObject remote, EStructuralFeature f) { ((MyXMLHelper) helper).currentFeature = f; super.saveHref(remote, f); } }; } /** * EMF does not break down the reference graph of a resources contents * property. Under some circumstances the JVM cannot remove this contents * even if the resource is unloaded and removed from the resource set. This * change in the EMF standard behavior of the resources fixes that. */ @Override protected void doUnload() { Iterator<EObject> allContents = getAllProperContents(unloadingContents); super.doUnload(); while (allContents.hasNext()) { FInternalObjectImpl internalObject = (FInternalObjectImpl) allContents.next(); internalObject.trulyUnload(); } } @Override protected boolean isAttachedDetachedHelperRequired() { return false; } }