blob: a93521421ec6be980f52836f63ac8e9768497559 [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.utils;
import java.io.File;
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.apache.commons.io.FileUtils;
import org.eclipse.emf.common.util.URI;
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.osgi.util.NLS;
import org.eclipse.papyrus.interoperability.rpy.Activator;
import org.eclipse.papyrus.interoperability.rpy.messages.Messages;
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.RpyStringMap;
import org.eclipse.papyrus.interoperability.rpy.parser.rpySyntax.RpyStringMapEntry;
import org.eclipse.papyrus.interoperability.rpy.parser.rpySyntax.SimpleValueList;
import com.google.common.io.Files;
/**
* @author sr246418
* Class allowing to easily parse Rpy projects.
* It can return a CST or an AST instance of the parsed files.
*/
// TODO decide which techno use for file:
// emf URI is ok, but we should should between java.nio, java, io, apache and google
public class RpyProjectHandler {
private RpyFileHandler projectFile;
public RpyFileHandler getProjectFile() {
return projectFile;
}
private RpyFileHandler fileTable = null;
private Map<String, RpyFileHandler> uriToHandler = new HashMap<String, RpyFileHandler>();
private Map<Resource, RpyFileHandler> resourceToHandlerMap = new HashMap<Resource, RpyFileHandler>();
private Map<String, String> aliasToPathMap = new HashMap<String, String>();
private Map<String, RpyNode> idToProxyNode = new HashMap<String, RpyNode>();
private URI projectURI = null;
private ResourceSet resSet;
private URI rpyProjectFolderURI = null;
private static final String RPY_SUFFIX = "_rpy";
private static final String FILE_TABLE_NAME = "filesTable.dat";
private static final String FILE_TABLE_FEATURE_NAME = "filesTable";
private static final String OM_ROOT = "$OMROOT";
/**
*
* Constructor.
*
* @param rpyFileURi
* the URI of the file selected by the user (should be a uri like this : file:C:/...)
*/
// TODO : not yet used , not working yet
public RpyProjectHandler(final URI rpyFileURi) {
initializeExtensions();
this.resSet = new ResourceSetImpl();
this.projectURI = rpyFileURi;
projectFile = getRpyFileHandler(projectURI.toFileString());
String rpyFolder = projectURI.trimFileExtension().lastSegment() + RPY_SUFFIX;
rpyProjectFolderURI = projectURI.trimSegments(1).appendSegment(rpyFolder).appendSegment("");
loadFileTable();
}
// TODO : replaced by an other constructor with URI
public RpyProjectHandler(String rpyPath) {
initializeExtensions();
resSet = new ResourceSetImpl();
projectURI = getNormalizedURI(rpyPath);
projectFile = getRpyFileHandler(projectURI.toFileString());
String rpyFolder = projectURI.trimFileExtension().lastSegment() + RPY_SUFFIX;
rpyProjectFolderURI = projectURI.trimSegments(1).appendSegment(rpyFolder).appendSegment("");
loadFileTable();
}
/**
*
*/
private void initializeExtensions() {
}
/**
*
*/
private void loadFileTable() {
URI fileTableURI = rpyProjectFolderURI.appendSegment(FILE_TABLE_NAME);
Resource fileTableRes = getResource(fileTableURI);
if (fileTableRes != null && !fileTableRes.getContents().isEmpty()) {
fileTable = new RpyFileHandler(fileTableRes, this);
RpyFile rpyTableFile = fileTable.getRpyFile();
if (rpyTableFile != null && !rpyTableFile.getContents().isEmpty() && rpyTableFile.getContents().get(0) instanceof RpyFeature) {
RpyFeature rootFeature = (RpyFeature) rpyTableFile.getContents().get(0);
if (FILE_TABLE_FEATURE_NAME.equals(rootFeature.getName()) && rootFeature.getValue() instanceof RpyNodeList) {
RpyFeatureValue value = RpyUtil.getFeatureValue(rootFeature);
if (value instanceof RpyStringMap) {
for (RpyStringMapEntry entry : ((RpyStringMap) value).getEntries()) {
if (!entry.getValue().isEmpty()) {
// remark key and value are switched compared to what has been defined in the RpySyntax
String entryValue = entry.getValue();
aliasToPathMap.put(entryValue, entry.getKey());
if (entryValue.contains(" ")) {
aliasToPathMap.put(entryValue.replaceAll(" ", "_"), entry.getKey());
}
}
}
}
}
}
}
}
private Resource getResource(URI uri) {
if (this.resSet.getURIConverter().exists(uri, null)) {
return resSet.getResource(uri, true);
} else {
return null;
}
}
/**
* @param rpyPath
*/
public void loadSubFiles() {
File rpyProjectFolder = new File(rpyProjectFolderURI.toFileString());
if (rpyProjectFolder.exists() && rpyProjectFolder.isDirectory()) {
for (File subFile : FileUtils.listFiles(rpyProjectFolder, null, true)) {
URI subFileURI = getNormalizedURI(subFile.getAbsolutePath());
if (RpyUtil.SUPPORTED_EXTENSIONS.contains(subFileURI.fileExtension())) {
if (!FILE_TABLE_NAME.equals(subFileURI.lastSegment())) {
uriToHandler.put(subFileURI.toFileString(), getRpyFileHandler(subFileURI.toFileString()));
}
} else {
Activator.log.info(NLS.bind(Messages.RpyProjectHandler_IgnoredSubFile, subFileURI.toFileString()));
}
}
}
}
/**
* This method copy the current rpy project in a new folder given as argument.
* This method doesn't change the URI on which work this class after the copy
*
* @param newPath
* the new path for the rpy project
* @return
* the URi of the *.rpy file of the project
*/
public URI copyRpyProjectToNewFolder(final URI newPath) {
URI uri = projectURI.trimSegments(1);// to get the parent folder
File rpyProjectFolder = new File(uri.toFileString());
List<File> duplicatedFile = new ArrayList<File>();
if (rpyProjectFolder.exists() && rpyProjectFolder.isDirectory()) {
for (File subFile : rpyProjectFolder.listFiles()) {
duplicatedFile.addAll(copyFile(subFile, newPath));
}
}
for (File current : duplicatedFile) {
URI newURI = URI.createFileURI(current.getPath());
if (RpyFileUtils.FILE_EXTENSION_RPY.equals(newURI.fileExtension())) {
return newURI;
}
}
return null;
}
/**
* This method copy a file to a given path. The File can be a directory. In this case, we create it in the new path with its contents
*
* @param src
* the source file (can be a directory
* @param target
* the target path for the copied file
* @return
* the file of copied file (useful in case of folder
*/
public List<File> copyFile(final File src, final URI target) {
List<File> duplicatedFile = new ArrayList<File>();
URI copiedFileURI = URI.createFileURI(target.devicePath());
copiedFileURI = copiedFileURI.appendSegment(src.getName());
if (src.isDirectory()) {
File folder = new File(copiedFileURI.devicePath());
folder.mkdir();
for (File f : src.listFiles()) {
duplicatedFile.addAll(copyFile(f, copiedFileURI));
}
} else {
File newFile = new File(copiedFileURI.devicePath());
try {
Files.copy(src, newFile);
duplicatedFile.add(newFile);
} catch (IOException e) {
Activator.log.error(e);
}
}
return duplicatedFile;
}
private URI getNormalizedURI(String fileString) {
// TODO : improve me
if (fileString.startsWith(OM_ROOT)) {
return null;
}
fileString = fileString.replaceAll("\\\\\\\\", "\\\\");
fileString = fileString.replaceAll("//", "/");
URI uri = URI.createFileURI(fileString);
if (uri.isRelative()) {
uri = uri.resolve(rpyProjectFolderURI);
}
return resSet.getURIConverter().normalize(uri);
}
public List<RpyFileHandler> getFiles() {
List<RpyFileHandler> ret = new ArrayList<RpyFileHandler>();
ret.add(projectFile);
ret.addAll(uriToHandler.values());
return ret;
}
public RpyFileHandler getOwningFileHandler(RpyNode node) {
Resource nodeResource = node.eResource();
return resourceToHandlerMap.get(nodeResource);
}
public RpyNode getSimpleFeatureReferencedNode(RpyFeature feature) {
if (RpyUtil.isDirectReference(feature)) {
String id = RpyUtil.getStringValue((SimpleValueList) feature.getValue());
RpyNode owningNode = (RpyNode) feature.eContainer();
if (owningNode != null) {
RpyFileHandler owningHandler = getOwningFileHandler(owningNode);
if (owningHandler != null) {
return owningHandler.getNodeById(id);
}
}
}
return null;
}
public List<RpyNode> getNodes(RpyNodeList nodeList) {
List<RpyNode> ret = new ArrayList<RpyNode>();
for (RpyNode node : nodeList.getValues()) {
if (RpyUtil.RAW_CONTAINER_NAME.equals(node.getName())) {
RpyFeatureValue value = RpyUtil.getNodeFeatureValue(node, RpyUtil.RAW_CONTAINER_VALUE_FEATURE_NAME);
if (value instanceof RpyNodeList) {
ret.addAll(getNodes((RpyNodeList) value));
}
} else if (RpyUtil.isRpyIHandle(node)) {
RpyNode referencedNode = getReferencedNodeFromIHandle(node);
if (referencedNode != null) {
ret.add(referencedNode);
}
} else if (RpyUtil.isElementRef(node)) {
RpyNode referencedNode = getReferencedNodeFromElementRef(node);
if (referencedNode != null) {
ret.add(referencedNode);
}
} else {
ret.add(node);
}
}
return ret;
}
/**
* @param node
* @return
*/
private RpyNode getReferencedNodeFromElementRef(RpyNode node) {
String referencedFileName = RpyUtil.getElementFileRef(node);
if (referencedFileName != null) {
if (referencedFileName.isEmpty()) {
// the "fileName" attribute is an empty string, it is a reference in the current file
return getReferencedNodeInFileHandler(node, resourceToHandlerMap.get(node.eResource()), true);
} else {
String persistAt = RpyUtil.getElementPersistAt(node);
if (persistAt != null) {
referencedFileName = persistAt + "/" + referencedFileName;
if (!persistAt.startsWith(OM_ROOT)) {
URI currentNodeURI;
// if the reference is in the rpy file, the path is relative to the rpy_folder
if (node.eResource() == projectFile.getRpyFile().eResource()) {
currentNodeURI = rpyProjectFolderURI;
} else {
// else the pas is relative to the current file
currentNodeURI = node.eResource().getURI();
}
currentNodeURI = currentNodeURI.trimSegments(1);
referencedFileName = currentNodeURI.toFileString() + "/" + referencedFileName;
}
} else {
URI currentNodeURI = node.eResource().getURI();
String resourceURIString = currentNodeURI.toFileString();
if (!resourceURIString.startsWith(projectFile.getRpyFile().eResource().getURI().trimSegments(1).toFileString())) {
referencedFileName = currentNodeURI.trimSegments(1).toFileString() + File.separator + referencedFileName;
}
}
RpyFileHandler handler = getRpyFileHandler(referencedFileName);
if (handler == null) {
if (false == referencedFileName.startsWith(OM_ROOT)) {
//we log only in other case, because file starting with OMROOT are licenced file, so we don't read them
String filePathWithWrongRef = node.eResource().getURI().toFileString();
Activator.log.error(NLS.bind(Messages.RpyProjectHandler_FileNotFoundElementReference, new String[] { referencedFileName, RpyUtil.getNodeIndexInFile(node), filePathWithWrongRef }), null);
}
} else {
return getReferencedNodeInFileHandler(node, handler, true);
}
}
}
return null;
}
/**
* @param handlerNode
* @return
*/
private RpyNode getReferencedNodeFromIHandle(RpyNode handlerNode) {
String id = RpyUtil.getReferencedID(handlerNode);
// we first check is the referenced element is not a local proxy to previously not found element
RpyNode proxy = idToProxyNode.get(id);
if (proxy != null) {
return proxy;
}
// we first look at the _filename attribute
String filePath = RpyUtil.getIHandleFileRef(handlerNode);
if (filePath == null) {
filePath = "";
}
if (filePath.isEmpty()) {
// if the _filename feature is an empty string, it can be either in the current file, or in the root project RpyFile
RpyNode localNode = getReferencedNodeInFileHandler(handlerNode, resourceToHandlerMap.get(handlerNode.eResource()), false);
if (localNode != null) {
return localNode;
} else {
localNode = getReferencedNodeInFileHandler(handlerNode, projectFile, false);
if (localNode != null) {
return localNode;
}
}
} else {
RpyFileHandler fileHandler = getRpyFileHandler(filePath);
if (fileHandler != null) {
RpyNode referencedNode = getReferencedNodeInFileHandler(handlerNode, fileHandler, false);
if (referencedNode != null) {
// ok we got it!
return referencedNode;
}
}
}
// here either fileHandler is null (didn't find the referenced filename), either we didn't find
// the searched node in the referenced file.
// First case can occur for files located in subfolders for instance, and the real path to file should be
// found in the fileTable.dat
// Second case occurs when the node is indeed in a "subfile" of the root referenced file. The fileTable.dat
// should help here as well...
String referencedSubsystem = RpyUtil.getReferencedSubsystemFromHandle(handlerNode);
String referencedClass = RpyUtil.getReferencedClassFromHandle(handlerNode);
String referencedName = RpyUtil.getReferencedNameFromHandle(handlerNode);
List<String> namesToTry = new ArrayList<String>();
String referencedQN = "";
if (referencedSubsystem != null) {
namesToTry.add(referencedSubsystem);
referencedQN += referencedSubsystem;
}
if (referencedClass != null) {
if (referencedSubsystem == null) {
namesToTry.add(referencedClass);
} else {
referencedQN += "::" + referencedClass;
namesToTry.add(referencedQN);
}
}
if (referencedName != null) {
if (referencedQN.isEmpty()) {
namesToTry.add(referencedName);
} else {
referencedQN += "::" + referencedName;
namesToTry.add(referencedQN);
}
}
for (String nameToTry : namesToTry) {
filePath = aliasToPathMap.get(nameToTry);
if (filePath != null) {
filePath = "../" + filePath;
RpyFileHandler fileHandler = getRpyFileHandler(filePath);
if (fileHandler != null) {
RpyNode result = getReferencedNodeInFileHandler(handlerNode, fileHandler, false);
if (result != null) {
return result;
}
} else {
logFileNodeFound(handlerNode, filePath);
}
}
}
// if we arrive here, we have not found the node with the fileTable.dat
// we give-up
proxy = RpyUtil.createProxyNodeFromHandler(handlerNode);
if (proxy != null) {
idToProxyNode.put(id, proxy);
}
return proxy;
}
/**
* @param node
* @param filePath
*/
private void logFileNodeFound(RpyNode node, String filePath) {
String filePathWithWrongRef = node.eResource().getURI().toFileString();
Activator.log.error(NLS.bind(Messages.RpyProjectHandler_FileNotFoundHandleReference, new String[] { filePath, RpyUtil.getNodeIndexInFile(node), filePathWithWrongRef }), null);
}
/**
* @param referencedURI
* @return
*/
private RpyFileHandler getRpyFileHandler(String uriString) {
boolean isExternal = uriString.startsWith(OM_ROOT);
URI referencedURI = getNormalizedURI(uriString);
if (referencedURI != null) {
RpyFileHandler result = uriToHandler.get(referencedURI.toFileString());
if (result == null) {
Resource resource = getResource(referencedURI);
if (resource != null) {
result = new RpyFileHandler(resource, this);
uriToHandler.put(referencedURI.toFileString(), result);
resourceToHandlerMap.put(resource, result);
}
}
return result;
}
return null;
}
/**
* @param node
* @param handler
* @return
*/
private RpyNode getReferencedNodeInFileHandler(RpyNode node, RpyFileHandler handler, boolean log) {
String id = RpyUtil.getReferencedID(node);
RpyNode referencedNode = null;
if (id != null) {
referencedNode = handler.getNodeById(id);
}
if (referencedNode != null && RpyUtil.isElementRef(referencedNode)) {
return getReferencedNodeFromElementRef(referencedNode);
}
if (referencedNode == null && log) {
logIDNotFound(handler, node);
}
return referencedNode;
}
/**
* @param id
* @param handler
* @param node
*/
private void logIDNotFound(RpyFileHandler handler, RpyNode node) {
String id = RpyUtil.getReferencedID(node);
String filePathWithWrongRef = node.eResource().getURI().toFileString();
Activator.log.error(NLS.bind(Messages.RpyProjectHandler_NotFoundIDReference, new String[] { id, handler.getRpyFile().eResource().getURI().toFileString(), RpyUtil.getNodeIndexInFile(node), filePathWithWrongRef }), null);
}
public Collection<RpyNode> getAllProxies() {
return idToProxyNode.values();
}
}