/******************************************************************************* * Copyright (c) 2012, 2014 Obeo. * 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: * Obeo - initial API and implementation *******************************************************************************/ package org.eclipse.emf.compare.match.eobject; import com.google.common.base.Function; import java.util.Iterator; import java.util.List; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.compare.utils.ReferenceUtil; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EFactory; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.impl.BasicEObjectImpl; import org.eclipse.emf.ecore.util.EContentsEList; import org.eclipse.emf.ecore.util.FeatureMap; import org.eclipse.emf.ecore.util.InternalEList; /** * A function computing an URI Fragment. This implementation is based on * org.eclipse.emf.ecore.impl.BasicEObjectImpl.eURIFragmentSegment(EStructuralFeature, EObject) no ID or * specific code for a given EObject instance will be used, and that's on purpose, in the case of UML models * for instance the specialization of the eURIFragment() method leads to a massive loss of performance for no * added value in our current use case (matching references). * * @author <a href="mailto:cedric.brun@obeo.fr">Cedric Brun</a> */ public class EUriFragmentFunction implements Function<EObject, String> { /** * {@inheritDoc} */ public String apply(EObject input) { EObject container = input.eContainer(); EStructuralFeature feat = input.eContainingFeature(); if (container instanceof BasicEObjectImpl) { // String frag = ((BasicEObjectImpl)container).eURIFragmentSegment(feat, input); return eURIFragmentSegment(container, feat, input); } return null; } // CHECKSTYLE:OFF // TODO Comment the checkstyle suppression. Was that copy/pasted from somewhere? public String eURIFragmentSegment(EObject container, EStructuralFeature eStructuralFeature, EObject eObject) { EStructuralFeature actualFeature = eStructuralFeature; if (actualFeature == null) { for (@SuppressWarnings("unchecked") EContentsEList.FeatureIterator<EObject> crossReferences = (EContentsEList.FeatureIterator<EObject>)((InternalEList<?>)container .eCrossReferences()).basicIterator(); crossReferences.hasNext();) { EObject crossReference = crossReferences.next(); if (crossReference == eObject) { actualFeature = crossReferences.feature(); } } } assert actualFeature != null; StringBuilder result = new StringBuilder(); result.append('@'); result.append(actualFeature.getName()); if (actualFeature instanceof EAttribute) { FeatureMap featureMap = (FeatureMap)ReferenceUtil.safeEGet(container, actualFeature); for (int i = 0, size = featureMap.size(); i < size; ++i) { if (featureMap.getValue(i) == eObject) { EStructuralFeature entryFeature = featureMap.getEStructuralFeature(i); if (entryFeature instanceof EReference && ((EReference)entryFeature).isContainment()) { result.append('.'); result.append(i); return result.toString(); } } } result.append(".-1"); //$NON-NLS-1$ } else if (actualFeature.isMany()) { EList<EAttribute> eKeys = ((EReference)actualFeature).getEKeys(); if (eKeys.isEmpty()) { EList<?> eList = (EList<?>)ReferenceUtil.safeEGet(container, actualFeature); int index = eList.indexOf(eObject); result.append('.'); result.append(index); } else { EAttribute[] eAttributes = (EAttribute[])((BasicEList<?>)eKeys).data(); result.append('['); for (int i = 0, size = eAttributes.length; i < size; ++i) { EAttribute eAttribute = eAttributes[i]; if (eAttribute == null) { break; } else { if (i != 0) { result.append(','); } result.append(eAttribute.getName()); result.append('='); EDataType eDataType = eAttribute.getEAttributeType(); EFactory eFactory = eDataType.getEPackage().getEFactoryInstance(); if (eAttribute.isMany()) { List<?> values = (List<?>)eObject.eGet(eAttribute); result.append('['); if (!values.isEmpty()) { Iterator<?> j = values.iterator(); eEncodeValue(result, eFactory, eDataType, j.next()); while (j.hasNext()) { result.append(','); eEncodeValue(result, eFactory, eDataType, j.next()); } } result.append(']'); } else { eEncodeValue(result, eFactory, eDataType, eObject.eGet(eAttribute)); } } } result.append(']'); } } return result.toString(); } private void eEncodeValue(StringBuilder result, EFactory eFactory, EDataType eDataType, Object value) { String stringValue = eFactory.convertToString(eDataType, value); if (stringValue == null) { result.append("null"); //$NON-NLS-1$ } else { int length = stringValue.length(); result.ensureCapacity(result.length() + length + 2); result.append('\''); for (int i = 0; i < length; ++i) { char character = stringValue.charAt(i); if (character < ESCAPE.length) { String escape = ESCAPE[character]; if (escape != null) { result.append(escape); continue; } } result.append(character); } result.append('\''); } } @SuppressWarnings("nls") private final String[] ESCAPE = {"%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07", "%08", "%09", "%0A", "%0B", "%0C", "%0D", "%0E", "%0F", "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17", "%18", "%19", "%1A", "%1B", "%1C", "%1D", "%1E", "%1F", "%20", null, "%22", "%23", null, "%25", "%26", "%27", null, null, null, null, "%2C", null, null, "%2F", null, null, null, null, null, null, null, null, null, null, "%3A", null, "%3C", null, "%3E", null, }; // CHECKSTYLE:ON }