Commit 16ff9781 authored by Adam Knapp's avatar Adam Knapp
Browse files

Run config generation feature for Titan Java project



Detailed description of operation is available in the documentation

Change-Id: Iee30ab52b33a81dee18653864b13e840dc1aa82b
Signed-off-by: default avatarAdam Knapp <adam.knapp@sigmatechnology.se>
parent 3a68fa98
...@@ -24,6 +24,7 @@ import org.eclipse.titan.common.utils.Joiner; ...@@ -24,6 +24,7 @@ import org.eclipse.titan.common.utils.Joiner;
* location, to what the result should be relative to. * location, to what the result should be relative to.
* *
* @author Kristof Szabados * @author Kristof Szabados
* @author Adam Knapp
*/ */
public final class PathUtil { public final class PathUtil {
...@@ -247,4 +248,36 @@ public final class PathUtil { ...@@ -247,4 +248,36 @@ public final class PathUtil {
return calculateRelativePath(Arrays.asList(basePath.segments()), Arrays.asList(whatPath.segments())); return calculateRelativePath(Arrays.asList(basePath.segments()), Arrays.asList(whatPath.segments()));
} }
/**
* Validates the file path string
*
* @param path Path to validate
* @return Whether the path is valid or not
* @see java.io.File#getCanonicalPath
*/
public static boolean isValidFilePath(String path) {
File f = new File(path);
try {
f.getCanonicalPath();
return true;
}
catch (IOException e) {
return false;
}
}
/**
* Validates the file name string
*
* @param filename File name to validate
* @return Whether the name is valid or not
* @see org.eclipse.titan.common.path.PathUtil#isValidFilePath
*/
public static boolean isValidFileName(String filename) {
if (filename.contains("/") || filename.contains("\\")) {
return false;
}
return isValidFilePath(filename);
}
} }
...@@ -84,6 +84,16 @@ ...@@ -84,6 +84,16 @@
id="org.eclipse.titan.designer.actions.FindDefinitionAction" id="org.eclipse.titan.designer.actions.FindDefinitionAction"
name="Find definition"> name="Find definition">
</command> </command>
<command
defaultHandler="org.eclipse.titan.designer.actions.runconfiggenerator.GenerateRunConfigSingle"
id="org.eclipse.titan.designer.actions.GenerateRunConfigSingle"
name="Generate single run configuration for Eclipse Titan">
</command>
<command
defaultHandler="org.eclipse.titan.designer.actions.runconfiggenerator.GenerateRunConfigParallel"
id="org.eclipse.titan.designer.actions.GenerateRunConfigParallel"
name="Generate parallel run configuration for Eclipse Titan">
</command>
</extension> </extension>
<extension <extension
name="Designer Editor Commands" name="Designer Editor Commands"
...@@ -410,7 +420,7 @@ ...@@ -410,7 +420,7 @@
</with> </with>
</visibleWhen> </visibleWhen>
</command> </command>
<separator name="org.eclipse.titan.designer.separator1" <separator name="separator1"
visible="true"> visible="true">
</separator> </separator>
<command <command
...@@ -475,6 +485,48 @@ ...@@ -475,6 +485,48 @@
</with> </with>
</visibleWhen> </visibleWhen>
</command> </command>
<separator name="separator2"
visible="true">
</separator>
<command
commandId="org.eclipse.titan.designer.actions.GenerateRunConfigSingle"
label="Generate single run configuration for Eclipse Titan">
<visibleWhen checkEnabled="false">
<with variable="selection">
<count value="1">
</count>
<iterate operator="and">
<instanceof value="org.eclipse.core.resources.IFile">
</instanceof>
<test property="org.eclipse.core.resources.projectNature"
value="org.eclipse.titan.designer.core.TITANNature" />
<test property="org.eclipse.core.resources.extension" value="cfg" />
<test property="org.eclipse.titan.designer.properties.TitanBuilder.isTitanJavaBuilder" />
</iterate>
</with>
</visibleWhen>
</command>
<command
commandId="org.eclipse.titan.designer.actions.GenerateRunConfigParallel"
label="Generate parallel run configuration for Eclipse Titan">
<visibleWhen checkEnabled="false">
<with variable="selection">
<count value="1">
</count>
<iterate operator="and">
<instanceof value="org.eclipse.core.resources.IFile">
</instanceof>
<test property="org.eclipse.core.resources.projectNature"
value="org.eclipse.titan.designer.core.TITANNature" />
<test property="org.eclipse.core.resources.extension" value="cfg" />
<test property="org.eclipse.titan.designer.properties.TitanBuilder.isTitanJavaBuilder" />
</iterate>
</with>
</visibleWhen>
</command>
<separator name="separator3"
visible="true">
</separator>
</menu> </menu>
</menuContribution> </menuContribution>
...@@ -581,8 +633,6 @@ ...@@ -581,8 +633,6 @@
label="Rename refactoring"> label="Rename refactoring">
</command> </command>
</menuContribution> </menuContribution>
</extension> </extension>
......
/******************************************************************************
* Copyright (c) 2000-2021 Ericsson Telecom AB
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
******************************************************************************/
package org.eclipse.titan.designer.actions.runconfiggenerator;
import java.text.MessageFormat;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.titan.common.path.PathUtil;
public class FileNameDialog extends TitleAreaDialog {
private static String SHELL_TEXT = "Save run configuration for Eclipse Titan";
private static String TITLE_TEXT = "You can save the run configration for {0} mode";
private static String HELP_TEXT = "Give name for the run configuration";
private static String ERROR_TEXT = "Invalid file name";
private static String LABEL_TEXT = "File name: ";
private static String OVERWRITE_TEXT = "Overwrite if exists?";
private Text fileNameText;
private Button overwriteButton;
private String selectedFileName = "";
private String defaultFileName = "";
private boolean isOverwite = false;
/**
* False -> Single mode
* True -> Parallel mode
*/
private boolean mode = false;
public FileNameDialog(Shell parent) {
super(parent);
setHelpAvailable(false);
}
@Override
/** {@inheritDoc} */
public void create() {
super.create();
setTitle(MessageFormat.format(TITLE_TEXT, mode ? "parallel" : "single"));
setMessage(HELP_TEXT, IMessageProvider.INFORMATION);
}
@Override
/** {@inheritDoc} */
protected Control createDialogArea(Composite parent) {
Composite area = (Composite) super.createDialogArea(parent);
Composite container = new Composite(area, SWT.NONE);
container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
GridLayout layout = new GridLayout(1, false);
container.setLayout(layout);
createFileNameText(container);
createOverwriteCheckBox(container);
return area;
}
@Override
/** {@inheritDoc} */
protected Point getInitialSize() {
return new Point(500, 300);
}
@Override
/** {@inheritDoc} */
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
newShell.setText(SHELL_TEXT);
}
private void createFileNameText(Composite container) {
Label fileNameLabel = new Label(container, SWT.NONE);
fileNameLabel.setText(LABEL_TEXT);
GridData dataFileName = new GridData();
dataFileName.grabExcessHorizontalSpace = true;
dataFileName.horizontalAlignment = GridData.FILL;
fileNameText = new Text(container, SWT.BORDER);
fileNameText.setLayoutData(dataFileName);
fileNameText.setText(defaultFileName);
fileNameText.addListener(SWT.Modify, new Listener() {
public void handleEvent(Event e) {
String string = fileNameText.getText();
Button okButton = getButton(IDialogConstants.OK_ID);
if (!PathUtil.isValidFileName(string)) {
setMessage(ERROR_TEXT, IMessageProvider.ERROR);
if (okButton != null)
okButton.setEnabled(false);
} else {
setMessage(HELP_TEXT, IMessageProvider.INFORMATION);
if (okButton != null)
okButton.setEnabled(true);
}
}
});
}
private void createOverwriteCheckBox(Composite container) {
overwriteButton = new Button(container, SWT.CHECK);
overwriteButton.setText(OVERWRITE_TEXT);
}
@Override
/** {@inheritDoc} */
protected boolean isResizable() {
return true;
}
/**
* Sets the default file name to show
*
* @param defaultFileName default file name
*/
public void setDefaultFileName(String defaultFileName) {
this.defaultFileName = defaultFileName;
}
/**
* Returns the default file name
*
* @return default file name
*/
public String getDefaultFileName() {
return defaultFileName;
}
private void saveInput() {
selectedFileName = fileNameText.getText();
isOverwite = overwriteButton.getSelection();
}
@Override
/** {@inheritDoc} */
protected void okPressed() {
saveInput();
super.okPressed();
}
/**
* Returns the filled file name
*
* @return the filled file name
*/
public String getFirstName() {
return selectedFileName;
}
/**
* Returns whether the user wants to overwrite
* the existing run configuration or not
*
* @return overwrite or not
*/
public boolean getOverwrite() {
return isOverwite;
}
/**
* Returns the mode of the run configuration.
* <li> False -> Single mode
* <li> True -> Parallel mode
*
* @return the mode
*/
public boolean getMode() {
return mode;
}
/**
* Sets the mode of the run configuration.
* <li> False -> Single mode
* <li> True -> Parallel mode
*
* @param mode the mode to set
*/
public void setMode(boolean mode) {
this.mode = mode;
}
}
package org.eclipse.titan.designer.actions.runconfiggenerator;
import static org.eclipse.titan.common.utils.StringUtils.isNullOrEmpty;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.titan.common.logging.ErrorReporter;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.handlers.HandlerUtil;
public abstract class GenerateRunConfigBase extends AbstractHandler implements IObjectActionDelegate {
/**
* Template for single mode run configuration as Java application.
* To be filled:
* <ol>
* <li>Project name</li>
* <li>Titan config file name</li>
* </ol>
*/
public static final String SINGLE_RUNCONFIG_TEMPLATE =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
+ "<launchConfiguration type=\"org.eclipse.jdt.launching.localJavaApplication\">\n"
+ " <listAttribute key=\"org.eclipse.debug.core.MAPPED_RESOURCE_PATHS\">\n"
+ " <listEntry value=\"/{0}/java_src/org/eclipse/titan/{0}/generated/Single_main.java\"/>\n"
+ " </listAttribute>\n"
+ " <listAttribute key=\"org.eclipse.debug.core.MAPPED_RESOURCE_TYPES\">\n"
+ " <listEntry value=\"1\"/>\n"
+ " </listAttribute>\n"
+ " <listAttribute key=\"org.eclipse.debug.ui.favoriteGroups\">\n"
+ " <listEntry value=\"org.eclipse.debug.ui.launchGroup.run\"/>\n"
+ " </listAttribute>\n"
+ " <booleanAttribute key=\"org.eclipse.jdt.launching.ATTR_ATTR_USE_ARGFILE\" value=\"false\"/>\n"
+ " <booleanAttribute key=\"org.eclipse.jdt.launching.ATTR_SHOW_CODEDETAILS_IN_EXCEPTION_MESSAGES\" value=\"true\"/>\n"
+ " <booleanAttribute key=\"org.eclipse.jdt.launching.ATTR_USE_CLASSPATH_ONLY_JAR\" value=\"false\"/>\n"
+ " <booleanAttribute key=\"org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD\" value=\"true\"/>\n"
+ " <stringAttribute key=\"org.eclipse.jdt.launching.MAIN_TYPE\" value=\"org.eclipse.titan.{0}.generated.Single_main\"/>\n"
+ " <stringAttribute key=\"org.eclipse.jdt.launching.MODULE_NAME\" value=\"{0}\"/>\n"
+ " <stringAttribute key=\"org.eclipse.jdt.launching.PROGRAM_ARGUMENTS\" value=\"{1}\"/>\n"
+ " <stringAttribute key=\"org.eclipse.jdt.launching.PROJECT_ATTR\" value=\"{0}\"/>\n"
+ "</launchConfiguration>\r\n";
/**
* Template for <b>HC</b> (parallel mode run configuration as Java application).
* To be filled:
* <ol>
* <li>Project name</li>
* <li>Host from Titan config file</li>
* <li>Port from Titan config file</li>
* </ol>
*/
public static final String PARALLEL_RUNCONFIG_TEMPLATE =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
+ "<launchConfiguration type=\"org.eclipse.jdt.launching.localJavaApplication\">\n"
+ " <listAttribute key=\"org.eclipse.debug.core.MAPPED_RESOURCE_PATHS\">\n"
+ " <listEntry value=\"/{0}/java_src/org/eclipse/titan/{0}/generated/Parallel_main.java\"/>\n"
+ " </listAttribute>\n"
+ " <listAttribute key=\"org.eclipse.debug.core.MAPPED_RESOURCE_TYPES\">\n"
+ " <listEntry value=\"1\"/>\n"
+ " </listAttribute>\n"
+ " <booleanAttribute key=\"org.eclipse.jdt.launching.ATTR_ATTR_USE_ARGFILE\" value=\"false\"/>\n"
+ " <booleanAttribute key=\"org.eclipse.jdt.launching.ATTR_SHOW_CODEDETAILS_IN_EXCEPTION_MESSAGES\" value=\"true\"/>\n"
+ " <booleanAttribute key=\"org.eclipse.jdt.launching.ATTR_USE_CLASSPATH_ONLY_JAR\" value=\"false\"/>\n"
+ " <booleanAttribute key=\"org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD\" value=\"true\"/>\n"
+ " <stringAttribute key=\"org.eclipse.jdt.launching.MAIN_TYPE\" value=\"org.eclipse.titan.{0}.generated.Parallel_main\"/>\n"
+ " <stringAttribute key=\"org.eclipse.jdt.launching.MODULE_NAME\" value=\"{0}\"/>\n"
+ " <stringAttribute key=\"org.eclipse.jdt.launching.PROGRAM_ARGUMENTS\" value=\"{1} {2,number,#}\"/>\n"
+ " <stringAttribute key=\"org.eclipse.jdt.launching.PROJECT_ATTR\" value=\"{0}\"/>\n"
+ "</launchConfiguration>\n";
/**
* Template for <b>MC</b> (parallel mode run configuration as TITAN Java Native launcher).
* To be filled:
* <ol>
* <li>Project name</li>
* <li>Titan config file name</li>
* </ol>
*/
public static final String TITAN_RUNCONFIG_TEMPLATE =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n"
+ "<launchConfiguration type=\"org.eclipse.titan.executor.executors.java_mctr.LaunchConfigurationDelegate\">\r\n"
+ " <stringAttribute key=\"bad_container_name\" value=\"\\consume\"/>\r\n"
+ " <stringAttribute key=\"lastTimeSelection\" value=\"configuration file\"/>\r\n"
+ " <intAttribute key=\"lastTimeSelectionTime\" value=\"1\"/>\r\n"
+ " <intAttribute key=\"lastTimeSelectionType\" value=\"4\"/>\r\n"
+ " <listAttribute key=\"org.eclipse.debug.core.MAPPED_RESOURCE_PATHS\">\r\n"
+ " <listEntry value=\"/{0}\"/>\r\n"
+ " </listAttribute>\r\n"
+ " <listAttribute key=\"org.eclipse.debug.core.MAPPED_RESOURCE_TYPES\">\r\n"
+ " <listEntry value=\"4\"/>\r\n"
+ " </listAttribute>\r\n"
+ " <intAttribute key=\"org.eclipse.titan.executor.MainControllerStateRefreshTimeout\" value=\"5\"/>\r\n"
+ " <stringAttribute key=\"org.eclipse.titan.executor.configurationFilePath\" value=\"{1}\"/>\r\n"
+ " <booleanAttribute key=\"org.eclipse.titan.executor.consoleLogging\" value=\"true\"/>\r\n"
+ " <stringAttribute key=\"org.eclipse.titan.executor.executableFilePath\" value=\"\"/>\r\n"
+ " <booleanAttribute key=\"org.eclipse.titan.executor.executeConfigurationFileOnLaunch\" value=\"true\"/>\r\n"
+ " <booleanAttribute key=\"org.eclipse.titan.executor.keepTemporarilyGeneratedConfigurationFiles\" value=\"true\"/>\r\n"
+ " <intAttribute key=\"org.eclipse.titan.executor.maximumNotificationLineCount\" value=\"1000\"/>\r\n"
+ " <stringAttribute key=\"org.eclipse.titan.executor.projectName\" value=\"{0}\"/>\r\n"
+ " <booleanAttribute key=\"org.eclipse.titan.executor.severityLevelExtraction\" value=\"true\"/>\r\n"
+ " <booleanAttribute key=\"org.eclipse.titan.executor.testcaseRefreshOnStart\" value=\"true\"/>\r\n"
+ " <booleanAttribute key=\"org.eclipse.titan.executor.verdictExtraction\" value=\"true\"/>\r\n"
+ " <stringAttribute key=\"org.eclipse.titan.executor.workingdirectoryPath\" value=\"\"/>\r\n"
+ "</launchConfiguration>\r\n";
/**
* Template for automatic start of MC and HC as Launch Group.
* To be filled:
* <ol>
* <li>Run configuration of MC</li>
* <li>Run configuration of HC</li>
* </ol>
*/
public static final String LAUNCH_GROUP_CONFIG_TEMPLATE =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n"
+ "<launchConfiguration type=\"org.eclipse.debug.core.groups.GroupLaunchConfigurationType\">\r\n"
+ " <stringAttribute key=\"org.eclipse.debug.core.launchGroup.0.action\" value=\"NONE\"/>\r\n"
+ " <booleanAttribute key=\"org.eclipse.debug.core.launchGroup.0.adoptIfRunning\" value=\"false\"/>\r\n"
+ " <booleanAttribute key=\"org.eclipse.debug.core.launchGroup.0.enabled\" value=\"true\"/>\r\n"
+ " <stringAttribute key=\"org.eclipse.debug.core.launchGroup.0.mode\" value=\"inherit\"/>\r\n"
+ " <stringAttribute key=\"org.eclipse.debug.core.launchGroup.0.name\" value=\"{0}\"/>\r\n"
+ " <stringAttribute key=\"org.eclipse.debug.core.launchGroup.1.action\" value=\"OUTPUT_REGEXP\"/>\r\n"
+ " <stringAttribute key=\"org.eclipse.debug.core.launchGroup.1.actionParam\" value=\"Listening on IP address\"/>"
+ " <booleanAttribute key=\"org.eclipse.debug.core.launchGroup.1.adoptIfRunning\" value=\"false\"/>\r\n"
+ " <booleanAttribute key=\"org.eclipse.debug.core.launchGroup.1.enabled\" value=\"true\"/>\r\n"
+ " <stringAttribute key=\"org.eclipse.debug.core.launchGroup.1.mode\" value=\"inherit\"/>\r\n"
+ " <stringAttribute key=\"org.eclipse.debug.core.launchGroup.1.name\" value=\"{1}\"/>\r\n"
+ " <listAttribute key=\"org.eclipse.debug.ui.favoriteGroups\">\r\n"
+ " <listEntry value=\"org.eclipse.debug.ui.launchGroup.run\"/>\r\n"
+ " </listAttribute>\r\n"
+ "</launchConfiguration>";
/**
* Folder where the run configurations are stored (inside the project)
*/
public static final String RUN_CONFIG_FOLDER = "launch";
private ISelection selection;
/**
* Invokes the abstract run configuration generation method
*/
private void invokeGeneration() {
final IStructuredSelection structSelection = (IStructuredSelection) selection;
for (final Object selected : structSelection.toList()) {
if (selected instanceof IFile) {
final IFile tempFile = (IFile) selected;
try {
generateRunConfig(tempFile);
} catch (CoreException e) {
ErrorReporter.logExceptionStackTrace(e);
}
}
}
}
/**
* Generates the run configuration file for Eclipse.
* It simply fills the necessary parameters in the template launch config.
*
* @param file The selected Titan configuration file
* @throws CoreException
*/
abstract protected void generateRunConfig(final IFile file) throws CoreException;
@Override
/** {@inheritDoc} */
public Object execute(ExecutionEvent event) throws ExecutionException {
selection = HandlerUtil.getActiveWorkbenchWindow(event).getActivePage().getSelection();
if (!(selection instanceof IStructuredSelection)) {
return null;
}
invokeGeneration();
return null;
}
@Override
/** {@inheritDoc} */
public void run(IAction action) {
if (!(selection instanceof IStructuredSelection)) {
return;
}
invokeGeneration();
}
@Override
/** {@inheritDoc} */
public void selectionChanged(IAction action, ISelection selection) {
this.selection = selection;
}
@Override
/** {@inheritDoc} */
public void setActivePart(IAction action, IWorkbenchPart targetPart) {
//Do nothing
}
/**
* Checks the file name, project name and project location
* properties of the selected file.
*
* @param file The selected file to checks
* @return Whether the properties of the file is okay or not
* @throws CoreException
*/
public boolean validateFile(final IFile file) throws CoreException {
final String configFileName = file.getLocation().toOSString();
if (isNullOrEmpty(configFileName)) {
ErrorReporter.logError("Error during processing the Titan configuration file");
return false;
}
final String projectName = file.getProject().getName();