/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.visualvm.coredump.impl;
import com.sun.tools.visualvm.core.datasource.DataSourceRepository;
import com.sun.tools.visualvm.core.datasource.Storage;
import com.sun.tools.visualvm.core.snapshot.Snapshot;
import com.sun.tools.visualvm.core.datasupport.Utils;
import com.sun.tools.visualvm.core.explorer.ExplorerSupport;
import com.sun.tools.visualvm.core.datasource.descriptor.DataSourceDescriptor;
import com.sun.tools.visualvm.core.datasource.descriptor.DataSourceDescriptorFactory;
import com.sun.tools.visualvm.coredump.CoreDumpSupport;
import com.sun.tools.visualvm.coredump.CoreDumpsContainer;
import com.sun.tools.visualvm.tools.sa.SaModel;
import com.sun.tools.visualvm.tools.sa.SaModelFactory;
import java.awt.BorderLayout;
import java.io.File;
import java.io.FilenameFilter;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.netbeans.lib.profiler.ui.SwingWorker;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
import org.openide.windows.WindowManager;
/**
*
* @author Tomas Hurka
* @author Jiri Sedlacek
*/
public class CoreDumpProvider {
private static final Logger LOGGER = Logger.getLogger(CoreDumpProvider.class.getName());
private static final String SNAPSHOT_VERSION = "snapshot_version"; // NOI18N
private static final String SNAPSHOT_VERSION_DIVIDER = "."; // NOI18N
private static final String CURRENT_SNAPSHOT_VERSION_MAJOR = "1"; // NOI18N
private static final String CURRENT_SNAPSHOT_VERSION_MINOR = "0"; // NOI18N
private static final String CURRENT_SNAPSHOT_VERSION = CURRENT_SNAPSHOT_VERSION_MAJOR + SNAPSHOT_VERSION_DIVIDER + CURRENT_SNAPSHOT_VERSION_MINOR;
private static final String PROPERTY_JAVA_HOME = "prop_java_home"; // NOI18N
private static class CoreDumpAdder extends SwingWorker {
volatile private ProgressHandle ph = null;
volatile private boolean success = false;
private CoreDumpImpl newCoreDump;
private Storage storage;
private String[] propNames, propValues;
public CoreDumpAdder(CoreDumpImpl newCoreDump, Storage storage, String[] propNames, String[] propValues) {
this.newCoreDump = newCoreDump;
this.storage = storage;
this.propValues = propValues;
this.propNames = propNames;
}
@Override
protected void doInBackground() {
SaModel model = SaModelFactory.getSAAgentFor(newCoreDump);
if (model != null) {
storage.setCustomProperties(propNames, propValues);
CoreDumpsContainer.sharedInstance().getRepository().addDataSource(newCoreDump);
success = true;
}
}
@Override
protected void nonResponding() {
ph = ProgressHandleFactory.createHandle(NbBundle.getMessage(CoreDumpProvider.class, "LBL_Inspecting_core_dump")); // NOI18N
ph.start();
}
@Override
protected void done() {
if (ph != null) {
ph.finish();
}
if (!success) {
DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(NbBundle.getMessage(CoreDumpProvider.class, "MSG_not_valid_core_dump", newCoreDump.getFile().getAbsolutePath()))); // NOI18N
}
}
}
static void createCoreDump(final String coreDumpFile, final String displayName, final String jdkHome, final boolean deleteCoreDump) {
RequestProcessor.getDefault().post(new Runnable() {
public void run() {
createCoreDumpImpl(coreDumpFile, displayName, jdkHome, deleteCoreDump);
}
});
}
private static void createCoreDumpImpl(String coreDumpFile, final String displayName, String jdkHome, boolean deleteCoreDump) {
// TODO: check if the same coredump isn't already imported (can happen for moved coredumps)
final CoreDumpImpl knownCoreDump = getCoreDumpByFile(new File(coreDumpFile));
if (knownCoreDump != null) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ExplorerSupport.sharedInstance().selectDataSource(knownCoreDump);
DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.
Message(NbBundle.getMessage(CoreDumpProvider.class,
"MSG_Core_dump_already_added", new Object[] {displayName, // NOI18N
DataSourceDescriptorFactory.getDescriptor(knownCoreDump).
getName()}), NotifyDescriptor.ERROR_MESSAGE));
}
});
return;
}
if (deleteCoreDump) {
ProgressHandle pHandle = null;
try {
pHandle = ProgressHandleFactory.createHandle(NbBundle.getMessage(CoreDumpProvider.class, "MSG_Adding", displayName)); // NOI18N
pHandle.setInitialDelay(0);
pHandle.start();
File file = new File(coreDumpFile);
File copy = Utils.getUniqueFile(CoreDumpSupport.getStorageDirectory(), file.getName());
if (Utils.copyFile(file, copy)) {
coreDumpFile = copy.getAbsolutePath();
if (!file.delete()) file.deleteOnExit();
}
} finally {
final ProgressHandle pHandleF = pHandle;
SwingUtilities.invokeLater(new Runnable() {
public void run() { if (pHandleF != null) pHandleF.finish(); }
});
}
}
final String[] propNames = new String[] {
SNAPSHOT_VERSION,
Snapshot.PROPERTY_FILE,
DataSourceDescriptor.PROPERTY_NAME,
PROPERTY_JAVA_HOME };
final String[] propValues = new String[] {
CURRENT_SNAPSHOT_VERSION,
coreDumpFile,
displayName,
jdkHome
};
File customPropertiesStorage = Utils.getUniqueFile(CoreDumpSupport.getStorageDirectory(), new File(coreDumpFile).getName(), Storage.DEFAULT_PROPERTIES_EXT);
Storage storage = new Storage(customPropertiesStorage.getParentFile(), customPropertiesStorage.getName());
try {
CoreDumpImpl newCoreDump = new CoreDumpImpl(new File(coreDumpFile), new File(jdkHome), storage);
if (newCoreDump != null) {
new CoreDumpAdder(newCoreDump, storage, propNames, propValues).execute();
}
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Error creating coredump", e); // NOI18N
return;
}
}
private static CoreDumpImpl getCoreDumpByFile(File file) {
if (!file.isFile()) return null;
Set<CoreDumpImpl> knownCoredumps = DataSourceRepository.sharedInstance().getDataSources(CoreDumpImpl.class);
for (CoreDumpImpl knownCoredump : knownCoredumps)
if (knownCoredump.getFile().equals(file)) return knownCoredump;
return null;
}
private void initPersistedCoreDumps() {
if (!CoreDumpSupport.storageDirectoryExists()) return;
File[] files = CoreDumpSupport.getStorageDirectory().listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(Storage.DEFAULT_PROPERTIES_EXT);
}
});
Set<File> unresolvedCoreDumpsF = new HashSet();
Set<String> unresolvedCoreDumpsS = new HashSet();
Set<CoreDumpImpl> coredumps = new HashSet();
for (File file : files) {
Storage storage = new Storage(file.getParentFile(), file.getName());
String[] propNames = new String[] {
Snapshot.PROPERTY_FILE,
PROPERTY_JAVA_HOME
};
String[] propValues = storage.getCustomProperties(propNames);
if (propValues[0] == null || propValues[1] == null) continue;
CoreDumpImpl persistedCoredump = null;
try {
persistedCoredump = new CoreDumpImpl(new File(propValues[0]), new File(propValues[1]), storage);
} catch (Exception e) {
LOGGER.log(Level.INFO, "Error loading persisted coredump", e); // NOI18N
unresolvedCoreDumpsF.add(file);
unresolvedCoreDumpsS.add(propValues[0]);
}
if (persistedCoredump != null) coredumps.add(persistedCoredump);
}
if (!unresolvedCoreDumpsF.isEmpty()) notifyUnresolvedCoreDumps(unresolvedCoreDumpsF, unresolvedCoreDumpsS);
if (!coredumps.isEmpty())
CoreDumpsContainer.sharedInstance().getRepository().addDataSources(coredumps);
}
private static void notifyUnresolvedCoreDumps(final Set<File> unresolvedCoreDumpsF, final Set<String> unresolvedCoreDumpsS) {
RequestProcessor.getDefault().post(new Runnable() {
public void run() {
JPanel messagePanel = new JPanel(new BorderLayout(5, 5));
messagePanel.add(new JLabel(NbBundle.getMessage(CoreDumpProvider.class, "MSG_Unresolved_CoreDumps")), BorderLayout.NORTH); // NOI18N
JList list = new JList(unresolvedCoreDumpsS.toArray());
list.setVisibleRowCount(4);
messagePanel.add(new JScrollPane(list), BorderLayout.CENTER);
NotifyDescriptor dd = new NotifyDescriptor(
messagePanel, NbBundle.getMessage(CoreDumpProvider.class, "Title_Unresolved_CoreDumps"), // NOI18N
NotifyDescriptor.YES_NO_OPTION, NotifyDescriptor.ERROR_MESSAGE,
null, NotifyDescriptor.YES_OPTION);
if (DialogDisplayer.getDefault().notify(dd) == NotifyDescriptor.NO_OPTION)
for (File file : unresolvedCoreDumpsF) Utils.delete(file, true);
unresolvedCoreDumpsF.clear();
unresolvedCoreDumpsS.clear();
}
}, 1000);
}
CoreDumpProvider() {
}
public static void register() {
final CoreDumpProvider provider = new CoreDumpProvider();
WindowManager.getDefault().invokeWhenUIReady(new Runnable() {
public void run() {
RequestProcessor.getDefault().post(new Runnable() {
public void run() {
provider.initPersistedCoreDumps();
}
});
}
});
}
}