package de.hub.emffrag.fragmentation; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import org.eclipse.emf.common.notify.NotificationChain; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EStructuralFeature.Setting; import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.impl.DynamicEObjectImpl; import org.eclipse.emf.ecore.impl.EClassImpl; import org.eclipse.emf.ecore.impl.EStructuralFeatureImpl; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.Resource.Internal; import org.eclipse.emf.ecore.util.EContentsEList; import org.eclipse.emf.ecore.util.EcoreEList; import org.eclipse.emf.ecore.util.InternalEList; import de.hub.emffrag.EmfFragActivator; import de.hub.emffrag.util.EMFFragUtil; import de.hub.emffrag.util.EMFFragUtil.FragmentationType; public class FInternalObjectImpl extends DynamicEObjectImpl implements FInternalObject { boolean hasPriliminaryId = false; boolean hasDefaultModelId = false; long indexBeforeAdd = -1; String addValueSetId = null; public FInternalObjectImpl(EClass eClass) { super(eClass); EmfFragActivator.instance.globalEventListener.onInternalObjectCreated(this); onLoad(); } public boolean isFragmentRoot() { Resource eResource = eResource(); return eResource != null && eResource instanceof Fragment && (eContainer() == null || eResource != eContainer().eResource()); } public EObject getUserObject() { return UserObjectsCache.instance.getUserObject(this); } public FragmentedModel getFragmentation() { Fragment fragment = getFragment(); if (fragment != null) { return fragment.getFragmentedModel(); } else { return null; } } public Fragment getFragment() { Resource eResource = eResource(); if (eResource != null) { if (eResource instanceof Fragment) { return ((Fragment) eResource); } else { return null; } } else if (eIsProxy()) { EObject container = eContainer(); while (container != null) { eResource = container.eResource(); if (eResource != null) { if (eResource instanceof Fragment) { return ((Fragment) eResource); } else { return null; } } container = container.eContainer(); } return null; } else { return null; } } private EList<EObject> eContentsWithOutFragments() { EStructuralFeature[] eStructuralFeatures = ((EClassImpl.FeatureSubsetSupplier) this.eClass().getEAllStructuralFeatures()).containments(); EStructuralFeature[] eStructuralFeaturesWithOutFragmentsArray = null; if (eStructuralFeatures != null) { List<EStructuralFeature> eStructuralFeaturesWithOutFragments = new ArrayList<EStructuralFeature>(eStructuralFeatures.length); for (EStructuralFeature eStructuralFeature : eStructuralFeatures) { FragmentationType fragmentationType = EMFFragUtil.getFragmentationType(eStructuralFeature); if (fragmentationType == FragmentationType.None || eStructuralFeature instanceof EAttribute) { eStructuralFeaturesWithOutFragments.add(eStructuralFeature); } } eStructuralFeaturesWithOutFragmentsArray = eStructuralFeaturesWithOutFragments .toArray(new EStructuralFeature[eStructuralFeaturesWithOutFragments.size()]); } EContentsEList<EObject> eContentsEListWithOutFragments = eStructuralFeaturesWithOutFragmentsArray == null ? EContentsEList .<EObject> emptyContentsEList() : new EContentsEList<EObject>(this, eStructuralFeaturesWithOutFragmentsArray); return eContentsEListWithOutFragments; } @Override public NotificationChain eSetResource(Internal resource, NotificationChain notifications) { EmfFragActivator.instance.globalEventListener.onInternalObjectSetResource(this, resource); Resource oldResource = eResource(); NotificationChain result = super.eSetResource(resource, notifications); updateAfterResourceChange(oldResource); return result; } private void updateAfterResourceChange(Resource oldResource) { EmfFragActivator.instance.idSemantics.onRequiredId(this); Fragment oldFragment = (Fragment) oldResource; Fragment newFragment = (Fragment) getFragment(); if (oldFragment == newFragment) { return; } if (newFragment != null && oldFragment == null) { onCreate(); EPackage metaModel = eClass().getEPackage(); FragmentedModel fragmentedModel = newFragment.getFragmentedModel(); if (fragmentedModel != null) { fragmentedModel.getInternalResourceSet().getPackageRegistry().put(metaModel.getNsURI(), metaModel); } } if (newFragment != null) { updateIdsAfterContainerChange(this, newFragment); } else { // TODO remove objects from the index? } } private void updateIdsAfterContainerChange(FInternalObjectImpl object, Fragment fragment) { EmfFragActivator.instance.idSemantics.onContainerChange(object, fragment.getFragmentedModel()); for (EObject content : object.eContentsWithOutFragments()) { updateIdsAfterContainerChange((FInternalObjectImpl) content, fragment); } } private void updateFragmentationAfterCreatingAFragment(FInternalObjectImpl object, Fragment newFragment) { EReference eContainmentFeature = object.eContainmentFeature(); if (eContainmentFeature != null) { FragmentationType fragmentationType = EMFFragUtil.getFragmentationType(eContainmentFeature); boolean isFragmenting = fragmentationType == FragmentationType.FragmentsContainment || fragmentationType == FragmentationType.FragmentsIndexedContainment; if (isFragmenting) { if (!object.isFragmentRoot()) { object.updateAfterContainerChange(newFragment); if (newFragment != object.getFragment()) { return; } } } } for (EObject content: object.eContents()) { if (((FInternalObjectImpl)content).getFragment() == newFragment) { updateFragmentationAfterCreatingAFragment((FInternalObjectImpl)content, newFragment); } } } private void updateAfterContainerChange(Fragment oldFragment) { Fragment currentFragment = getFragment(); EStructuralFeature eContainingFeature = eContainingFeature(); FragmentationType fragmentationType = eContainingFeature != null ? EMFFragUtil.getFragmentationType(eContainingFeature) : FragmentationType.None; boolean isFragmenting = fragmentationType == FragmentationType.FragmentsContainment || fragmentationType == FragmentationType.FragmentsIndexedContainment; FragmentedModel fragmentation = getFragmentation(); if (isFragmenting && fragmentation != null) { Fragment newFragment = null; if (fragmentURIForContainerChange != null) { newFragment = fragmentation.createFragment(fragmentURIForContainerChange, this); } else if (!isFragmentRoot()) { newFragment = fragmentation.createFragment(null, this); } if (newFragment != null) { updateFragmentationAfterCreatingAFragment(this, newFragment); } } if (eContainer() == null && currentFragment != null) { // Object was removed (container set to null. // This will delete the resource (fragment) based on normal emf // semantics. currentFragment.getContents().remove(this); } if (oldFragment != eResource()) { updateAfterResourceChange(oldFragment); if (oldFragment != null) { // delete if the old fragment is empty and is not deleted // already if (oldFragment.getContents().isEmpty() && oldFragment.getResourceSet() != null) { oldFragment.getFragmentedModel().deleteFragment(oldFragment); } } } else { if (currentFragment != null) { updateIdsAfterContainerChange(this, currentFragment); } } fragmentURIForContainerChange = null; } /** * The EMF-implementation does somehow create a network of Java references * that prevent to fully unload the contents of a resource. This method * breaks the corresponding references. */ public void trulyUnload() { UserObjectsCache.instance.unload(this); if (eProperties != null) { eProperties.setEContents(null); eProperties.setECrossReferences(null); } eSettings = null; eContainer = null; eAdapters = null; } private static Collection<EStructuralFeature> featuresWithIndexWarning = new HashSet<EStructuralFeature>(); private void checkForReasonableNonIndexedValueSet(EStructuralFeature feature, EList<?> valueSet) { FragmentationType fragmentationType = EMFFragUtil.getFragmentationType(feature); if (fragmentationType == FragmentationType.None || fragmentationType == FragmentationType.FragmentsContainment) { if (valueSet.size() > 500) { if (!featuresWithIndexWarning.contains(feature)) { EmfFragActivator.instance.warning("A value set of feature " + feature.getName() + " of class " + feature.getEContainingClass().getName() + " has now more than 1000 values. Consider to make this feature indexed."); featuresWithIndexWarning.add(feature); } } } } @Override protected NotificationChain eDynamicInverseAdd(InternalEObject otherEnd, int featureID, NotificationChain msgs) { EReference feature = (EReference)eClass().getEStructuralFeature(featureID); EStructuralFeature opposite = feature.getEOpposite(); if (opposite != null && opposite.isMany()) { checkForReasonableNonIndexedValueSet(opposite, (EList<?>)otherEnd.eGet(opposite)); } return super.eDynamicInverseAdd(otherEnd, featureID, msgs); } @Override protected EStructuralFeature.Internal.SettingDelegate eSettingDelegate(final EStructuralFeature eFeature) { FragmentationType type = EMFFragUtil.getFragmentationType(eFeature); if (type == FragmentationType.None || type == FragmentationType.FragmentsContainment) { return ((EStructuralFeature.Internal) eFeature).getSettingDelegate(); } else { return new EStructuralFeatureImpl.InternalSettingDelegateMany(EStructuralFeatureImpl.InternalSettingDelegateMany.DATA_DYNAMIC, eFeature) { @Override protected Setting createDynamicSetting(InternalEObject owner) { int kind = EcoreEList.Generic.kind(eFeature); return new FValueSetList(kind, FInternalObjectImpl.class, FInternalObjectImpl.this, eFeature); } }; } } void eBasicSetContainerForIndexClass(FInternalObjectImpl indexClass, URI uri) { Resource eResource = eResource(); if (!eIsProxy()) { // Do not update containment if the object is a proxy. In that case // the object is loaded and not modified by a user. indexClass.getFragmentation().createFragment(uri, this); updateAfterResourceChange(eResource); } } @Override protected void eBasicSetContainer(InternalEObject newContainer, int newContainerFeatureID) { Fragment oldFragment = getFragment(); super.eBasicSetContainer(newContainer, newContainerFeatureID); if (!eIsProxy()) { // Do not update containment if the object is a proxy. In that case // the object is loaded and not modified by a user. updateAfterContainerChange(oldFragment); } } /** * Called when a Java instance of this class is created. */ private void onLoad() { if (EmfFragActivator.instance.collectStatistics) { setLoaded(getLoaded() + 1); } } /** * Called when the object is added to a fragmented model. */ private void onCreate() { if (EmfFragActivator.instance.collectStatistics) { long loaded = getLoaded(); if (loaded > 0) { setLoaded(loaded - 1); } } } void onAccess() { if (EmfFragActivator.instance.collectStatistics) { setAccessed(getAccessed() + 1); } Fragment fragment = getFragment(); if (fragment != null) { fragment.getFragmentedModel().touch(fragment); } } /** * The default value of the '{@link #getId() <em>Id</em>}' attribute. <!-- * begin-user-doc --> <!-- end-user-doc --> * * @see #getId() * @generated * @ordered */ protected static final String ID_EDEFAULT = null; /** * The default value of the '{@link #getAccessed() <em>Accessed</em>}' attribute. * <!-- begin-user-doc --> <!-- end-user-doc --> * @see #getAccessed() * @generated * @ordered */ protected static final long ACCESSED_EDEFAULT = 0L; /** * The default value of the '{@link #getLoaded() <em>Loaded</em>}' attribute. * <!-- begin-user-doc --> <!-- end-user-doc --> * @see #getLoaded() * @generated * @ordered */ protected static final long LOADED_EDEFAULT = 0L; /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ protected FInternalObjectImpl() { super(); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @Override protected EClass eStaticClass() { return InternalPackage.Literals.FINTERNAL_OBJECT; } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * * @generated */ // @Override // protected EClass eStaticClass() { // return InternalPackage.Literals.FINTERNAL_OBJECT; // } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @Override protected int eStaticFeatureCount() { return 0; } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public String getId() { return (String)eDynamicGet(InternalPackage.FINTERNAL_OBJECT__ID, InternalPackage.Literals.FINTERNAL_OBJECT__ID, true, true); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public void setId(String newId) { eDynamicSet(InternalPackage.FINTERNAL_OBJECT__ID, InternalPackage.Literals.FINTERNAL_OBJECT__ID, newId); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @SuppressWarnings("unchecked") public EList<EObject> getExtensions() { return (EList<EObject>)eDynamicGet(InternalPackage.FINTERNAL_OBJECT__EXTENSIONS, InternalPackage.Literals.FINTERNAL_OBJECT__EXTENSIONS, true, true); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public long getAccessed() { return (Long)eDynamicGet(InternalPackage.FINTERNAL_OBJECT__ACCESSED, InternalPackage.Literals.FINTERNAL_OBJECT__ACCESSED, true, true); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public void setAccessed(long newAccessed) { eDynamicSet(InternalPackage.FINTERNAL_OBJECT__ACCESSED, InternalPackage.Literals.FINTERNAL_OBJECT__ACCESSED, newAccessed); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public long getLoaded() { return (Long)eDynamicGet(InternalPackage.FINTERNAL_OBJECT__LOADED, InternalPackage.Literals.FINTERNAL_OBJECT__LOADED, true, true); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public void setLoaded(long newLoaded) { eDynamicSet(InternalPackage.FINTERNAL_OBJECT__LOADED, InternalPackage.Literals.FINTERNAL_OBJECT__LOADED, newLoaded); } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ @SuppressWarnings("unchecked") public EList<Long> getIndexes() { return (EList<Long>)eDynamicGet(InternalPackage.FINTERNAL_OBJECT__INDEXES, InternalPackage.Literals.FINTERNAL_OBJECT__INDEXES, true, true); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @Override public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs) { switch (featureID) { case InternalPackage.FINTERNAL_OBJECT__EXTENSIONS: return ((InternalEList<?>)getExtensions()).basicRemove(otherEnd, msgs); } return super.eInverseRemove(otherEnd, featureID, msgs); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @Override public Object eGet(int featureID, boolean resolve, boolean coreType) { switch (featureID) { case InternalPackage.FINTERNAL_OBJECT__ID: return getId(); case InternalPackage.FINTERNAL_OBJECT__EXTENSIONS: return getExtensions(); case InternalPackage.FINTERNAL_OBJECT__ACCESSED: return getAccessed(); case InternalPackage.FINTERNAL_OBJECT__LOADED: return getLoaded(); case InternalPackage.FINTERNAL_OBJECT__INDEXES: return getIndexes(); } return super.eGet(featureID, resolve, coreType); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @SuppressWarnings("unchecked") @Override public void eSet(int featureID, Object newValue) { switch (featureID) { case InternalPackage.FINTERNAL_OBJECT__ID: setId((String)newValue); return; case InternalPackage.FINTERNAL_OBJECT__EXTENSIONS: getExtensions().clear(); getExtensions().addAll((Collection<? extends EObject>)newValue); return; case InternalPackage.FINTERNAL_OBJECT__ACCESSED: setAccessed((Long)newValue); return; case InternalPackage.FINTERNAL_OBJECT__LOADED: setLoaded((Long)newValue); return; case InternalPackage.FINTERNAL_OBJECT__INDEXES: getIndexes().clear(); getIndexes().addAll((Collection<? extends Long>)newValue); return; } super.eSet(featureID, newValue); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @Override public void eUnset(int featureID) { switch (featureID) { case InternalPackage.FINTERNAL_OBJECT__ID: setId(ID_EDEFAULT); return; case InternalPackage.FINTERNAL_OBJECT__EXTENSIONS: getExtensions().clear(); return; case InternalPackage.FINTERNAL_OBJECT__ACCESSED: setAccessed(ACCESSED_EDEFAULT); return; case InternalPackage.FINTERNAL_OBJECT__LOADED: setLoaded(LOADED_EDEFAULT); return; case InternalPackage.FINTERNAL_OBJECT__INDEXES: getIndexes().clear(); return; } super.eUnset(featureID); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @Override public boolean eIsSet(int featureID) { switch (featureID) { case InternalPackage.FINTERNAL_OBJECT__ID: return ID_EDEFAULT == null ? getId() != null : !ID_EDEFAULT.equals(getId()); case InternalPackage.FINTERNAL_OBJECT__EXTENSIONS: return !getExtensions().isEmpty(); case InternalPackage.FINTERNAL_OBJECT__ACCESSED: return getAccessed() != ACCESSED_EDEFAULT; case InternalPackage.FINTERNAL_OBJECT__LOADED: return getLoaded() != LOADED_EDEFAULT; case InternalPackage.FINTERNAL_OBJECT__INDEXES: return !getIndexes().isEmpty(); } return super.eIsSet(featureID); } private URI fragmentURIForContainerChange = null; public void fragmentURIForContainerChange(URI uri) { assert (fragmentURIForContainerChange == null); fragmentURIForContainerChange = uri; } }