blob: 55050eac9b71018f69efcab523cfdd116fec3af2 [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2015 CEA LIST.
*
*
* 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:
* Sebastien Revol (CEA LIST) sebastien.revol@cea.fr - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.interoperability.rpy.importer;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EModelElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.osgi.util.NLS;
import org.eclipse.papyrus.interoperability.rpy.Activator;
import org.eclipse.papyrus.interoperability.rpy.importer.utils.RpyFileHandler;
import org.eclipse.papyrus.interoperability.rpy.importer.utils.RpyFileUtils;
import org.eclipse.papyrus.interoperability.rpy.importer.utils.RpyProjectHandler;
import org.eclipse.papyrus.interoperability.rpy.importer.utils.RpyUtil;
import org.eclipse.papyrus.interoperability.rpy.messages.Messages;
import org.eclipse.papyrus.interoperability.rpy.parser.rpySyntax.RpyContent;
import org.eclipse.papyrus.interoperability.rpy.parser.rpySyntax.RpyFeature;
import org.eclipse.papyrus.interoperability.rpy.parser.rpySyntax.RpyFeatureValue;
import org.eclipse.papyrus.interoperability.rpy.parser.rpySyntax.RpyFile;
import org.eclipse.papyrus.interoperability.rpy.parser.rpySyntax.RpyNode;
import org.eclipse.papyrus.interoperability.rpy.parser.rpySyntax.RpyNodeList;
import org.eclipse.papyrus.interoperability.rpy.parser.rpySyntax.RpySimpleValueElement;
import org.eclipse.papyrus.interoperability.rpy.parser.rpySyntax.SimpleValueList;
import org.eclipse.papyrus.interoperability.rpy.rpymetamodel.IProject;
import org.eclipse.papyrus.interoperability.rpy.rpymetamodel.UMLRpyFactory;
import org.eclipse.papyrus.interoperability.rpy.rpymetamodel.UMLRpyPackage;
/**
* @author sr246418
*
*/
public class UMLRpyImporter {
private RpyProjectHandler projectHandler;
private ResourceSet resSet = new ResourceSetImpl();
private IProject rootProject = null;
private String targetPath;
Map<EObject, EObject> transformedObjectMap = new HashMap<EObject, EObject>();
Map<RpyFileHandler, Resource> fileToResourceMap = new HashMap<RpyFileHandler, Resource>();
// TODO : would be better with URI instead of string
public UMLRpyImporter(String rpyPath, String targetPath) {
projectHandler = new RpyProjectHandler(rpyPath);
this.targetPath = targetPath;
}
// public UMLRpyImporter(URI rpyPath, String targetPath){
// projectHandler = new RpyProjectHandler(rpyPath);
// this.targetPath = targetPath;
// }
public IProject getRootProject() {
if (rootProject == null) {
doTransformation();
}
return (rootProject);
}
public void save() {
Map<Object, Object> options = new HashMap<Object, Object>();
options.put(XMLResource.OPTION_ESCAPE_USING_CDATA, true);
options.put(XMLResource.OPTION_XML_VERSION, "1.1");
for (Resource res : resSet.getResources()) {
try {
res.save(options);
} catch (IOException e) {
Activator.log.error(e);
}
}
}
/**
*
*/
private void doTransformation() {
RpyFileHandler projectFileHandler = projectHandler.getProjectFile();
EObject rootTransformedObject = transform(projectFileHandler);
// post transformation cleaning
if (rootTransformedObject instanceof IProject) {
rootProject = (IProject) rootTransformedObject;
if (projectFileHandler.getRpyFile() != null && projectFileHandler.getRpyFile().getVersion() != null) {
// set the RPY version to the project
rootProject.setVersion(projectFileHandler.getRpyFile().getVersion());
}
// embedd the transformed proxies in the root resource (proxies are placeholder for not found references)
for (RpyNode proxyNode : projectHandler.getAllProxies()) {
EObject transformedProxy = transformedObjectMap.get(proxyNode);
if (transformedProxy != null) {
rootProject.eResource().getContents().add(transformedProxy);
}
}
}
}
/**
* @param projectFileHandler
* @return
*/
private EObject transform(RpyFileHandler rpyFileHandler) {
Resource outputRes = getResource(rpyFileHandler);
if (outputRes.getContents().isEmpty() || outputRes.getContents().get(0) instanceof EAnnotation) {
RpyFile rpyFile = rpyFileHandler.getRpyFile();
List<EObject> roots = new ArrayList<EObject>();
for (RpyContent fileContent : rpyFile.getContents()) {
if (fileContent instanceof RpyNode) {
EObject ret = transformNode((RpyNode) fileContent);
if (ret != null) {
roots.add(ret);
}
}
}
outputRes.getContents().addAll(0, roots);
}
if (outputRes.getContents().isEmpty()) {
return null;
} else {
return outputRes.getContents().get(0);
}
}
/**
* @param fileContent
* @param rpyFileHandler
*/
private EObject transformNode(RpyNode node) {
EObject ret = transformedObjectMap.get(node);
if (ret == null) {
String nodeName = node.getName();
EClass targetEClass = (EClass) UMLRpyPackage.eINSTANCE.getEClassifier(nodeName);
if (targetEClass != null) {
ret = UMLRpyFactory.eINSTANCE.create(targetEClass);
transformedObjectMap.put(node, ret);
List<EObject> subNodes = new ArrayList<EObject>();
for (RpyContent nodeContent : node.getContents()) {
if (nodeContent instanceof RpyFeature) {
transformFeature(ret, (RpyFeature) nodeContent);
} else if (nodeContent instanceof RpyNode) {
EObject transformedNode = transformNode((RpyNode) nodeContent);
if (transformedNode != null) {
subNodes.add(transformedNode);
}
}
}
if (!subNodes.isEmpty()) {
EStructuralFeature graphicalElementsFeature = targetEClass.getEStructuralFeature(RpyUtil.OWNED_ELEMENT_FEATURE_NAME);
if (graphicalElementsFeature != null) {
setEReferenceValue(ret, graphicalElementsFeature, subNodes);
}
}
}
}
return ret;
}
/**
* @param ret
* @param nodeContent
* @param rpyFileHandler
*/
private void transformFeature(EObject receiver, RpyFeature rpyFeature) {
EStructuralFeature targetFeature = receiver.eClass().getEStructuralFeature(rpyFeature.getName().replaceAll("^_", ""));
if (targetFeature != null) {
RpyFeatureValue rpyFeatureValue = RpyUtil.getFeatureValue(rpyFeature);
if (rpyFeatureValue instanceof SimpleValueList) {
if (RpyUtil.isDirectReference(rpyFeature)) {
RpyNode referencedNode = projectHandler.getSimpleFeatureReferencedNode(rpyFeature);
transformOwningHandlerIfDifferent(referencedNode, rpyFeature);
EObject value = transformNode(referencedNode);
if (value != null && targetFeature instanceof EReference && isCompatibleType((EReference) targetFeature, value)) {
setEReferenceValue(receiver, targetFeature, value);
}
} else if (targetFeature instanceof EAttribute) {
if (targetFeature.isMany()) {
List featValueList = (List) receiver.eGet(targetFeature);
for (RpySimpleValueElement valueElement : ((SimpleValueList) rpyFeatureValue).getValueElements()) {
for (String value : valueElement.getValues()) {
featValueList.add(value.replaceAll("^\"", "").replaceAll("\"$", ""));
}
}
} else {
receiver.eSet(targetFeature, RpyUtil.getStringValue((SimpleValueList) rpyFeatureValue).replaceAll("^\"", "").replaceAll("\"$", ""));
}
}
} else if (rpyFeatureValue instanceof RpyNodeList) {
RpyNodeList nodeList = (RpyNodeList) rpyFeatureValue;
List<EObject> transformedObjects = new ArrayList<EObject>();
for (RpyNode rpyNode : projectHandler.getNodes(nodeList)) {
transformOwningHandlerIfDifferent(rpyNode, rpyFeature);
EObject targetObject = transformNode(rpyNode);
if (targetObject != null) {
transformedObjects.add(targetObject);
}
}
if (targetFeature instanceof EReference
&& isCompatibleType((EReference) targetFeature, transformedObjects)) {
setEReferenceValue(receiver, targetFeature, transformedObjects);
}
}
} else {
RpyNode sourceNode = (RpyNode) rpyFeature.eContainer();
if (RpyUtil.HANDLE_FILE_NAME_REF.equals(rpyFeature.getName())) {
EAnnotation eannotation = EcoreFactory.eINSTANCE.createEAnnotation();
String fileName = ((SimpleValueList) rpyFeature.getValue()).getValueElements().get(0).getValues().get(0);
// we remove the quote around the file name
if (fileName.startsWith("\"")) {
fileName = fileName.substring(1);
}
if (fileName.endsWith("\"")) {
fileName = fileName.substring(0, fileName.length() - 1);
}
eannotation.getDetails().put(RpyUtil.ELEMENT_FILE_NAME_REF, fileName);
eannotation.setSource(RpyUtil.EANNOTATION_SOURCE__RPY_FILENAME);
if (receiver instanceof EModelElement) {
((EModelElement) receiver).getEAnnotations().add(eannotation);
}
} else {
Activator.log.error(
NLS.bind(Messages.UMLRpyImporter_FeatureNotFound, new String[] { rpyFeature.getName(), receiver.eClass().getName(), RpyUtil.getNodeIndexInFile(sourceNode), projectHandler.getOwningFileHandler(sourceNode).getURI().toFileString() }),
null);
}
}
}
/**
* @param referencedNode
* @param rpyFeature
*/
private void transformOwningHandlerIfDifferent(RpyNode referencedNode, RpyFeature rpyFeature) {
RpyFileHandler referencedNodeHandler = projectHandler.getOwningFileHandler(referencedNode);
if (referencedNodeHandler != null && referencedNodeHandler != projectHandler.getOwningFileHandler((RpyNode) rpyFeature.eContainer())) {
transform(referencedNodeHandler);
}
}
/**
* @param receiver
* @param targetFeature
* @param value
*/
private void setEReferenceValue(EObject receiver, EStructuralFeature targetFeature, Object value) {
if (targetFeature.isMany()) {
List receiverList = (List) receiver.eGet(targetFeature);
if (value instanceof List) {
receiverList.addAll((List) value);
} else {
receiverList.add(value);
}
} else {
if (value instanceof List) {
if (!((List) value).isEmpty()) {
receiver.eSet(targetFeature, ((List) value).get(0));
}
} else {
receiver.eSet(targetFeature, value);
}
}
}
private boolean isCompatibleType(EReference targetReference, Object value) {
boolean result = true;
EClass containingEClass = targetReference.getEContainingClass();
EClass eType = targetReference.getEReferenceType();
if (value instanceof Collection) {
for (Object valueElement : (Collection) value) {
if (!eType.isInstance(valueElement)) {
result = false;
value = valueElement;
break;
}
}
} else {
result = eType.isInstance(value);
}
if (!result) {
Activator.log.warn("Object " + value + " has an incompatible type with " + eType.getName() + " of feature "
+ targetReference.getName() + " of EClass " + containingEClass.getName()
+ ".\n This element won't be imported. RpyMetamodel implementation in Papyrus should be updated");
}
return result;
}
/**
* @param rpyFileHandler
* @return
*/
private Resource getResource(RpyFileHandler rpyFileHandler) {
Resource ret = fileToResourceMap.get(rpyFileHandler);
if (ret == null) {
URI inURI = rpyFileHandler.getURI();
if (inURI != null) {
URI outURI = URI.createFileURI(targetPath).appendSegment(inURI.trimFileExtension().lastSegment()).appendFileExtension(RpyFileUtils.UML_RPY_FILE);
ret = resSet.createResource(outURI);
fileToResourceMap.put(rpyFileHandler, ret);
}
}
return ret;
}
}