blob: 71ee60cb95052bad79151dee0da9926bf00616a9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006 - 2012 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.designer.languages.common.base;
import java.util.Collections;
import java.util.List;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.papyrus.designer.languages.common.base.file.ICleanUntouched;
import org.eclipse.papyrus.designer.languages.common.extensionpoints.ILangCodegen;
import org.eclipse.papyrus.designer.languages.common.extensionpoints.LanguageCodegen;
import org.eclipse.papyrus.designer.languages.common.profile.Codegen.GeneratorHint;
import org.eclipse.papyrus.designer.languages.common.profile.Codegen.NoCodeGen;
import org.eclipse.papyrus.infra.tools.file.IPFileSystemAccess;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.PackageableElement;
import org.eclipse.uml2.uml.util.UMLUtil;
/**
* Main class of code generator. This is an abstract class that is supposed to be overriden by language specific code generators
*/
abstract public class ModelElementsCreator {
/**
* optional reference to a project (is used in case of handling multiple code generators)
*/
protected IProject project;
protected ILocationStrategy locStrategy;
protected IPFileSystemAccess fileSystemAccess;
protected String generatorLanguage;
/**
*
* Constructor.
*
* @param fileSystemAccess
* a file system access implementation
* @param locStrategy
* a strategy that chooses suitable file names for generated code.
* @param generatorLanguage
* the language to use (used to check, whether the language changes when a generator hint is found)
*/
public ModelElementsCreator(IPFileSystemAccess fileSystemAccess, ILocationStrategy locStrategy, String generatorLanguage) {
this.fileSystemAccess = fileSystemAccess;
this.locStrategy = locStrategy;
this.generatorLanguage = generatorLanguage;
}
/**
* Obtain fileName of file(s) generated for a named element. Delegates to location strategy.
* Caller must eventually add extensions.
*
* @param element
* a named element.
* @return the file name to use
*/
public String getFileName(NamedElement element) {
return locStrategy.getFileName(element);
}
/**
* Creates the file(s) corresponding to a packageable element. This class needs to be
* implemented by language specific model elements
*
* @param classifier
* a classifier for which could should be generated
* @param monitor
* a progress monitor
*/
abstract protected void createPackageableElementFile(PackageableElement classifier, IProgressMonitor monitor);
/**
* Return true, if no code should be generated for a certain element. May be overloaded by
* specific code generators, but they should delegate to this method (super.noCodeGen) in
* case of a non language-specific behavior.
*
* @param element
* @return
*/
protected boolean noCodeGen(Element element) {
return GenUtils.hasStereotype(element, NoCodeGen.class);
}
/**
* Main function for user calls. Creates code for a packageable element. In case of a passed package, the contained elements
* are generated recursively.
*
* @param element
* the element for which code should be generated
* @param monitor
* a progress monitor
*/
public void createPackageableElement(PackageableElement element, IProgressMonitor monitor) {
createPackageableElement(element, monitor, true);
}
/**
* Variant of main function: user may supply explicit container (also used by internal function to avoid
* re-calculating the entry container for each element).
*
* @param element
* An element for which code should be created
* @param monitor
* a progress monitor
* @param recursive
* if true, step into packages
*/
public void createPackageableElement(PackageableElement element, IProgressMonitor monitor, boolean recursive) {
if (noCodeGen(element)) {
return;
}
GeneratorHint hint = UMLUtil.getStereotypeApplication(element, GeneratorHint.class);
if (hint != null && hint.getLanguage() != null) {
String language = hint.getLanguage().getBase_Class().getName();
if ((language != null) && (!language.equals(generatorLanguage))) {
// try to generate code with a new model elements creator for the requested language
ILangCodegen newGenerator = LanguageCodegen.getGenerator(language);
// generate code (use same target project. Determine project automatically, if null)
newGenerator.generateCode(project, element, monitor);
return;
}
}
if (element instanceof Package) {
Package pkg = (Package) element;
if (monitor != null) {
monitor.subTask("generate package " + element.getQualifiedName()); //$NON-NLS-1$
}
createPackageableElementFile(element, monitor);
if (recursive) {
// Continue generation parsing package contents
for (PackageableElement subElement : pkg.getPackagedElements()) {
createPackageableElement(subElement, monitor, recursive);
}
}
} else {
createPackageableElementFile(element, monitor);
}
}
/**
* Remove elements (used for differential code generation)
*
* @param element
* An element for which code should be created
* @param monitor
* a progress monitor
*/
public void removePackageableElement(PackageableElement element, IProgressMonitor monitor) {
String fileName = getFileName(element);
fileSystemAccess.deleteFile(fileName); // need recursion support?
}
/**
* remove files for which no code has been generated. This enables the
* removal of old code e.g. after a suppression or renaming of elements
* in the model.
*
* @param folder
* the folder which should be cleaned
* @param monitor
* a progress monitor
*/
public void cleanUntouched(IFolder folder, IProgressMonitor monitor) {
cleanUntouched(folder, Collections.emptyList(), monitor);
}
/**
* Remove files for which no code has been generated - with the exception of
* some files that should be kept. This enables the
* removal of old code e.g. after a suppression or renaming of elements
* in the model.
*
* @param folder
* the folder which should be cleaned
* @param keepFiles
* a list of filenames correcponding to files that should be kept.
* @param monitor
* a progress monitor
*/
public void cleanUntouched(IFolder folder, List<String> keepFiles, IProgressMonitor monitor) {
if (fileSystemAccess instanceof ICleanUntouched) {
try {
((ICleanUntouched) fileSystemAccess).cleanUntouched(folder, keepFiles, monitor);
} catch (CoreException e) {
throw new RuntimeException(e);
}
}
}
}