package de.hub.emffrag.fragmentation;
import java.lang.ref.WeakReference;
import org.eclipse.emf.common.notify.NotificationChain;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.EStoreEObjectImpl;
import org.eclipse.emf.ecore.resource.Resource.Internal;
import de.hub.emffrag.EmfFragActivator;
import de.hub.emffrag.util.EMFFragUtil;
import de.hub.emffrag.util.EMFFragUtil.FragmentationType;
public class FObjectImpl extends EStoreEObjectImpl {
private FragmentedModel fragmentedModel;
private FInternalObjectImpl internalObject;
private WeakReference<InternalEObject> containerReference = null;
public FObjectImpl() {
eSetStore(FStoreImpl.getInstance());
eContainerFeatureID = Integer.MAX_VALUE;
}
protected void fSetInternalObject(FInternalObjectImpl internalObject, boolean load) {
this.internalObject = internalObject;
if (fragmentedModel == null) {
this.fragmentedModel = internalObject.getFragmentation();
}
if (!load) {
EmfFragActivator.instance.globalEventListener.onUserObjectCreated(internalObject, this);
}
}
public FInternalObjectImpl fInternalObject() {
if (internalObject == null) {
// This object was not yet added to a model
internalObject = UserObjectsCache.instance.createInternalObject(this);
}
if (fragmentedModel == null) {
fragmentedModel = internalObject.getFragmentation();
}
internalObject.onAccess();
return internalObject;
}
public FragmentedModel fFragmentation() {
if (internalObject != null) {
FragmentedModel fragmentation = internalObject.getFragmentation();
if (fragmentation != null) {
this.fragmentedModel = fragmentation;
}
}
return fragmentedModel;
}
/**
* Changes the super class behavior so that the fragmented model is always
* returned as the objects resource.
*/
@Override
public Internal eDirectResource() {
return (Internal) fInternalObject().getFragmentation();
}
/**
* EStoreObjectImpl holds a strong java reference towards container. This is
* bad, since those cannot be differentiated between actual user references.
* We have to replace EBasicEObjectImpl.eContainer (modified by this method
* and eInitializeContainer()) with a java weak reference.
*/
@Override
public InternalEObject eInternalContainer() {
if (containerReference == null || eContainerFeatureID == Integer.MAX_VALUE) {
eInitializeContainer();
return containerReference.get();
} else {
InternalEObject container = containerReference.get();
if (container == null) {
eInitializeContainer();
return containerReference.get();
} else {
return container;
}
}
}
/**
* See doc of {@link #eInternalContainer()}
*/
@Override
protected void eInitializeContainer() {
super.eInitializeContainer();
containerReference = new WeakReference<InternalEObject>(eContainer);
eContainer = EUNINITIALIZED_CONTAINER;
}
/**
* See doc of {@link #eInternalContainer()}
*/
@Override
public int eContainerFeatureID() {
if (containerReference == null || eContainerFeatureID == Integer.MAX_VALUE) {
eInitializeContainer();
return eContainerFeatureID;
} else {
InternalEObject container = containerReference.get();
if (container == null) {
eInitializeContainer();
}
return eContainerFeatureID;
}
}
/**
* See doc of {@link #eInternalContainer()}.
*/
@Override
protected void eBasicSetContainer(InternalEObject newContainer, int newContainerFeatureID) {
// Container are handled internally, externally there are not container
// to change. This disables the according super class functionality.
// update the weak reference that is used instead of EMF's hard
// reference super.eBasicSetContainer(newContainer,
// newContainerFeatureID);
containerReference = new WeakReference<InternalEObject>(eContainer);
}
public NotificationChain eBasicSetContainer(InternalEObject newContainer, int newContainerFeatureID, NotificationChain msgs) {
// Container are handled internally, externally there are not container
// to change. This disables the according super class functionality.
return msgs;
}
@Override
public NotificationChain eBasicRemoveFromContainer(NotificationChain msgs) {
// disables superclass implementation to avoid instant remove through
// double realization of containment
return msgs;
}
@Override
public NotificationChain eBasicRemoveFromContainerFeature(NotificationChain msgs) {
// disables superclass implementation to avoid instant remove through
// double realization of containment
return msgs;
}
@SuppressWarnings("rawtypes")
@Override
protected EList<?> createList(EStructuralFeature eStructuralFeature) {
final EClassifier eType = eStructuralFeature.getEType();
if (eType.getInstanceClassName() == "java.util.Map$Entry") {
return super.createList(eStructuralFeature);
} else {
FragmentationType fragmentationType = EMFFragUtil.getFragmentationType(eStructuralFeature);
if (fragmentationType == FragmentationType.IndexedReferences || fragmentationType == FragmentationType.FragmentsIndexedContainment) {
return new MyBasicEStoreEList(this, eStructuralFeature);
} else {
return super.createList(eStructuralFeature);
}
}
}
private static class MyBasicEStoreEList<T> extends BasicEStoreEList<T> {
private static final long serialVersionUID = -2460474979751814503L;
public MyBasicEStoreEList(InternalEObject arg0, EStructuralFeature arg1) {
super(arg0, arg1);
}
@Override
public int indexOf(Object object) {
if (object instanceof EObject) {
object = resolveProxy((EObject)object);
}
return delegateIndexOf(object);
}
@Override
public int lastIndexOf(Object object) {
if (object instanceof EObject) {
object = resolveProxy((EObject)object);
}
return delegateLastIndexOf(object);
}
@Override
public boolean contains(Object object) {
if (object instanceof EObject) {
object = resolveProxy((EObject)object);
}
return delegateContains(object);
}
}
}