blob: 70240a5b49811fdce3879aa6c8a162025bcb8f3c [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2017 CEA LIST and others.
*
* 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:
* CEA LIST - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.interoperability.rpy.xmi;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.xmi.XMIResource;
import org.eclipse.m2m.internal.qvt.oml.library.Context;
import org.eclipse.papyrus.interoperability.common.utils.TraceHelper;
import org.eclipse.papyrus.interoperability.rpy.importer.utils.RpyUtil;
import org.eclipse.uml2.uml.ConnectorEnd;
import org.eclipse.uml2.uml.util.UMLUtil;
/**
* @author VL222926
*
* This class allows to reuse Rpy id when possible end and calls helper to generate "standard" XMI_ID when we can't reuse Rpy ones.
*
*/
public class PreserveRpySemanticIDHelper {
/**
* The context of the QVTo transformation
*/
@SuppressWarnings("restriction")
private Context context;
/**
* the name of the feature representing the Rpy ID
*/
private static final String ID_FEATURE_NAME = "id"; //$NON-NLS-1$
/**
* The helper to use to manipulate QVTo trace
*/
private TraceHelper helper = new TraceHelper();
/**
*
* Constructor.
*
* @param context
* the context of the QVTo transformation
*/
public PreserveRpySemanticIDHelper(@SuppressWarnings("restriction") final Context context) {
this.context = context;
}
public void keepIdForUMLResource(final XMIResource res) {
// a set owning the known id to avoid duplicate
final Set<String> knownIds = new HashSet<String>();
// the object to manage in the second run
final List<EObject> eobjectForSecondRun = new ArrayList<>();
// we mainly set the stereotype application in this list
final List<EObject> eobjectForThirdRun = new ArrayList<>();
// we iterate on all elements of the UML model
final TreeIterator<EObject> iter = res.getAllContents();
while (iter.hasNext()) {
final EObject current = iter.next();
if (isStereotypeApplication(current)) {
eobjectForThirdRun.add(current);
continue;
}
if (requiredToBeManagedInASecondRun(current)) {
eobjectForSecondRun.add(current);
continue;
}
// looking for the Rpy object in the QVto trace
final Object result = helper.traceFrom(context, current, null);
String rpyId = getRpyId(result);
if (isValidId(rpyId) && false == knownIds.contains(rpyId)) {
knownIds.add(rpyId);
res.setID(current, rpyId);
} else {
eobjectForSecondRun.add(current);
}
}
// second run (duplicated and null id in the first run)
for (final EObject current : eobjectForSecondRun) {
final String value = XMI_ID_Helper.calculateXMI_ID(current);
if (isValidId(value) && false == knownIds.contains(value)) {
knownIds.add(value);
res.setID(current, value);
} else {
System.out.println("It is not possible to found an id for " + current.toString()); //$NON-NLS-1$
}
}
// third run (stereotype)
for (final EObject current : eobjectForThirdRun) {
final String value = XMI_ID_Helper.calculateXMI_ID(current);
if (isValidId(value) && false == knownIds.contains(value)) {
knownIds.add(value);
res.setID(current, value);
} else {
System.out.println("It is not possible to found an id for " + current.toString()); //$NON-NLS-1$
}
}
}
/**
*
* @param eobject
* an eobject
* @return
* <code>true</code> if the object must be manage during the second run
*/
protected boolean requiredToBeManagedInASecondRun(final EObject eobject) {
return eobject instanceof ConnectorEnd;
}
/**
*
* @param object
* a rpy object
* @return
* the id of this object or <code>null</code> if not found
*/
protected String getRpyId(final Object object) {
if (object instanceof EObject) {
final EObject eobject = (EObject) object;
final EStructuralFeature idFeature = eobject.eClass().getEStructuralFeature(ID_FEATURE_NAME);
if (null != idFeature) {
final String value = (String) eobject.eGet(idFeature);
return value;
}
}
return null;
}
/**
*
* @param eobject
* an eobject
* @return
* <code>true</code> when the element represents a stereotype application
*/
protected boolean isStereotypeApplication(final EObject eobject) {
return null != UMLUtil.getBaseElement(eobject);
}
/**
*
* @param id
* an id
* @return
* <code>true</code> when the string represents a valid id : so it must contains GUID or OLDID
*/
public static final boolean isValidId(final String id) {
return null != id && (id.contains(RpyUtil.GUID_STRING) || id.contains(RpyUtil.OLDID_STRING));
}
}