/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * 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: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.workbench.internal.contributions; import java.io.File; import java.io.IOException; import java.lang.management.ManagementFactory; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.FileDialog; import org.osgi.service.prefs.BackingStoreException; import org.osgi.service.prefs.Preferences; import org.simantics.utils.ui.ErrorLogger; import org.simantics.utils.ui.ExceptionUtils; import org.simantics.utils.ui.gfx.HSVAdjustmentImageDescriptor; import org.simantics.workbench.internal.Activator; /** * @author Tuukka Lehtonen */ public class DumpHeapButtonTrim extends Composite { private static final String PREF_HEAP_DUMP_PATH = "heap.dump.path"; IPath path; LocalResourceManager resourceManager; boolean disabled = false; /** * Creates a new heap status control with the given parent, and using * the given preference store to obtain settings such as the refresh * interval. * * @param parent the parent composite * @param prefStore the preference store */ public DumpHeapButtonTrim(Composite parent) { super(parent, SWT.NONE); restorePrefs(); setLayout(new FillLayout()); final Button b = new Button(this, SWT.PUSH); this.resourceManager = new LocalResourceManager(JFaceResources.getResources(), b); b.setToolTipText("Dump Java heap for debugging"); b.setImage(resourceManager.createImage(Activator.getImageDescriptor("img/lorry.png"))); b.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (disabled) return; dumpHeap(); } }); if (getBean() == null) { disabled = true; b.setImage(resourceManager.createImage(HSVAdjustmentImageDescriptor.adjustSaturation( Activator.getImageDescriptor("img/lorry.png"), 0))); b.setToolTipText("Sorry, Java heap dumping not available, JVM does not support HotSpotDiagnosticMXBean."); } } private void restorePrefs() { Preferences prefs = InstanceScope.INSTANCE.getNode(Activator.PLUGIN_ID); String p = prefs.get(PREF_HEAP_DUMP_PATH, null); path = p == null ? null : new Path(p); } private void savePrefs() { Preferences prefs = InstanceScope.INSTANCE.getNode(Activator.PLUGIN_ID); prefs.put(PREF_HEAP_DUMP_PATH, path.toPortableString()); try { prefs.flush(); } catch (BackingStoreException e) { ErrorLogger.defaultLogError(e); } } private void dumpHeap() { FileDialog fd = new FileDialog(getShell(), SWT.SAVE); fd.setFilterExtensions(new String[] { "*.hprof" }); if (path != null) { fd.setFileName(path.lastSegment()); fd.setFilterPath(path.removeLastSegments(1).toOSString()); } String result = fd.open(); if (result == null) return; path = new Path(result); savePrefs(); try { final File dumpFile = path.toFile(); if (dumpFile.exists() && !dumpFile.delete()) { MessageDialog.openError(getShell(), "Delete Failed", "Could not delete old heap dump file '" + dumpFile + "'.\n\nIs the file still in use?"); return; } new ProgressMonitorDialog(getShell()).run(true, false, new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { monitor.beginTask("Creating heap dump '" + dumpFile + "'", IProgressMonitor.UNKNOWN); try { Object bean = getBean(); if (bean == null) return; Method m = bean.getClass().getMethod("dumpHeap", String.class, boolean.class); m.invoke(bean, path.toOSString(), true); } catch (IllegalArgumentException e) { throw new InvocationTargetException(e); } catch (IllegalAccessException e) { throw new InvocationTargetException(e); } catch (SecurityException e) { throw new InvocationTargetException(e); } catch (NoSuchMethodException e) { throw new InvocationTargetException(e); } finally { monitor.done(); } } }); } catch (InvocationTargetException e) { Throwable t = e.getTargetException(); ExceptionUtils.logAndShowError(t); } catch (InterruptedException e) { ExceptionUtils.logAndShowError(e); } } private static Object getBean() { Class beanClass = getBeanClass(); if (beanClass == null) return null; try { Object bean = ManagementFactory.newPlatformMXBeanProxy( ManagementFactory.getPlatformMBeanServer(), "com.sun.management:type=HotSpotDiagnostic", beanClass); return bean; } catch (IOException e) { return null; } } private static Class getBeanClass() { try { Class clazz = Class.forName("com.sun.management.HotSpotDiagnosticMXBean"); return clazz; } catch (ClassNotFoundException e) { return null; } } }