/*******************************************************************************
* Copyright (c) 2014 BREDEX GmbH.
* 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:
* BREDEX GmbH - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.jubula.client.api.converter.ui.handlers;
import static org.eclipse.jubula.client.api.converter.utils.Utils.EXEC_PATH;
import static org.eclipse.jubula.client.api.converter.utils.Utils.SPEC_PATH;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.window.Window;
import org.eclipse.jubula.client.api.converter.CTDSGenerator;
import org.eclipse.jubula.client.api.converter.CTDSInfo;
import org.eclipse.jubula.client.api.converter.NodeGenerator;
import org.eclipse.jubula.client.api.converter.NodeInfo;
import org.eclipse.jubula.client.api.converter.exceptions.InvalidNodeNameException;
import org.eclipse.jubula.client.api.converter.exceptions.MinorConversionException;
import org.eclipse.jubula.client.api.converter.exceptions.StopConversionException;
import org.eclipse.jubula.client.api.converter.ui.i18n.Messages;
import org.eclipse.jubula.client.api.converter.utils.Utils;
import org.eclipse.jubula.client.core.errorhandling.ErrorMessagePresenter;
import org.eclipse.jubula.client.core.model.IAUTMainPO;
import org.eclipse.jubula.client.core.model.ICategoryPO;
import org.eclipse.jubula.client.core.model.INodePO;
import org.eclipse.jubula.client.core.model.IProjectPO;
import org.eclipse.jubula.client.core.model.IReusedProjectPO;
import org.eclipse.jubula.client.core.persistence.GeneralStorage;
import org.eclipse.jubula.client.core.persistence.IExecPersistable;
import org.eclipse.jubula.client.core.persistence.ISpecPersistable;
import org.eclipse.jubula.client.core.persistence.ProjectPM;
import org.eclipse.jubula.client.ui.handlers.AbstractHandler;
import org.eclipse.jubula.client.ui.rcp.Plugin;
import org.eclipse.jubula.client.ui.utils.ErrorHandlingUtil;
import org.eclipse.jubula.tools.internal.constants.CommandConstants;
import org.eclipse.jubula.tools.internal.constants.StringConstants;
import org.eclipse.jubula.tools.internal.exception.JBException;
import org.eclipse.jubula.tools.internal.messagehandling.MessageIDs;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author BREDEX GmbH
* @created 24.10.2014
*/
public class ConvertProjectHandler extends AbstractHandler {
/** the logger */
private static final Logger LOG = LoggerFactory
.getLogger(ConvertProjectHandler.class);
/** target path of conversion */
private static String genPath;
/** target package name space */
private static String genPackage;
/**
* {@inheritDoc}
*/
public Object executeImpl(ExecutionEvent event) {
DirectoryDialog directoryDialog = createDirectoryDialog();
genPath = directoryDialog.open();
if (genPath != null) {
org.eclipse.jubula.client.ui.rcp.utils.Utils.storeLastDirPath(
directoryDialog.getFilterPath());
File directory = new File(genPath);
if (directory.list().length == 0) {
InputDialog inputDialog = new InputDialog(getActiveShell(),
Messages.InputDialogName, Messages.InputDialogMessage,
StringConstants.EMPTY, new PackageNameValidator());
if (inputDialog.open() == Window.OK) {
genPackage = inputDialog.getValue();
IWorkbench workbench = PlatformUI.getWorkbench();
try {
workbench.getProgressService().run(true, true,
new ConvertProjectOperation());
} catch (InvocationTargetException
| InterruptedException e) {
LOG.error(Messages.ErrorWhileConverting, e);
}
}
} else {
ErrorHandlingUtil.createMessageDialog(
MessageIDs.E_NON_EMPTY_DIRECTORY);
}
}
return null;
}
/**
* @return a directory dialog
*/
private DirectoryDialog createDirectoryDialog() {
DirectoryDialog directoryDialog =
new DirectoryDialog(getActiveShell(), SWT.SAVE);
String filterPath =
org.eclipse.jubula.client.ui.rcp.utils.Utils.getLastDirPath();
directoryDialog.setFilterPath(filterPath);
return directoryDialog;
}
/**
* @created 24.10.2014
*/
private static class ConvertProjectOperation implements
IRunnableWithProgress {
/** the project */
private static IProgressMonitor progressMonitor;
/** the default toolkit */
private static String defaultToolkit;
/** maps a UUID from a test case/suite/job to the name of its
* corresponding node info for generation */
private static Map<String, NodeInfo> uuidToNodeInfoMap;
/** set of projects to convert */
private static Set<IProjectPO> projects;
/** counting absolute work units */
private static int workUnits;
/** {@inheritDoc} */
public void run(IProgressMonitor monitor) {
progressMonitor = monitor;
IProjectPO project = GeneralStorage.getInstance().getProject();
progressMonitor.setTaskName(
Messages.PreparingConvertProjectTaskName);
String basePath = genPath + StringConstants.SLASH
+ genPackage.replace(StringConstants.DOT,
StringConstants.SLASH);
uuidToNodeInfoMap = new HashMap<String, NodeInfo>();
NodeInfo.setUuidToNodeInfoMap(uuidToNodeInfoMap);
projects = new HashSet<IProjectPO>();
workUnits = 0;
if (project != null) {
defaultToolkit = determineDefaultToolkit(project);
addProjectsToConvert(project);
try {
for (IProjectPO p : projects) {
determineClassNamesForProject(p, basePath);
}
progressMonitor.beginTask(
Messages.PreparingConvertProjectTaskName,
workUnits);
for (IProjectPO p : projects) {
progressMonitor.setTaskName(NLS.bind(
Messages.ConvertProjectTaskName, p.getName()));
handleProject(p, basePath);
}
} catch (StopConversionException e) {
progressMonitor.setCanceled(true);
if (!e.wasManuallyTriggered()) {
ErrorHandlingUtil.createMessageDialog(
new JBException(e.getMessage(), e,
MessageIDs.E_CONVERSION_ABORTED_ERROR));
}
return;
}
}
progressMonitor.done();
}
/**
* Adds a project and its reused projects to the set of projects to convert
* @param project the project
*/
private void addProjectsToConvert(IProjectPO project) {
projects.add(project);
Iterator iterator = project.getUsedProjects().iterator();
while (iterator.hasNext()) {
IReusedProjectPO reusedProject =
(IReusedProjectPO) iterator.next();
IProjectPO usedProject;
try {
usedProject = ProjectPM
.loadReusedProjectInMasterSession(reusedProject);
addProjectsToConvert(usedProject);
} catch (JBException e) {
ErrorHandlingUtil.createMessageDialog(
new JBException(e.getMessage(), e,
MessageIDs.E_LOAD_PROJECT));
}
}
}
/**
* Maps for all nodes from a project their UUIDs to the name
* of its corresponding class to generate
* @param project the project
* @param basePath the base path
* @throws StopConversionException
*/
private void determineClassNamesForProject(IProjectPO project,
String basePath) throws StopConversionException {
String projectName = StringConstants.EMPTY;
try {
projectName = Utils.translateToPackageName(project);
} catch (InvalidNodeNameException e) {
displayErrorForInvalidName(project);
throw new StopConversionException();
}
String projectPath = basePath + StringConstants.SLASH + projectName;
for (INodePO node : project.getExecObjCont().getExecObjList()) {
if (progressMonitor.isCanceled()) {
throw new StopConversionException();
}
String path = projectPath + StringConstants.SLASH + EXEC_PATH;
determineClassNamesForNode(node, path);
}
for (INodePO node : project.getSpecObjCont().getSpecObjList()) {
if (progressMonitor.isCanceled()) {
throw new StopConversionException();
}
String path = projectPath + StringConstants.SLASH + SPEC_PATH;
determineClassNamesForNode(node, path);
}
}
/**
* Maps a node's UUID to the name of its corresponding class to generate
* @param node the node
* @param basePath the base path
* @throws StopConversionException
*/
private void determineClassNamesForNode(INodePO node, String basePath)
throws StopConversionException {
workUnits++;
if (node instanceof ICategoryPO) {
ICategoryPO category = (ICategoryPO) node;
String path = StringConstants.EMPTY;
try {
path = basePath + StringConstants.SLASH
+ Utils.translateToPackageName(category);
} catch (InvalidNodeNameException e) {
displayErrorForInvalidName(category);
throw new StopConversionException();
}
for (NodeInfo nodeInfo : uuidToNodeInfoMap.values()) {
if (nodeInfo.getFqFileName().equals(path)) {
displayErrorForDuplicate(node);
throw new StopConversionException();
}
}
NodeInfo nodeInfo = new NodeInfo(path, node,
genPackage, defaultToolkit);
uuidToNodeInfoMap.put(node.getGuid(), nodeInfo);
for (INodePO child : node.getUnmodifiableNodeList()) {
determineClassNamesForNode(child, path);
}
} else {
String className = StringConstants.EMPTY;
try {
className = Utils.determineClassName(node);
} catch (InvalidNodeNameException e) {
displayErrorForInvalidName(node);
throw new StopConversionException();
}
String fileName = basePath + StringConstants.SLASH
+ className + ".java"; //$NON-NLS-1$
for (NodeInfo nodeInfo : uuidToNodeInfoMap.values()) {
if (nodeInfo.getFqFileName().equals(fileName)) {
Plugin.getDefault().writeErrorLineToConsole(
"Duplicate filename error:" + fileName, true); //$NON-NLS-1$
}
}
NodeInfo nodeInfo = new NodeInfo(fileName, node,
genPackage, defaultToolkit);
uuidToNodeInfoMap.put(node.getGuid(), nodeInfo);
}
}
/**
* Returns the default toolkit for a project
* by inspecting its first AUT
* @param project the project
* @return the name of the default toolkit
*/
private String determineDefaultToolkit(IProjectPO project) {
String toolkit = null;
IAUTMainPO firstAUT = null;
try {
firstAUT = project.getAutCont()
.getAutMainList().iterator().next();
} catch (NoSuchElementException e) {
ErrorMessagePresenter.getPresenter().showErrorMessage(
new JBException(
Messages.NoAutInProject,
MessageIDs.E_NO_AUT_IN_PROJECT),
null, null);
progressMonitor.setCanceled(true);
}
if (firstAUT != null) {
toolkit = firstAUT.getToolkit();
}
if (toolkit.equals(CommandConstants.RCP_TOOLKIT)) {
toolkit = CommandConstants.SWT_TOOLKIT;
}
return toolkit;
}
/**
* Traverses a project and creates files and directories for its content.
* @param project the project
* @param basePath the base path
* @throws StopConversionException
*/
private void handleProject(IProjectPO project, String basePath)
throws StopConversionException {
createCentralTestDataClass(project, basePath);
for (IExecPersistable node : project.getExecObjCont()
.getExecObjList()) {
handleNode(node);
}
for (ISpecPersistable node : project.getSpecObjCont()
.getSpecObjList()) {
handleNode(node);
}
}
/**
* Handles the conversion for a node.
* @param node the test case
* @throws StopConversionException
*/
private void handleNode(INodePO node) throws StopConversionException {
if (progressMonitor.isCanceled()) {
throw new StopConversionException(true);
}
progressMonitor.worked(1);
NodeInfo info = uuidToNodeInfoMap.get(node.getGuid());
File file = new File(info.getFqFileName());
if (node instanceof ICategoryPO) {
file.mkdirs();
for (INodePO child : node.getUnmodifiableNodeList()) {
handleNode(child);
}
} else {
try {
file.getParentFile().mkdirs();
file.createNewFile();
NodeGenerator gen = new NodeGenerator();
try {
String content = gen.generate(info);
writeContentToFile(file, content);
} catch (MinorConversionException e) {
Plugin.getDefault().writeLineToConsole(
NLS.bind(Messages.InvalidNode,
new String[] { node.getName(),
e.getMessage() }),
true);
file.delete();
}
} catch (IOException e) {
ErrorHandlingUtil.createMessageDialog(
new JBException(e.getMessage(), e,
MessageIDs.E_FILE_NO_PERMISSION));
throw new StopConversionException();
}
}
}
/**
* Writes a string into a given file.
* @param file the file
* @param content the content
*/
private void writeContentToFile(File file, String content)
throws IOException {
FileOutputStream fop = new FileOutputStream(file);
byte[] contentInBytes = content.getBytes();
IOUtils.write(contentInBytes, fop);
}
/**
* Displays an error message in the case that a node occurs multiple times
* @param node the duplicate node
*/
private void displayErrorForDuplicate(INodePO node) {
String fqNodeName = Utils.getFullyQualifiedName(node);
ErrorMessagePresenter.getPresenter().showErrorMessage(
new JBException(
NLS.bind(Messages.DuplicateNode,
new String[] {fqNodeName}),
MessageIDs.E_DUPLICATE_NODE),
new String [] {fqNodeName},
null);
progressMonitor.setCanceled(true);
}
/**
* Displays an error for the case of an invalid node name
* @param node the node
*/
private void displayErrorForInvalidName(INodePO node) {
String fqNodeName = Utils.getFullyQualifiedName(node);
ErrorMessagePresenter.getPresenter().showErrorMessage(
new JBException(
NLS.bind(Messages.InvalidNodeName,
new String[] {fqNodeName}),
MessageIDs.E_INVALID_NODE_NAME),
new String [] {fqNodeName},
null);
progressMonitor.setCanceled(true);
}
/**
* Creates a central test data file for a project
* @param project the project
* @param basePath the base path
*/
private void createCentralTestDataClass(IProjectPO project,
String basePath) {
String projectName = StringConstants.EMPTY;
try {
projectName = Utils.translateToPackageName(project);
} catch (InvalidNodeNameException e) {
displayErrorForInvalidName(project);
}
String className = "CTDS.java"; //$NON-NLS-1$
String projectPath = basePath + StringConstants.SLASH + projectName;
File projectDir = new File(projectPath);
projectDir.mkdirs();
String fileName = projectPath + StringConstants.SLASH + className;
File file = new File(fileName);
try {
file.createNewFile();
CTDSGenerator gen = new CTDSGenerator();
CTDSInfo info = new CTDSInfo(className,
project, genPackage);
String content = gen.generate(info);
writeContentToFile(file, content);
} catch (IOException e) {
ErrorHandlingUtil.createMessageDialog(
new JBException(e.getMessage(), e,
MessageIDs.E_FILE_NO_PERMISSION));
}
}
}
/**
* @created 27.10.2014
*/
private static class PackageNameValidator implements IInputValidator {
/** {@inheritDoc} */
public String isValid(String newText) {
if (newText.isEmpty()) {
return Messages.NoPackageNameSpecified;
}
Pattern p = Pattern.compile(
"^[a-zA-Z_][\\w]*(\\.[a-zA-Z_][\\w]*)*$"); //$NON-NLS-1$
if (!p.matcher(newText).matches()) {
return Messages.InvalidPackageName;
}
return null;
}
}
}