blob: 840f77bd92d45f8d631f61da3206553cc029ac33 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2021 SAP AG, IBM Corporation and others.
* 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:
* SAP AG - initial API and implementation
* IBM Corporation - refactor for new/import wizard
* IBM Corporation/Andrew Johnson - report changed dumpdir to user
*******************************************************************************/
package org.eclipse.mat.ui.internal.acquire;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.mat.SnapshotException;
import org.eclipse.mat.internal.acquire.HeapDumpProviderDescriptor;
import org.eclipse.mat.internal.acquire.HeapDumpProviderRegistry;
import org.eclipse.mat.query.annotations.descriptors.IAnnotatedObjectDescriptor;
import org.eclipse.mat.query.registry.AnnotatedObjectArgumentsSet;
import org.eclipse.mat.query.registry.ArgumentDescriptor;
import org.eclipse.mat.query.registry.ArgumentFactory;
import org.eclipse.mat.snapshot.acquire.VmInfo;
import org.eclipse.mat.ui.MemoryAnalyserPlugin;
import org.eclipse.mat.ui.Messages;
import org.eclipse.mat.ui.editor.PathEditorInput;
import org.eclipse.mat.ui.util.ErrorHelper;
import org.eclipse.mat.ui.util.ProgressMonitorWrapper;
import org.eclipse.mat.util.IProgressListener;
import org.eclipse.mat.util.MessageUtil;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.ui.IWorkbenchWizard;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
public class AcquireSnapshotAction extends Action implements IWorkbenchWindowActionDelegate
{
public void run()
{
final Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
Collection<HeapDumpProviderDescriptor> dumpProviders = HeapDumpProviderRegistry.instance().getHeapDumpProviders();
if (dumpProviders == null || dumpProviders.size() == 0)
{
showError(Messages.AcquireSnapshotAction_NoProviderError);
return;
}
Wizard wizard = new AcquireWizard(dumpProviders);
WizardDialog dialog = new WizardDialog(shell, wizard);
dialog.setHelpAvailable(true);
dialog.open();
}
public static class AcquireWizard extends Wizard implements IWorkbenchWizard {
ProviderConfigurationWizardPage configPage;
AcquireDialog acquireDialog;
ProviderArgumentsWizardPage argumentsPage;
Collection<HeapDumpProviderDescriptor> dumpProviders;
public AcquireWizard(Collection<HeapDumpProviderDescriptor> dumpProviders)
{
this.dumpProviders = dumpProviders;
setWindowTitle(Messages.AcquireSnapshotAction_AcquireDialogName);
setNeedsProgressMonitor(true);
}
public AcquireWizard()
{
this(HeapDumpProviderRegistry.instance().getHeapDumpProviders());
}
public void addPages()
{
acquireDialog = new AcquireDialog(dumpProviders);
configPage = new ProviderConfigurationWizardPage(acquireDialog);
argumentsPage = new ProviderArgumentsWizardPage(acquireDialog);
addPage(configPage);
addPage(acquireDialog);
addPage(argumentsPage);
}
public boolean performFinish()
{
if (acquireDialog == null)
return false;
VmInfo selectedProcess = acquireDialog.getProcess();
try
{
String selectedPath = acquireDialog.getSelectedPath();
File preferredLocation = new File(selectedPath);
if (!validatePath(preferredLocation)) return false;
// request the heap dump and check if result is OK
AcquireDumpOperation dumpOperation = new AcquireDumpOperation(selectedProcess, preferredLocation, argumentsPage.getArgumentSet(), getContainer());
if (!dumpOperation.run().isOK())
{
// Update the arguments with any modified VmInfo to allow a retry
AnnotatedObjectArgumentsSet args = argumentsPage.getArgumentSet();
argumentsPage.processSelected(null);
argumentsPage.processSelected(args);
return false;
}
File destFile = dumpOperation.getResult();
// open the heapdump
Path path = new Path(destFile.getAbsolutePath());
// Find the content type of the dump
FileInputStream is = null;
IContentType ct;
try
{
is = new FileInputStream(destFile);
ct = Platform.getContentTypeManager().findContentTypeFor(is, destFile.getAbsolutePath());
}
catch (IOException e)
{
ct = null;
}
finally
{
if (is != null)
is.close();
}
IEditorDescriptor descriptor = ct != null ?
PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(path.toOSString(), ct) :
PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(path.toOSString());
try
{
IDE.openEditor(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), new PathEditorInput(path), descriptor != null ? descriptor.getId() : MemoryAnalyserPlugin.EDITOR_ID,
true);
if (PlatformUI.getWorkbench().getIntroManager().getIntro() != null)
{
// if this action was called with open welcome page
// - set it to standby mode.
PlatformUI.getWorkbench().getIntroManager().setIntroStandby(PlatformUI.getWorkbench().getIntroManager().getIntro(), true);
}
}
catch (Exception e)
{
ErrorHelper.logThrowableAndShowMessage(e, Messages.AcquireSnapshotAction_UnableToOpenEditor + path);
}
if (new File(acquireDialog.getSelectedPath()).exists()) acquireDialog.saveSettings();
}
catch (Exception e)
{
ErrorHelper.logThrowableAndShowMessage(e);
return false;
}
return true;
}
private boolean validatePath(File destFile)
{
if (destFile.exists())
{
if (MessageDialog.openConfirm(getShell(), Messages.AcquireSnapshotAction_Confirmation, Messages.AcquireSnapshotAction_FileAlreadyExists))
{
if (!destFile.delete())
{
if (ErrorDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), Messages.AcquireSnapshotAction_Warning, null, ErrorHelper.createErrorStatus(Messages.AcquireSnapshotAction_UnableToDeleteFile)) != Dialog.OK)
{
return false;
}
}
}
else
{
return false;
}
}
else if (destFile.getParentFile() != null && !destFile.getParentFile().isDirectory())
{
if (MessageDialog.openConfirm(getShell(), Messages.AcquireSnapshotAction_Confirmation, Messages.AcquireSnapshotAction_DirectoryDoesntExist))
{
if (!destFile.getParentFile().mkdirs())
{
if (ErrorDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), Messages.AcquireSnapshotAction_Warning, null, ErrorHelper.createErrorStatus(Messages.AcquireSnapshotAction_UnableToCreateDirectory)) != Dialog.OK)
{
return false;
}
}
}
else
{
return false;
}
}
return true;
}
@Override
public boolean canFinish()
{
return acquireDialog.isPageComplete() && argumentsPage.isPageComplete() && configPage.isPageComplete();
}
@Override
public IWizardPage getStartingPage() {
return acquireDialog;
}
public void init(IWorkbench workbench, IStructuredSelection selection)
{
}
}
private void showError(String msg)
{
ErrorDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), Messages.AcquireSnapshotAction_Error, null, ErrorHelper.createErrorStatus(msg));
}
public void dispose()
{}
public void init(IWorkbenchWindow window)
{}
public void run(IAction action)
{
run();
}
public void selectionChanged(IAction action, ISelection selection)
{}
public static class Handler extends AbstractHandler
{
public Handler()
{}
public Object execute(ExecutionEvent executionEvent)
{
new AcquireSnapshotAction().run();
return null;
}
}
static class AcquireDumpOperation implements IRunnableWithProgress
{
private IStatus status;
private IRunnableContext context;
private VmInfo vmInfo;
private File preferredLocation;
private File result;
private AnnotatedObjectArgumentsSet argumentSet;
public AcquireDumpOperation(VmInfo vmInfo, File preferredLocation, AnnotatedObjectArgumentsSet argumentSet, IRunnableContext context)
{
this.vmInfo = vmInfo;
this.preferredLocation = preferredLocation;
this.context = context;
this.argumentSet = argumentSet;
}
private IStatus doOperation(IProgressMonitor monitor)
{
IProgressListener listener = new ProgressMonitorWrapper(monitor);
try
{
result = triggerHeapDump(listener);
if (listener.isCanceled()) return Status.CANCEL_STATUS;
}
catch (Exception e)
{
return ErrorHelper.createErrorStatus(e);
}
return Status.OK_STATUS;
}
private File triggerHeapDump(IProgressListener listener) throws SnapshotException, SnapshotException
{
VmInfo impl = vmInfo;
setupVmInfo(vmInfo, argumentSet);
File result = impl.getHeapDumpProvider().acquireDump(vmInfo, preferredLocation, listener);
return result;
}
static void setupVmInfo(VmInfo vmInfo, AnnotatedObjectArgumentsSet argumentSet) throws SnapshotException
{
try
{
IAnnotatedObjectDescriptor providerDescriptor = (IAnnotatedObjectDescriptor) argumentSet.getDescriptor();
VmInfo impl = vmInfo;
for (ArgumentDescriptor parameter : providerDescriptor.getArguments())
{
Object value = argumentSet.getArgumentValue(parameter);
if (value == null && parameter.isMandatory())
{
value = parameter.getDefaultValue();
if (value == null)
throw new SnapshotException(MessageUtil.format(
Messages.AcquireSnapshotAction_MissingParameterErrorMessage, parameter.getName()));
}
if (value == null)
{
if (argumentSet.getValues().containsKey(parameter))
{
Logger.getLogger(AcquireDumpOperation.class.getName()).log(Level.INFO,
MessageUtil.format("Setting null value for: {0}", parameter.getName())); //$NON-NLS-1$
if (parameter.isBoolean())
parameter.getField().set(impl, parameter.getDefaultValue());
else
parameter.getField().set(impl, null);
}
continue;
}
try
{
if (value instanceof ArgumentFactory)
{
parameter.getField().set(impl, ((ArgumentFactory) value).build(parameter));
}
else if (parameter.isArray())
{
List<?> list = (List<?>) value;
Object array = Array.newInstance(parameter.getType(), list.size());
int ii = 0;
for (Object v : list)
Array.set(array, ii++, v);
parameter.getField().set(impl, array);
}
else if (parameter.isList())
{
// handle ArgumentFactory inside list
List<?> source = (List<?>) value;
List<Object> target = new ArrayList<Object>(source.size());
for (int ii = 0; ii < source.size(); ii++)
{
Object v = source.get(ii);
if (v instanceof ArgumentFactory)
v = ((ArgumentFactory) v).build(parameter);
target.add(v);
}
parameter.getField().set(impl, target);
}
else
{
parameter.getField().set(impl, value);
}
}
catch (IllegalArgumentException e)
{
throw new SnapshotException(MessageUtil.format(Messages.AcquireSnapshotAction_IllegalTypeErrorMessage, value,
value.getClass().getName(), parameter.getName(), parameter.getType().getName()), e);
}
catch (IllegalAccessException e)
{
// should not happen as we check accessibility when
// registering queries
throw new SnapshotException(MessageUtil.format("Unable to access field {0} of type {1}", parameter //$NON-NLS-1$
.getName(), parameter.getType().getName()), e);
}
}
}
catch (IProgressListener.OperationCanceledException e)
{
throw e; // no nesting!
}
catch (SnapshotException e)
{
throw e; // no nesting!
}
catch (Exception e)
{
throw SnapshotException.rethrow(e);
}
}
private File getResult()
{
return result;
}
public final void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException
{
status = doOperation(monitor);
}
public final IStatus run()
{
try
{
context.run(true, true, this);
}
catch (Exception e)
{
status = ErrorHelper.createErrorStatus(Messages.AcquireSnapshotAction_UnexpectedException, e);
}
// report error if any occurred
if (!status.isOK() && status != Status.CANCEL_STATUS)
ErrorDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), Messages.AcquireSnapshotAction_Error, null, status);
return status;
}
}
}