/** * <copyright> * * Copyright (c) 2010-2016 Thales Global Services S.A.S. * 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: * Thales Global Services S.A.S. - initial API and implementation * * </copyright> */ package org.eclipse.emf.diffmerge.impl.scopes; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.eclipse.emf.common.util.AbstractTreeIterator; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.diffmerge.api.scopes.IEditableModelScope; import org.eclipse.emf.diffmerge.api.scopes.IFeaturedModelScope; import org.eclipse.emf.diffmerge.api.scopes.IPersistentModelScope; import org.eclipse.emf.diffmerge.util.ModelImplUtil; import org.eclipse.emf.diffmerge.util.structures.FHashSet; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.util.FeatureMapUtil; import org.eclipse.emf.ecore.util.InternalEList; /** * A partial implementation of IFeaturedModelScope based on unbounded EMF containment. * @author Olivier Constant */ public abstract class AbstractModelScope implements IFeaturedModelScope { /** A potentially null object that identifies the origin of the scope */ private Object _originator; /** * Default constructor */ protected AbstractModelScope() { _originator = null; } /** * @see org.eclipse.emf.diffmerge.api.scopes.IModelScope#covers(EObject) */ public boolean covers(EObject element_p) { Iterator<EObject> it = getAllContents(); while (it.hasNext()) { EObject current = it.next(); if (current == element_p) return true; } return false; } /** * @see org.eclipse.emf.diffmerge.api.scopes.IFeaturedModelScope#get(org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EReference) */ public List<EObject> get(EObject source_p, EReference reference_p) { return get(source_p, reference_p, resolveProxies()); } /** * Return the values which are held by the given element via the given * reference, if any. The values may not belong to the scope. * If the given element does not belong to this scope, the behavior of this * method is undefined. * @param source_p a non-null element * @param reference_p a non-null reference * @param resolveProxies_p whether proxies must be resolved * @return an unmodifiable non-null list of the corresponding elements * within this scope, not containing null */ @SuppressWarnings("unchecked") protected List<EObject> get(EObject source_p, EReference reference_p, boolean resolveProxies_p) { List<EObject> result = Collections.emptyList(); try { if (source_p.eIsSet(reference_p)) { Object value = source_p.eGet(reference_p, resolveProxies_p); if (FeatureMapUtil.isMany(source_p, reference_p)) { List<EObject> values = (List<EObject>)value; if (!resolveProxies_p && values instanceof InternalEList) values = ((InternalEList<EObject>)values).basicList(); result = Collections.unmodifiableList(values); } else if (value != null) { result = Collections.singletonList((EObject)value); } } } catch (RuntimeException e) { // Proceed } return result; } /** * @see org.eclipse.emf.diffmerge.api.scopes.IFeaturedModelScope#get(org.eclipse.emf.ecore.EObject, org.eclipse.emf.ecore.EAttribute) */ @SuppressWarnings("unchecked") public List<Object> get(EObject source_p, EAttribute attribute_p) { List<Object> result; try { if (source_p.eIsSet(attribute_p)) { // Attribute is set Object value = source_p.eGet(attribute_p, resolveProxies()); if (FeatureMapUtil.isMany(source_p, attribute_p)) { // Set, many (may contain null values) result = new LinkedList<Object>(); for (Object inValue : (List<Object>)value) { if (inValue != null) result.add(inValue); } result = Collections.unmodifiableList(result); } else if (value != null) { // Set, not many, not null result = Collections.singletonList(value); } else { // Set, not many, null result = Collections.emptyList(); } } else { // Attribute is not set result = Collections.emptyList(); } } catch (RuntimeException e) { result = Collections.emptyList(); } return result; } /** * @see org.eclipse.emf.diffmerge.api.scopes.IModelScope#getAllContents() */ public TreeIterator<EObject> getAllContents() { // Return an iterator which is derived from getAllContents(EObject) return new ModelScopeIterator(this); } /** * @see org.eclipse.emf.diffmerge.api.scopes.IModelScope#getAllContents(org.eclipse.emf.ecore.EObject) */ public TreeIterator<EObject> getAllContents(EObject root_p) { // Return an iterator which is derived from getContents(EObject) return new AbstractTreeIterator<EObject>(root_p, false) { /** The serial version ID */ private static final long serialVersionUID = 1L; /** * @see org.eclipse.emf.common.util.AbstractTreeIterator#getChildren(java.lang.Object) */ @Override public Iterator<EObject> getChildren(Object object_p) { return getContents((EObject)object_p).iterator(); } }; } /** * @see org.eclipse.emf.diffmerge.api.scopes.IModelScope#getAllContentsAsSet() */ public Set<EObject> getAllContentsAsSet() { Set<EObject> result = new FHashSet<EObject>(); Iterator<EObject> it = getAllContents(); while (it.hasNext()) result.add(it.next()); return Collections.unmodifiableSet(result); } /** * @see org.eclipse.emf.diffmerge.api.scopes.IModelScope#getContainer(EObject) */ public EObject getContainer(EObject element_p) { return element_p.eContainer(); } /** * @see org.eclipse.emf.diffmerge.api.scopes.IFeaturedModelScope#getContainment(org.eclipse.emf.ecore.EObject) */ public EReference getContainment(EObject element_p) { return element_p.eContainmentFeature(); } /** * @see org.eclipse.emf.diffmerge.api.scopes.IModelScope#getContents(org.eclipse.emf.ecore.EObject) */ public List<EObject> getContents(EObject element_p) { return element_p.eContents(); } /** * Return an object that characterizes or identifies this scope by default * @return a non-null object */ protected Object getDefaultOriginator() { return this; } /** * @see IPersistentModelScope#getExtrinsicID(EObject) */ protected Object getExtrinsicID(EObject element_p) { // Default implementation only covers XML/XMI Resources return ModelImplUtil.getXMLID(element_p); } /** * @see org.eclipse.emf.diffmerge.api.scopes.IModelScope#getOriginator() */ public Object getOriginator() { return _originator != null? _originator: getDefaultOriginator(); } /** * Return whether proxies must be resolved when this scope is navigated */ protected boolean resolveProxies() { return false; } /** * Set the originator of this scope. * If null, then the default originator will be used. * @see IEditableModelScope#getOriginator() * @param originator_p a potentially null object */ public void setOriginator(Object originator_p) { _originator = originator_p; } /** * @see org.eclipse.emf.diffmerge.api.scopes.IModelScope#size() */ public int size() { int result = 0; Iterator<EObject> it = getAllContents(); while (it.hasNext()) result++; return result; } }