/*************************************************************************************
* Copyright (c) 2008-2014 Red Hat, Inc. and others.
* 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:
* JBoss by Red Hat - Initial implementation.
************************************************************************************/
package org.jboss.tools.arquillian.core.internal.launcher;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationManager;
import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationsDialog;
import org.eclipse.debug.internal.ui.launchConfigurations.LaunchGroupExtension;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants;
import org.eclipse.jdt.junit.launcher.JUnitLaunchConfigurationDelegate;
import org.eclipse.jdt.ui.ISharedImages;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jdt.ui.text.java.ClasspathFixProcessor.ClasspathFixProposal;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.window.Window;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.NullChange;
import org.eclipse.ltk.core.refactoring.PerformChangeOperation;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.jboss.tools.arquillian.core.ArquillianCoreActivator;
import org.jboss.tools.arquillian.core.internal.ArquillianConstants;
import org.jboss.tools.arquillian.core.internal.util.ArquillianSearchEngine;
import org.jboss.tools.arquillian.core.internal.util.ArquillianUtility;
import org.jboss.tools.common.jdt.debug.RemoteDebugActivator;
/**
*
* @author snjeza
*
*/
public class ArquillianLaunchConfigurationDelegate extends
JUnitLaunchConfigurationDelegate {
private static final String ADD_ARQUILLIAN_SUPPORT = "Add Arquillian Support...";
public static final String ID = ArquillianCoreActivator.PLUGIN_ID + ".launchconfig"; //$NON-NLS-1$
@Override
protected IMember[] evaluateTests(ILaunchConfiguration configuration,
IProgressMonitor monitor) throws CoreException {
IMember[] tests = super.evaluateTests(configuration, monitor);
String testMethodName= configuration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_METHOD_NAME, ""); //$NON-NLS-1$
if (testMethodName.length() > 0) {
return tests;
}
List<IMember> filteredTests = new ArrayList<IMember>();
for (IMember member:tests) {
if (member instanceof IType && ArquillianSearchEngine.isArquillianJUnitTest(member, true, true)) {
filteredTests.add(member);
}
}
return filteredTests.toArray(new IMember[0]);
}
@Override
protected void preLaunchCheck(final ILaunchConfiguration configuration,
ILaunch launch, IProgressMonitor monitor) throws CoreException {
super.preLaunchCheck(configuration, launch, monitor);
final IStatus[] statuses= new IStatus[2];
statuses[0] = ArquillianSearchEngine.validateDeployableContainer(getJavaProject(configuration));
if (!statuses[0].isOK()) {
Display.getDefault().syncExec(new Runnable() {
@Override
public void run() {
try {
statuses[1] = fixArquillianLaunch(configuration, statuses[0]);
} catch (CoreException e) {
ArquillianCoreActivator.log(e);
}
}
});
if (statuses[1].getSeverity() == IStatus.CANCEL) {
monitor.setCanceled(true);
}
return;
}
}
private IStatus fixArquillianLaunch(ILaunchConfiguration configuration, IStatus status) throws CoreException {
ClasspathFixProposal[] fixProposals;
if (status.getCode() == ArquillianSearchEngine.CONTAINER_DEPLOYABLE_CONTAINER_NOT_EXISTS) {
fixProposals = new ClasspathFixProposal[1];
fixProposals[0] = new ArquillianLaunchFixProposal(configuration,
ArquillianConstants.ADD_ARQUILLIAN_SUPPORT_COMMAND,
ArquillianConstants.ADD_ARQUILLIAN_SUPPORT, true, 15);
} else {
fixProposals = new ClasspathFixProposal[2];
fixProposals[0] = new ArquillianLaunchFixProposal(configuration,
ArquillianConstants.ADD_ARQUILLIAN_PROFILES_COMMAND,
ArquillianConstants.ADD_ARQUILLIAN_PROFILES, true, 15);
fixProposals[1] = new ArquillianLaunchFixProposal(configuration,
ArquillianConstants.SELECT_MAVEN_PROFILES_COMMAND,
ArquillianConstants.SELECT_MAVEN_PROFILES, true, 15);
}
LaunchFixSelectionDialog dialog = new LaunchFixSelectionDialog(
ArquillianUtility.getShell(),
configuration,
ArquillianUtility.getJavaProject(configuration),
status.getMessage(), fixProposals);
if (dialog.open() == Window.CANCEL) {
return Status.CANCEL_STATUS;
}
return Status.OK_STATUS;
}
private static class LaunchFixSelectionDialog extends MessageDialog implements SelectionListener, IDoubleClickListener {
static class LaunchFixLabelProvider extends LabelProvider {
@Override
public Image getImage(Object element) {
if (element instanceof ClasspathFixProposal) {
ClasspathFixProposal classpathFixProposal= (ClasspathFixProposal) element;
return classpathFixProposal.getImage();
}
return null;
}
@Override
public String getText(Object element) {
if (element instanceof ClasspathFixProposal) {
ClasspathFixProposal classpathFixProposal= (ClasspathFixProposal) element;
return classpathFixProposal.getDisplayString();
}
return null;
}
}
private final ClasspathFixProposal[] fixProposals;
private final IJavaProject fProject;
private TableViewer fFixSelectionTable;
private Button fNoActionRadio;
private Button fOpenBuildPathRadio;
private Button fOpenLaunchConfiguration;
private Button fPerformFix;
private ArquillianLaunchFixProposal selectedFix;
private IResourceChangeListener resourceChangeListener;
private ILaunchConfiguration fConfiguration;
public LaunchFixSelectionDialog(Shell parent, ILaunchConfiguration configuration, IJavaProject project, String message, ClasspathFixProposal[] fixProposals) {
super(parent, "Arquillian JUnit test", null, message, MessageDialog.QUESTION, new String[] { IDialogConstants.OK_LABEL, IDialogConstants.CANCEL_LABEL }, 0);
fConfiguration = configuration;
fProject= project;
this.fixProposals= fixProposals;
selectedFix= null;
}
@Override
protected boolean isResizable() {
return true;
}
@Override
protected Control createCustomArea(Composite composite) {
fNoActionRadio= new Button(composite, SWT.RADIO);
fNoActionRadio.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
fNoActionRadio.setText("&Not now");
fNoActionRadio.addSelectionListener(this);
fOpenBuildPathRadio= new Button(composite, SWT.RADIO);
fOpenBuildPathRadio.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
fOpenBuildPathRadio.setText("&Open the build path property page");
fOpenBuildPathRadio.addSelectionListener(this);
fOpenLaunchConfiguration= new Button(composite, SWT.RADIO);
fOpenLaunchConfiguration.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
fOpenLaunchConfiguration.setText("Open the &Launch Configuration");
fOpenLaunchConfiguration.addSelectionListener(this);
if (fixProposals.length > 0) {
fPerformFix= new Button(composite, SWT.RADIO);
fPerformFix.setLayoutData(new GridData(SWT.LEAD, SWT.TOP, false, false));
fPerformFix.setText("&Perform the following action:");
fPerformFix.addSelectionListener(this);
fFixSelectionTable= new TableViewer(composite, SWT.SINGLE | SWT.BORDER);
fFixSelectionTable.setContentProvider(new ArrayContentProvider());
fFixSelectionTable.setLabelProvider(new LaunchFixLabelProvider());
fFixSelectionTable.setComparator(new ViewerComparator());
fFixSelectionTable.addDoubleClickListener(this);
fFixSelectionTable.setInput(fixProposals);
fFixSelectionTable.setSelection(new StructuredSelection(fixProposals[0]));
GridData gridData= new GridData(SWT.FILL, SWT.FILL, true, true);
gridData.heightHint= convertHeightInCharsToPixels(4);
gridData.horizontalIndent= convertWidthInCharsToPixels(2);
fFixSelectionTable.getControl().setLayoutData(gridData);
fNoActionRadio.setSelection(false);
fOpenBuildPathRadio.setSelection(false);
fOpenLaunchConfiguration.setSelection(false);
fPerformFix.setSelection(true);
} else {
fNoActionRadio.setSelection(true);
fOpenBuildPathRadio.setSelection(false);
fOpenLaunchConfiguration.setSelection(false);
}
updateEnableStates();
resourceChangeListener = new IResourceChangeListener() {
@Override
public void resourceChanged(IResourceChangeEvent event) {
IStatus status = ArquillianSearchEngine.validateDeployableContainer(fProject);
if (status.isOK()) {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
setReturnCode(OK);
close();
}
});
}
}
};
ResourcesPlugin.getWorkspace().addResourceChangeListener(resourceChangeListener, IResourceChangeEvent.POST_BUILD);
return composite;
}
private void updateEnableStates() {
if (fPerformFix != null) {
fFixSelectionTable.getTable().setEnabled(fPerformFix.getSelection());
}
}
@Override
public boolean close() {
if (resourceChangeListener != null) {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(resourceChangeListener);
resourceChangeListener = null;
}
return super.close();
}
private static final String BUILD_PATH_PAGE_ID= "org.eclipse.jdt.ui.propertyPages.BuildPathsPropertyPage"; //$NON-NLS-1$
private static final String BUILD_PATH_BLOCK= "block_until_buildpath_applied"; //$NON-NLS-1$
@Override
protected void buttonPressed(int buttonId) {
if (buttonId == IDialogConstants.CANCEL_ID) {
super.buttonPressed(buttonId);
return;
}
selectedFix= null;
if (buttonId == 0) {
if (fNoActionRadio.getSelection()) {
super.buttonPressed(buttonId);
} else if (fOpenBuildPathRadio.getSelection()) {
String id= BUILD_PATH_PAGE_ID;
Map<String, Boolean> input= new HashMap<String, Boolean>();
input.put(BUILD_PATH_BLOCK, Boolean.TRUE);
if (PreferencesUtil.createPropertyDialogOn(getShell(), fProject, id, new String[] { id }, input).open() != Window.OK) {
return;
}
} else if (fOpenLaunchConfiguration.getSelection()) {
openLaunchConfiguration(fConfiguration);
setReturnCode(CANCEL);
close();
} else if (fFixSelectionTable != null) {
IStructuredSelection selection= (IStructuredSelection) fFixSelectionTable.getSelection();
Object firstElement= selection.getFirstElement();
if (firstElement instanceof ArquillianLaunchFixProposal) {
selectedFix= (ArquillianLaunchFixProposal) firstElement;
}
}
}
final ArquillianLaunchFixProposal fix = getSelectedClasspathFix();
if (fix != null) {
try {
IProgressMonitor monitor = new NullProgressMonitor();
Change change = fix.createChange(monitor);
new PerformChangeOperation(change).run(monitor);
IStatus status = ArquillianSearchEngine.validateDeployableContainer(fProject);
if (status.isOK()) {
super.okPressed();
}
} catch (OperationCanceledException e) {
cancelPressed();
} catch (Exception e) {
ArquillianCoreActivator.log(e);
}
}
}
public ArquillianLaunchFixProposal getSelectedClasspathFix() {
return selectedFix;
}
public void widgetDefaultSelected(SelectionEvent e) {
updateEnableStates();
}
public void widgetSelected(SelectionEvent e) {
updateEnableStates();
}
public void doubleClick(DoubleClickEvent event) {
okPressed();
}
}
private static class ArquillianLaunchFixProposal extends ClasspathFixProposal {
private int relevance;
private ILaunchConfiguration configuration;
private String actionId;
private boolean select;
private String message;
public ArquillianLaunchFixProposal(ILaunchConfiguration configuration, String actionId, String message,
boolean select, int relevance) {
this.configuration = configuration;
this.relevance= relevance;
this.actionId = actionId;
this.select = select;
this.message = message;
}
@Override
public String getAdditionalProposalInfo() {
return message;
}
@Override
public Change createChange(IProgressMonitor monitor) throws CoreException {
if (monitor == null) {
monitor= new NullProgressMonitor();
}
ArquillianUtility.runAction(configuration, actionId, select);
return new NullChange();
}
@Override
public String getDisplayString() {
return message;
}
@Override
public Image getImage() {
return JavaUI.getSharedImages().getImage(ISharedImages.IMG_OBJS_LIBRARY);
}
@Override
public int getRelevance() {
return relevance;
}
public String getActionId() {
return actionId;
}
}
public static void openLaunchConfiguration(ILaunchConfiguration configuration) {
LaunchConfigurationManager lcManager = DebugUIPlugin.getDefault().getLaunchConfigurationManager();
LaunchGroupExtension group = lcManager.getLaunchGroup(RemoteDebugActivator.LAUNCH_CATEGORY);
LaunchConfigurationsDialog dialog = new LaunchConfigurationsDialog(ArquillianUtility.getShell(), group);
if (configuration != null) {
IStructuredSelection selection = new StructuredSelection(configuration);
dialog.setInitialSelection(selection);
dialog.setOpenMode(LaunchConfigurationsDialog.LAUNCH_CONFIGURATION_DIALOG_OPEN_ON_SELECTION);
} else {
dialog.setOpenMode(LaunchConfigurationsDialog.LAUNCH_CONFIGURATION_DIALOG_OPEN_ON_LAST_LAUNCHED);
}
dialog.open();
}
}