| /******************************************************************************* |
| * Copyright (c) 2008-2011 Chair for Applied Software Engineering, |
| * Technische Universitaet Muenchen. |
| * 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: |
| * Maximilian Koegel, Edgar Mueller - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.emf.emfstore.internal.common.model.impl; |
| |
| import java.io.IOException; |
| import java.text.MessageFormat; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.LinkedHashMap; |
| import java.util.LinkedHashSet; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.common.util.TreeIterator; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.EStructuralFeature.Setting; |
| import org.eclipse.emf.ecore.impl.EObjectImpl; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.util.EcoreUtil.Copier; |
| import org.eclipse.emf.ecore.util.EcoreUtil.UsageCrossReferencer; |
| import org.eclipse.emf.ecore.xmi.XMIResource; |
| import org.eclipse.emf.emfstore.common.extensionpoint.ESExtensionElement; |
| import org.eclipse.emf.emfstore.common.extensionpoint.ESExtensionPoint; |
| import org.eclipse.emf.emfstore.common.model.ESModelElementIdGenerator; |
| import org.eclipse.emf.emfstore.internal.common.ESDisposable; |
| import org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection; |
| import org.eclipse.emf.emfstore.internal.common.model.ModelElementId; |
| import org.eclipse.emf.emfstore.internal.common.model.ModelFactory; |
| import org.eclipse.emf.emfstore.internal.common.model.util.ModelUtil; |
| |
| /** |
| * Implementation of an ID based storage mechanism for {@link EObject}s. |
| * |
| * @author emueller |
| * @author mkoegel |
| */ |
| public abstract class IdEObjectCollectionImpl extends EObjectImpl implements IdEObjectCollection, ESDisposable { |
| |
| /** |
| * The extension point id to configure the {@link ESModelElementIdGenerator}. |
| */ |
| public static final String MODELELEMENTID_GENERATOR_EXTENSIONPOINT = "org.eclipse.emf.emfstore.common.model.modelelementIdGenerator"; //$NON-NLS-1$ |
| |
| /** |
| * The attribute identifying the class of the {@link ESModelElementIdGenerator} extension point. |
| */ |
| public static final String MODELELEMENTID_GENERATOR_CLASS_ATTRIBUTE = "class"; //$NON-NLS-1$ |
| |
| // Caches |
| private Map<EObject, String> eObjectToIdMap; |
| private Map<String, EObject> idToEObjectMap; |
| |
| // These caches will be used to assign specific IDs to newly created EObjects. |
| // Additionally, IDs of deleted model elements will also be put into these caches, in case |
| // the deleted elements will be restored during a command. |
| private final Map<EObject, String> allocatedEObjectToIdMap; |
| private final Map<String, EObject> allocatedIdToEObjectMap; |
| |
| private boolean cachesInitialized; |
| |
| /** |
| * A {@link ESModelElementIdGenerator} for other plugins to register a special ID generation. |
| */ |
| private ESModelElementIdGenerator<ModelElementId> modelElementIdGenerator; |
| |
| /** |
| * Constructor. |
| */ |
| @SuppressWarnings("unchecked") |
| public IdEObjectCollectionImpl() { |
| eObjectToIdMap = new LinkedHashMap<EObject, String>(); |
| idToEObjectMap = new LinkedHashMap<String, EObject>(); |
| |
| allocatedEObjectToIdMap = new LinkedHashMap<EObject, String>(); |
| allocatedIdToEObjectMap = new LinkedHashMap<String, EObject>(); |
| |
| final ESExtensionElement element = new ESExtensionPoint(MODELELEMENTID_GENERATOR_EXTENSIONPOINT) |
| .getElementWithHighestPriority(); |
| |
| if (element != null) { |
| modelElementIdGenerator = element.getClass( |
| MODELELEMENTID_GENERATOR_CLASS_ATTRIBUTE, |
| ESModelElementIdGenerator.class); |
| } |
| } |
| |
| /** |
| * Constructor. Adds the contents of the given {@link XMIResource} as model |
| * elements to the collection. If the {@link XMIResource} also has XMI IDs |
| * assigned to the {@link EObject}s it contains, they will be used for |
| * creating the {@link ModelElementId}s within the project, if not, the {@link ModelElementId}s will get created on |
| * the fly. |
| * |
| * @param xmiResource |
| * a {@link XMIResource} |
| * @throws IOException |
| * if the given {@link XMIResource} could not be loaded |
| */ |
| public IdEObjectCollectionImpl(XMIResource xmiResource) throws IOException { |
| this(); |
| boolean resourceHasIds = false; |
| try { |
| if (!xmiResource.isLoaded()) { |
| ModelUtil.loadResource(xmiResource, ModelUtil.getResourceLogger()); |
| } |
| } catch (final IOException e) { |
| ModelUtil.logException( |
| String.format(Messages.IdEObjectCollectionImpl_XMIResourceNotLoaded, xmiResource.getURI()), e); |
| throw e; |
| } |
| final TreeIterator<EObject> it = xmiResource.getAllContents(); |
| while (it.hasNext()) { |
| final EObject eObject = it.next(); |
| |
| if (ModelUtil.isIgnoredDatatype(eObject)) { |
| continue; |
| } |
| |
| final String id = xmiResource.getID(eObject); |
| final ModelElementId eObjectId = getNewModelElementID(); |
| |
| if (id != null) { |
| eObjectId.setId(id); |
| resourceHasIds = true; |
| } else { |
| xmiResource.setID(eObject, eObjectId.getId()); |
| } |
| |
| putIntoCaches(eObject, eObjectId.getId()); |
| } |
| |
| if (resourceHasIds) { |
| cachesInitialized = true; |
| } |
| |
| final EList<EObject> contents = xmiResource.getContents(); |
| setModelElements(contents); |
| |
| if (!resourceHasIds) { |
| // save, in order to write IDs back into resource |
| ModelUtil.saveResource(xmiResource, ModelUtil.getResourceLogger()); |
| } |
| } |
| |
| /** |
| * |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection#getModelElements() |
| */ |
| public abstract EList<EObject> getModelElements(); |
| |
| /** |
| * Sets the model elements of this collection. |
| * |
| * @param modelElements |
| * the new list of model elements the collection should hold |
| */ |
| protected abstract void setModelElements(EList<EObject> modelElements); |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection#addModelElement(org.eclipse.emf.ecore.EObject) |
| */ |
| public void addModelElement(EObject eObject) { |
| getModelElements().add(eObject); |
| } |
| |
| /** |
| * |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection#contains(org.eclipse.emf.ecore.EObject) |
| */ |
| public boolean contains(EObject modelElement) { |
| return getEObjectsCache().contains(modelElement); |
| } |
| |
| /** |
| * |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection#contains(org.eclipse.emf.emfstore.internal.common.model.ModelElementId) |
| */ |
| public boolean contains(ModelElementId id) { |
| if (!isCacheInitialized()) { |
| initMapping(); |
| } |
| return getIdToEObjectCache().containsKey(id); |
| } |
| |
| /** |
| * Returns the ID of a deleted model element. |
| * <b>NOTE</b>: If commands are used, IDs of deleted model elements are only available during command execution. |
| * If commands aren't used IDs of deleted model elements remain as long available until either a share, |
| * a commit or an update happens. |
| * |
| * @param deletedModelElement |
| * the model element that has been deleted |
| * @return the ID of the deleted model element or {@code null} if no such ID exists |
| */ |
| public ModelElementId getDeletedModelElementId(EObject deletedModelElement) { |
| |
| final String id = allocatedEObjectToIdMap.get(deletedModelElement); |
| |
| if (id != null) { |
| final ModelElementId modelElementId = ModelFactory.eINSTANCE.createModelElementId(); |
| modelElementId.setId(id); |
| return modelElementId; |
| } |
| |
| return ModelUtil.getSingletonModelElementId(deletedModelElement); |
| } |
| |
| /** |
| * Returns the deleted model element by means of an ID. |
| * <b>NOTE</b>: If commands are used, deleted model elements are only available during command execution. |
| * If commands aren't used IDs of deleted model elements remain as long available until either a share, |
| * a commit or an update happens. |
| * |
| * @param deletedModelElementId |
| * the ID of an already deleted model element |
| * @return the deleted model element or {@code null} if no such element exists |
| */ |
| public EObject getDeletedModelElement(ModelElementId deletedModelElementId) { |
| |
| if (deletedModelElementId == null) { |
| return null; |
| } |
| |
| final EObject eObject = allocatedIdToEObjectMap.get(deletedModelElementId); |
| return eObject != null ? eObject : ModelUtil.getSingleton(deletedModelElementId); |
| } |
| |
| /** |
| * |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection#getModelElementId(org.eclipse.emf.ecore.EObject) |
| */ |
| public ModelElementId getModelElementId(EObject eObject) { |
| |
| // EObject _is_ project -> assign magic ModelElementId |
| if (this == eObject) { |
| final ModelElementId modelElementId = getNewModelElementID(); |
| modelElementId.setId("001"); //$NON-NLS-1$ |
| return modelElementId; |
| } |
| |
| if (!eObjectToIdMap.containsKey(eObject) && !isCacheInitialized()) { |
| |
| // EObject contained in project, load ID from resource |
| try { |
| final Resource resource = eObject.eResource(); |
| |
| // EM: is this a potential error case we have to consider? |
| if (!(resource instanceof XMIResource)) { |
| return null; |
| } |
| |
| final XMIResource xmiResource = (XMIResource) resource; |
| ModelUtil.loadResource(xmiResource, ModelUtil.getResourceLogger()); |
| final ModelElementId modelElementId = getNewModelElementID(); |
| final String id = xmiResource.getID(eObject); |
| |
| if (id != null) { |
| // change generated ID if one has been found in the resource |
| modelElementId.setId(id); |
| } |
| |
| eObjectToIdMap.put(eObject, modelElementId.getId()); |
| return modelElementId; |
| |
| } catch (final IOException e) { |
| throw new RuntimeException(Messages.IdEObjectCollectionImpl_CouldNotLoadElementResource + eObject); |
| } |
| } |
| |
| final String id = eObjectToIdMap.get(eObject); |
| final ModelElementId modelElementId = getNewModelElementID(); |
| modelElementId.setId(id); |
| |
| return id != null ? modelElementId : ModelUtil.getSingletonModelElementId(eObject); |
| } |
| |
| /** |
| * |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection#getModelElement(org.eclipse.emf.emfstore.internal.common.model.ModelElementId) |
| */ |
| public EObject getModelElement(ModelElementId modelElementId) { |
| |
| if (modelElementId == null) { |
| return null; |
| } |
| |
| if (!isCacheInitialized()) { |
| initMapping(); |
| } |
| |
| final EObject eObject = getIdToEObjectCache().get(modelElementId.getId()); |
| |
| return eObject != null ? eObject : ModelUtil.getSingleton(modelElementId); |
| } |
| |
| /** |
| * |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection#deleteModelElement(org.eclipse.emf.ecore.EObject) |
| */ |
| public void deleteModelElement(final EObject modelElement) { |
| if (!this.contains(modelElement)) { |
| throw new IllegalArgumentException(Messages.IdEObjectCollectionImpl_ElementNotContainedInProject); |
| } |
| |
| // remove cross references |
| ModelUtil.deleteOutgoingCrossReferences(this, modelElement); |
| final Collection<Setting> crossReferences = UsageCrossReferencer.find(modelElement, this); |
| ModelUtil.deleteIncomingCrossReferencesToElement(modelElement, crossReferences, new LinkedHashSet<EObject>()); |
| |
| // remove containment |
| final EObject containerModelElement = ModelUtil.getContainerModelElement(modelElement); |
| if (containerModelElement == null) { |
| // removeModelElementAndChildrenFromCache(modelElement); |
| // getEobjectsIdMap().remove(modelElement); |
| getModelElements().remove(modelElement); |
| } else { |
| final EReference containmentFeature = modelElement.eContainmentFeature(); |
| if (containmentFeature.isMany()) { |
| final EList<?> containmentList = (EList<?>) containerModelElement.eGet(containmentFeature); |
| containmentList.remove(modelElement); |
| } else { |
| containerModelElement.eSet(containmentFeature, null); |
| } |
| |
| removeModelElementAndChildrenFromResource(modelElement); |
| } |
| } |
| |
| /** |
| * Removes the the given {@link EObject} and all its contained children from |
| * their respective {@link XMIResource}s. |
| * |
| * @param eObject |
| * the {@link EObject} to remove |
| */ |
| public void removeModelElementAndChildrenFromResource(EObject eObject) { |
| final Set<EObject> children = ModelUtil.getAllContainedModelElements(eObject, false); |
| for (final EObject child : children) { |
| removeModelElementFromResource(child); |
| } |
| removeModelElementFromResource(eObject); |
| |
| } |
| |
| /** |
| * Removes the the given {@link EObject} from its {@link XMIResource}. |
| * |
| * @param xmiResource |
| * the {@link EObject}'s resource |
| * @param eObject |
| * the {@link EObject} to remove |
| */ |
| private void removeModelElementFromResource(EObject eObject) { |
| |
| if (!(eObject.eResource() instanceof XMIResource)) { |
| return; |
| } |
| |
| final XMIResource xmiResource = (XMIResource) eObject.eResource(); |
| |
| if (xmiResource.getURI() == null) { |
| return; |
| } |
| |
| xmiResource.setID(eObject, null); |
| |
| try { |
| ModelUtil.saveResource(xmiResource, ModelUtil.getResourceLogger()); |
| } catch (final IOException e) { |
| throw new RuntimeException( |
| MessageFormat.format( |
| Messages.IdEObjectCollectionImpl_ResourceCouldNotBeSaved, |
| eObject, |
| e.getMessage())); |
| } |
| } |
| |
| /** |
| * Returns the {@link ModelElementId} for the given model element. If no |
| * such ID exists, a new one will be created. |
| * |
| * @param modelElement |
| * a model element to fetch a {@link ModelElementId} for |
| * @return the {@link ModelElementId} for the given model element |
| */ |
| private ModelElementId getIdForModelElement(EObject modelElement) { |
| |
| final Resource resource = modelElement.eResource(); |
| |
| if (resource != null && resource instanceof XMIResource) { |
| // resource available, read ID |
| final XMIResource xmiResource = (XMIResource) resource; |
| try { |
| ModelUtil.loadResource(xmiResource, ModelUtil.getResourceLogger()); |
| } catch (final IOException e) { |
| throw new RuntimeException( |
| MessageFormat.format(Messages.IdEObjectCollectionImpl_ResoruceCouldNotBeLoaded, |
| modelElement)); |
| } |
| final String id = xmiResource.getID(modelElement); |
| if (id != null) { |
| final ModelElementId objId = getNewModelElementID(); |
| objId.setId(id); |
| return objId; |
| } |
| } |
| |
| // create new ID |
| return getNewModelElementID(); |
| } |
| |
| /** |
| * |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection#getAllModelElements() |
| */ |
| public Set<EObject> getAllModelElements() { |
| if (!isCacheInitialized()) { |
| initMapping(); |
| } |
| |
| return Collections.unmodifiableSet(eObjectToIdMap.keySet()); |
| } |
| |
| /** |
| * Gets all model elements by class. |
| * |
| * @param modelElementClass the EClass |
| * @param list the list of model elements |
| * @return the model elements matching the class |
| * |
| * @param <T> type |
| */ |
| public <T extends EObject> EList<T> getAllModelElementsByClass(EClass modelElementClass, EList<T> list) { |
| return getAllModelElementsByClass(modelElementClass, list, true); |
| } |
| |
| /** |
| * Gets all model elements by class. |
| * |
| * @param modelElementClass the EClass |
| * @param list the list of model elements |
| * @return the model elements matching the class |
| * |
| * @param <T> type |
| */ |
| // cast below is guarded by sanity check |
| @SuppressWarnings("unchecked") |
| public <T extends EObject> EList<T> getModelElementsByClass(EClass modelElementClass, EList<T> list) { |
| |
| for (final EObject modelElement : getModelElements()) { |
| if (modelElementClass.isInstance(modelElement)) { |
| list.add((T) modelElement); |
| } |
| } |
| return list; |
| } |
| |
| /** |
| * Gets all model elements by class. |
| * |
| * @param modelElementClass the EClass |
| * @param list the list of model elements |
| * @param subclasses whether to use subclasses |
| * @return the model elements matching the class |
| * |
| * @param <T> type |
| */ |
| // two casts below are guarded by initial sanity check and if statement |
| @SuppressWarnings("unchecked") |
| public <T extends EObject> EList<T> getAllModelElementsByClass(EClass modelElementClass, EList<T> list, |
| Boolean subclasses) { |
| |
| if (subclasses) { |
| for (final EObject modelElement : getAllModelElements()) { |
| if (modelElementClass.isInstance(modelElement)) { |
| list.add((T) modelElement); |
| } |
| } |
| } else { |
| for (final EObject modelElement : getAllModelElements()) { |
| if (modelElement.eClass() == modelElementClass) { |
| list.add((T) modelElement); |
| } |
| } |
| } |
| |
| return list; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.common.model.ESObjectContainer#getAllModelElementsByClass(java.lang.Class) |
| */ |
| public <T extends EObject> Set<T> getAllModelElementsByClass(Class<T> modelElementClass) { |
| return getAllModelElementsByClass(modelElementClass, true); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.common.model.ESObjectContainer#getAllModelElementsByClass(java.lang.Class, |
| * java.lang.Boolean) |
| */ |
| @SuppressWarnings("unchecked") |
| public <T extends EObject> Set<T> getAllModelElementsByClass(Class<T> modelElementClass, |
| Boolean includeSubclasses) { |
| final LinkedHashSet<T> result = new LinkedHashSet<T>(); |
| if (includeSubclasses) { |
| for (final EObject modelElement : getAllModelElements()) { |
| if (modelElementClass.isInstance(modelElement)) { |
| result.add((T) modelElement); |
| } |
| } |
| } else { |
| for (final EObject modelElement : getAllModelElements()) { |
| if (modelElement.getClass() == modelElementClass) { |
| result.add((T) modelElement); |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Whether the cache has been initialized. |
| * |
| * @return true, if the cache is initialized, false otherwise |
| */ |
| protected boolean isCacheInitialized() { |
| return cachesInitialized; |
| } |
| |
| /** |
| * Returns the cache that maps {@link ModelElementId} to model elements. |
| * |
| * @return a map containing mappings from {@link ModelElementId}s to model |
| * element |
| */ |
| protected Map<String, EObject> getIdToEObjectCache() { |
| if (!isCacheInitialized()) { |
| initMapping(); |
| } |
| |
| return idToEObjectMap; |
| } |
| |
| /** |
| * Returns the model element cache. |
| * |
| * @return a set containing all model elements |
| */ |
| protected Set<EObject> getEObjectsCache() { |
| if (!isCacheInitialized()) { |
| initMapping(); |
| } |
| |
| return eObjectToIdMap.keySet(); |
| } |
| |
| /** |
| * |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection#initMapping() |
| */ |
| public void initMapping() { |
| |
| if (isCacheInitialized()) { |
| return; |
| } |
| |
| for (final EObject modelElement : getModelElements()) { |
| putModelElementIntoCache(modelElement); |
| } |
| |
| cachesInitialized = true; |
| } |
| |
| /** |
| * Puts the given model element into the collections' caches. |
| * |
| * @param modelElement |
| * the model element which should be added to the caches |
| */ |
| protected void putModelElementIntoCache(EObject modelElement) { |
| |
| // put model element into cache |
| final ModelElementId modelElementId = getIdForModelElement(modelElement); |
| putIntoCaches(modelElement, modelElementId.getId()); |
| |
| // put children of model element into cache |
| final TreeIterator<EObject> it = modelElement.eAllContents(); |
| |
| while (it.hasNext()) { |
| final EObject obj = it.next(); |
| final ModelElementId id = getIdForModelElement(obj); |
| putIntoCaches(obj, id.getId()); |
| } |
| } |
| |
| /** |
| * Adds a model element and all its children to the caches. |
| * |
| * @param modelElement |
| * the model element, that should get added to the caches |
| */ |
| protected void addModelElementAndChildrenToCache(EObject modelElement) { |
| |
| final HashSet<String> removableIds = new LinkedHashSet<String>(); |
| |
| final Set<EObject> containedModelElements = ModelUtil.getAllContainedModelElements(modelElement, false); |
| containedModelElements.add(modelElement); |
| |
| for (final EObject child : containedModelElements) { |
| |
| // first check whether ID should be reassigned |
| String childId = allocatedEObjectToIdMap.get(child); |
| |
| if (childId == null) { |
| // if not, create a new ID |
| childId = getNewModelElementID().getId(); |
| } else { |
| removableIds.add(childId); |
| } |
| |
| if (isCacheInitialized()) { |
| putIntoCaches(child, childId); |
| } |
| } |
| |
| // remove all IDs that are in use now |
| for (final String modelElementId : removableIds) { |
| final EObject eObject = allocatedIdToEObjectMap.get(modelElementId); |
| allocatedEObjectToIdMap.remove(eObject); |
| } |
| |
| allocatedIdToEObjectMap.keySet().removeAll(removableIds); |
| } |
| |
| /** |
| * |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection#initMapping(java.util.Map, java.util.Map) |
| */ |
| public void initMapping(Map<EObject, String> eObjectToIdMap, Map<String, EObject> idToEObjectMap) { |
| cachesInitialized = true; |
| this.eObjectToIdMap = eObjectToIdMap; |
| this.idToEObjectMap = idToEObjectMap; |
| } |
| |
| /** |
| * Creates a mapping for the given model element and the given {@link ModelElementId} within the cache. |
| * |
| * @param modelElement |
| * a model element |
| * @param modelElementId |
| * a {@link ModelElementId} |
| */ |
| protected void putIntoCaches(EObject modelElement, String modelElementId) { |
| // never overwrite existing IDs |
| if (!eObjectToIdMap.containsKey(modelElement)) { |
| eObjectToIdMap.put(modelElement, modelElementId); |
| idToEObjectMap.put(modelElementId, modelElement); |
| } |
| } |
| |
| /** |
| * Copies the collection. |
| * |
| * @param <T> |
| * a collection type |
| * @return the copied collection instance |
| */ |
| @SuppressWarnings("unchecked") |
| public <T extends IdEObjectCollection> T copy() { |
| final Copier copier = new IdEObjectCollectionCopier(); |
| final T result = (T) copier.copy(this); |
| ((IdEObjectCollectionImpl) result).cachesInitialized = true; |
| copier.copyReferences(); |
| return result; |
| } |
| |
| /** |
| * |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.internal.common.ESDisposable#dispose() |
| */ |
| public void dispose() { |
| eObjectToIdMap.clear(); |
| idToEObjectMap.clear(); |
| clearAllocatedCaches(); |
| cachesInitialized = false; |
| } |
| |
| /** |
| * Removes a model element and all its children from the cache. |
| * |
| * @param modelElement |
| * a model element to be removed from the cache |
| */ |
| protected void removeModelElementAndChildrenFromCache(EObject modelElement) { |
| |
| if (allocatedEObjectToIdMap.containsKey(modelElement)) { |
| return; |
| } |
| |
| removeFromCaches(modelElement); |
| |
| for (final EObject child : ModelUtil.getAllContainedModelElements(modelElement, false)) { |
| removeFromCaches(child); |
| } |
| } |
| |
| /** |
| * Removes the given model element from the caches. |
| * |
| * @param modelElement |
| * t#he model element to be removed from the caches |
| */ |
| private void removeFromCaches(EObject modelElement) { |
| if (isCacheInitialized()) { |
| final ModelElementId id = getModelElementId(modelElement); |
| |
| putIntoAllocatedCaches(modelElement, id); |
| |
| getEObjectsCache().remove(modelElement); |
| getIdToEObjectCache().remove(id.getId()); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection#allocateModelElementIds(java.util.Map) |
| */ |
| public void allocateModelElementIds(Map<EObject, ModelElementId> eObjectToIdMapping) { |
| for (final Map.Entry<EObject, ModelElementId> entry : eObjectToIdMapping.entrySet()) { |
| final EObject modelElement = entry.getKey(); |
| final ModelElementId modelElementId = entry.getValue(); |
| |
| final EObject alreadyContainedElement = getModelElement(modelElementId); |
| |
| // if model element to be allocated is different to |
| // model element with same ID in cache OR if model |
| // element ID is not yet in cache |
| if (alreadyContainedElement != modelElement) { |
| if (alreadyContainedElement != null) { |
| eObjectToIdMap.put(modelElement, modelElementId.getId()); |
| idToEObjectMap.put(modelElementId.getId(), modelElement); |
| } else { |
| // do this even if the model element is already contained; |
| // this is the case when a copied instance of the model element gets |
| // added again |
| putIntoAllocatedCaches(modelElement, modelElementId); |
| } |
| } |
| } |
| } |
| |
| /** |
| * |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection#disallocateModelElementIds(java.util.Set) |
| */ |
| public void disallocateModelElementIds(Set<ModelElementId> modelElementIds) { |
| for (final ModelElementId modelElementId : modelElementIds) { |
| allocatedIdToEObjectMap.remove(modelElementId.getId()); |
| allocatedEObjectToIdMap.values().remove(modelElementId.getId()); |
| } |
| } |
| |
| /** |
| * |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection#clearAllocatedCaches() |
| */ |
| public void clearAllocatedCaches() { |
| allocatedEObjectToIdMap.clear(); |
| allocatedIdToEObjectMap.clear(); |
| } |
| |
| /** |
| * |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection#clearAllocatedCaches(java.util.Set) |
| */ |
| public void clearAllocatedCaches(Set<ModelElementId> modelElementIds) { |
| allocatedIdToEObjectMap.keySet().removeAll(modelElementIds); |
| allocatedEObjectToIdMap.values().removeAll(modelElementIds); |
| } |
| |
| private void putIntoAllocatedCaches(EObject modelElement, ModelElementId modelElementId) { |
| allocatedEObjectToIdMap.put(modelElement, modelElementId.getId()); |
| allocatedIdToEObjectMap.put(modelElementId.getId(), modelElement); |
| } |
| |
| private ModelElementId getNewModelElementID() { |
| // if there is registered modelElementIdGenerator, use it |
| if (modelElementIdGenerator != null) { |
| final ESModelElementIdImpl modelElementId = (ESModelElementIdImpl) modelElementIdGenerator |
| .generateModelElementId(this); |
| return modelElementId.toInternalAPI(); |
| } |
| |
| // else create it via ModelFactory |
| return ModelFactory.eINSTANCE.createModelElementId(); |
| } |
| |
| /** |
| * |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.common.model.ESIdToEObjectMapping#get(java.lang.Object) |
| */ |
| public EObject get(ModelElementId modelElementId) { |
| final EObject modelElement = getModelElement(modelElementId); |
| if (modelElement != null) { |
| return modelElement; |
| } |
| return getDeletedModelElement(modelElementId); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection#getIdToEObjectMapping() |
| */ |
| public Map<String, EObject> getIdToEObjectMapping() { |
| return idToEObjectMap; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection#getEObjectToIdMapping() |
| */ |
| public Map<EObject, String> getEObjectToIdMapping() { |
| return eObjectToIdMap; |
| } |
| |
| /** |
| * Removes a model element. |
| * |
| * @param modelElement the element to remove |
| */ |
| public void removeModelElement(EObject modelElement) { |
| getModelElements().remove(modelElement); |
| } |
| |
| } |