blob: 4e080896995ad9024150d15adc05944e5cfbb401 [file] [log] [blame]
/*****************************************************************************
*
* Copyright (c) 2016 CEA LIST.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* CEA LIST Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.moka.fmi.fmu;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
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.papyrus.moka.fmi.Activator;
import org.eclipse.papyrus.moka.fmi.modeldescription.CoSimulationType;
import org.eclipse.papyrus.moka.fmi.modeldescription.DocumentRoot;
import org.eclipse.papyrus.moka.fmi.modeldescription.FmiModelDescriptionType;
import org.eclipse.papyrus.moka.fmi.modeldescription.FmiPackage;
import org.eclipse.papyrus.moka.fmi.modeldescription.util.FmiResourceFactoryImpl;
import org.eclipse.papyrus.moka.fmi.util.FMIOSDetector;
import org.eclipse.papyrus.moka.fmi.util.FMUResourceUtil;
import org.eclipse.papyrus.moka.fmi.util.UnzipUtility;
public class FMUParser{
File resourceFolder;
File binariesFolder;
FmiModelDescriptionType modelDescription;
String fmuPath;
File fmuFile;
File fmuFolder;
ResourceSet resSet ;
String fmuName;
boolean isUnzipped=false;
public FMUParser(String fmuPath) throws FileNotFoundException{
initializeParser(fmuPath, true);
}
public FMUParser(String fmuPath, boolean autoclean) throws FileNotFoundException{
initializeParser(fmuPath, autoclean);
}
private void initializeParser(String fmuPath, boolean autoclean) throws FileNotFoundException {
initResourceSet();
this.fmuPath = fmuPath ;
fmuFile= new File(fmuPath);
if (!fmuFile.exists()){
throw new IllegalArgumentException("file "+ fmuPath+" doesn't exist");
}
if (fmuFile.isFile()){
fmuName= fmuFile.getName();
if (fmuName.contains(".fmu")){
fmuName = fmuName.substring(0, fmuFile.getName().lastIndexOf(".fmu"));
}
if (autoclean){
setAutoClean();
}
initModelDescriptionFromZip();
}else if (fmuFile.isDirectory()) {
fmuFolder = fmuFile;
fmuName = fmuFile.getName();
isUnzipped = true;
initModelDescriptionFromFolder();
//we don't set autoclean by default when an FMU is initialized from an unzipped folder.
//it is the responsability of the tool which has unzipped the FMU to clean the folder or not
}
}
public void setAutoClean() {
Runtime.getRuntime().addShutdownHook(new Thread("Clean FMU resource tmp folder for "+ this.toString() ){
@Override
public void run() {
if (fmuFolder != null && fmuFolder.exists()){
clean();
}
}
});
}
private void initModelDescriptionFromFolder() throws FileNotFoundException {
try {
String uri = fmuFolder.getAbsolutePath() + File.separator + FMUResourceUtil.MODEL_DESCRIPTION_FILE_NAME;
Resource modelDescriptionResource = resSet.getResource(URI.createFileURI(uri), true);
if (modelDescriptionResource != null && !modelDescriptionResource.getContents().isEmpty()
&& modelDescriptionResource.getContents().get(0) instanceof DocumentRoot) {
DocumentRoot root = (DocumentRoot) modelDescriptionResource.getContents().get(0);
modelDescription = root.getFmiModelDescription();
Resource resFromZip = resSet.getResource(FMUResourceUtil.MODEL_DESCRIPTION_ZIP_URI, false);
if (resFromZip != null && resFromZip.isLoaded()) {
resFromZip.unload();
}
}
} catch (RuntimeException e) {
throw new FileNotFoundException("Can't find the " + FMUResourceUtil.MODEL_DESCRIPTION_FILE_NAME + " file of the FMU.");
}
}
private void initResourceSet() {
resSet = new ResourceSetImpl();
resSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*",
new FmiResourceFactoryImpl());
resSet.getPackageRegistry().put(null, FmiPackage.eINSTANCE);
}
public void clean(){
if (fmuFolder != null){
try {
deleteFolder(fmuFolder);
} catch (IOException e) {
Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.getDefault().getBundle().getSymbolicName(), "Failed to clean fmu folder " + fmuFolder, e));
}
}
}
public void unzip(String targetFolderPath, boolean erase) throws IOException{
File targetFolder;
boolean isTmp =false;
if (targetFolderPath == null){
targetFolder = Files.createTempDirectory("fmu").toFile();
isTmp = true;
}else {
targetFolder = new File(targetFolderPath);
}
if (targetFolder.isFile()){
throw new IllegalArgumentException("Target path should be a folder");
}
if (fmuFile == null){
throw new IllegalArgumentException("The FMU archive not initialized");
}
fmuFolder = targetFolder;
if (fmuFolder.exists() && !isTmp){
if (erase){
deleteFolder(fmuFolder);
fmuFolder.mkdir();
}else {
throw new IllegalArgumentException("FMU folder exists and erase is set to false");
}
}
try{
URI fileUri = URI.createFileURI(fmuFile.getAbsolutePath());
UnzipUtility.unzip(fileUri, fmuFolder.getAbsolutePath());
} catch (IOException e) {
Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.getDefault().getBundle().getSymbolicName(), "Could not unzip fmu archive" + fmuFile, e));
}
initModelDescriptionFromFolder();
isUnzipped = true;
}
private void deleteFolder(File folder) throws IOException {
Path folderPath = folder.toPath();
Files.walkFileTree(folderPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException
{
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException e)
throws IOException
{
if (e == null) {
Files.delete(dir);
return FileVisitResult.CONTINUE;
} else {
// directory iteration failed
throw e;
}
}
});
}
private void initModelDescriptionFromZip() {
try (ZipFile fmuZipFile = new ZipFile(fmuFile);){
if (fmuZipFile!=null){
ZipEntry modelDescriptionEntry = fmuZipFile.getEntry(FMUResourceUtil.MODEL_DESCRIPTION_FILE_NAME);
try (InputStream modelDescriptionStream = fmuZipFile.getInputStream(modelDescriptionEntry);){
Resource modelDescriptionResource = resSet.createResource(FMUResourceUtil.MODEL_DESCRIPTION_ZIP_URI);
modelDescriptionResource.load(modelDescriptionStream, null) ;
if (!modelDescriptionResource.getContents().isEmpty() && modelDescriptionResource.getContents().get(0) instanceof DocumentRoot){
DocumentRoot root = (DocumentRoot) modelDescriptionResource.getContents().get(0);
modelDescription = root.getFmiModelDescription();
}
} catch (IOException e) {
Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.getDefault().getBundle().getSymbolicName(), "Could not read modelDescription in FMU "+fmuPath, e));
}
}
} catch (IOException e1) {
Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.getDefault().getBundle().getSymbolicName(), "Could not read zipped FMU ", e1));
}
}
public FmiModelDescriptionType getModelDescription(){
return modelDescription;
}
public File getFMUFolder() throws IOException{
if (! isUnzipped){
unzip(null, true);
}
return fmuFolder;
}
public File getCosimulationLibrary() throws FileNotFoundException{
if (!isUnzipped){
try {
unzip(null, true);
} catch (IOException e) {
Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.getDefault().getBundle().getSymbolicName(), "failed to unzip FMU " + fmuName));
return null;
}
}
String dllRelativePath = getCosimulationLibraryRelativePath();
if (dllRelativePath == null){
String message = "Could not get compute the dll relative path in FMU " +fmuName;
Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.getDefault().getBundle().getSymbolicName(),message));
throw new FileNotFoundException(message);
}
File dllFile = new File(fmuFolder + File.separator + dllRelativePath);
if (!dllFile.exists()){
throw new FileNotFoundException("Did not find dll " + dllFile.getAbsolutePath());
}
return dllFile;
}
public String getCosimulationLibraryRelativePath(){
if (modelDescription != null && ! modelDescription.getCoSimulation().isEmpty()){
CoSimulationType cosimElem = modelDescription.getCoSimulation().get(0);
String identifier =cosimElem.getModelIdentifier();
if (identifier!= null){
return FMUResourceUtil.FOLDER_BINARIES+File.separator+FMIOSDetector.getOS()+File.separator + identifier +FMIOSDetector.getDLLFileExtension();
}else {
Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.getDefault().getBundle().getSymbolicName(), "FMU "+ fmuName + " does not contain a cosimulation model identifier"));
}
}else {
Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.getDefault().getBundle().getSymbolicName(), "FMU "+ fmuName + " does not contain a model description with a cosimulation section"));
}
return null;
}
public File getResourceFolder() throws IOException{
File fmuFolderFile = getFMUFolder();
File resourceFile = new File(fmuFolderFile.getAbsolutePath() + File.separator + FMUResourceUtil.FOLDER_RESOURCES);
if (resourceFile.isFile()){
Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.getDefault().getBundle().getSymbolicName(), "FMU "+ fmuName + " resources should be a folder, not a file"));
}
if( !resourceFile.exists()){
resourceFile.mkdir();
}
return resourceFile;
}
}