/*
* 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.profiling.presets;
import com.sun.tools.visualvm.application.Application;
import com.sun.tools.visualvm.application.jvm.Jvm;
import com.sun.tools.visualvm.application.jvm.JvmFactory;
import com.sun.tools.visualvm.application.type.ApplicationTypeFactory;
import com.sun.tools.visualvm.core.datasource.descriptor.DataSourceDescriptorFactory;
import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.prefs.Preferences;
import javax.swing.DefaultListModel;
import javax.swing.SwingUtilities;
import org.netbeans.api.options.OptionsDisplayer;
import org.openide.util.NbBundle;
import org.openide.util.NbPreferences;
import org.openide.util.RequestProcessor;
import org.openide.util.Utilities;
/**
*
* @author Jiri Sedlacek
*/
public final class ProfilerPresets {
private static final String JAR_SUFFIX = ".jar"; // NOI18N
private static final String OPTIONS_HANDLE = "ProfilerOptions"; // NOI18N
private static final String PROP_PRESET_HEADER = "prof_preset_header"; // NOI18N
private static ProfilerPresets INSTANCE;
private Preferences prefs;
private List<ProfilerPreset> presets;
private ProfilerPreset presetToSelect;
private ProfilerPreset presetToCreate;
private final Set<WeakReference<PresetSelector>> selectors;
public static synchronized ProfilerPresets getInstance() {
if (INSTANCE == null) INSTANCE = new ProfilerPresets();
return INSTANCE;
}
public void editPresets(ProfilerPreset preset) {
presetToSelect = preset;
OptionsDisplayer.getDefault().open(OPTIONS_HANDLE);
}
ProfilerPreset presetToSelect() {
ProfilerPreset toSelect = presetToSelect;
presetToSelect = null;
return toSelect;
}
public void savePreset(ProfilerPreset preset) {
presetToCreate = preset;
OptionsDisplayer.getDefault().open(OPTIONS_HANDLE);
}
ProfilerPreset presetToCreate() {
ProfilerPreset toCreate = presetToCreate;
presetToCreate = null;
return toCreate;
}
void optionsSubmitted(final ProfilerPreset selected) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Iterator<WeakReference<PresetSelector>> selectorsI =
selectors.iterator();
while (selectorsI.hasNext()) {
WeakReference<PresetSelector> selectorR = selectorsI.next();
PresetSelector selector = selectorR.get();
if (selector == null) selectorsI.remove();
else if (SwingUtilities.getRoot(selector) == null) selectorsI.remove();
else selector.presetsChanged(selected);
}
}
});
}
public PresetSelector createSelector(PresetSelector refSelector,
Runnable presetSync) {
return createSelector(null, refSelector, presetSync);
}
public PresetSelector createSelector(Application application,
PresetSelector refSelector,
Runnable presetSync) {
String mainClass = null;
if (application != null) {
mainClass = getMainClass(application);
if (mainClass == null || mainClass.isEmpty()) mainClass =
ApplicationTypeFactory.getApplicationTypeFor(application).getName();
if (mainClass == null || mainClass.isEmpty()) mainClass =
DataSourceDescriptorFactory.getDescriptor(application).getName();
}
ProfilerPreset toSelect = null;
if (mainClass != null && !mainClass.isEmpty()) {
String mainClassL = mainClass.toLowerCase();
for (int i = 0; i < presets.size(); i++) {
ProfilerPreset preset = presets.get(i);
String selector = preset.getSelector();
if (selector != null && !selector.isEmpty()) {
if (mainClass.equals(selector) || mainClassL.contains(selector.toLowerCase())) {
toSelect = preset;
break;
}
}
}
}
ProfilerPreset defPreset = createDefaultPreset(application);
ProfilerPreset custPreset = null;
PresetSelector selector = new PresetSelector(refSelector, defPreset, custPreset,
toSelect, presetSync, mainClass);
selectors.add(new WeakReference(selector));
return selector;
}
public ProfilerPreset[] getPresets(Application application) {
ProfilerPreset[] presetsArr = new ProfilerPreset[presets.size() + 1];
int index = 0;
presetsArr[index++] = createDefaultPreset(application);
for (ProfilerPreset preset : presets) presetsArr[index++] = preset;
return presetsArr;
}
private void loadPresets() {
RequestProcessor.getDefault().post(new Runnable() {
public void run() {
final List<ProfilerPreset> loadedPresets = doLoadPresets();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
presets.clear();
presets.addAll(loadedPresets);
}
});
}
});
}
void savePresets(final PresetsModel toSave) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
presets.clear();
Enumeration en = toSave.elements();
while (en.hasMoreElements())
presets.add((ProfilerPreset)en.nextElement());
RequestProcessor.getDefault().post(new Runnable() {
public void run() { doSavePresets(toSave); }
});
}
});
}
PresetsModel getPresets() {
PresetsModel model = new PresetsModel();
for (ProfilerPreset preset : presets) model.addElement(preset);
return model;
}
private static ProfilerPreset createDefaultPreset(Application application) {
ProfilerPreset defaultPreset = new ProfilerPreset(NbBundle.getMessage(
ProfilerPresets.class, "MSG_Default"), ""); // NOI18N
defaultPreset.setFilterS(getDefaultFiltersS());
defaultPreset.setRootsP(getDefaultRootsP(application));
defaultPreset.setFilterP(getDefaultFiltersP(defaultPreset.getRootsP()));
return defaultPreset;
}
private static String getMainClass(Application application) {
Jvm jvm = JvmFactory.getJVMFor(application);
String mainClass = jvm.getMainClass();
if (mainClass == null || mainClass.trim().length() == 0) {
mainClass = ""; // NOI18N
} else if (mainClass.endsWith(JAR_SUFFIX)) {
// application is launched with -jar and uses relative path, try to find jar
mainClass = ""; // NOI18N
if (jvm.isGetSystemPropertiesSupported()) {
Properties sysProp = jvm.getSystemProperties();
if (sysProp != null) {
String userdir = sysProp.getProperty("user.dir"); // NOI18N
if (userdir != null) {
String args = jvm.getCommandLine();
int index = args.indexOf(JAR_SUFFIX);
if (index != -1) {
File jarFile = new File(userdir,args.substring(0,index+JAR_SUFFIX.length()));
if (jarFile.exists()) {
try {
JarFile jf = new JarFile(jarFile);
String mainClassName = jf.getManifest().getMainAttributes().getValue(Attributes.Name.MAIN_CLASS);
assert mainClassName!=null;
mainClass = mainClassName.replace('\\', '/').replace('/', '.'); // NOI18N
} catch (IOException ex) {
// LOGGER.log(Level.INFO, "getMainClass", ex); // NOI18N
}
}
}
}
}
}
}
return mainClass;
}
private static String getDefaultFiltersS() {
return Utilities.isMac() ?
"java.*, javax.*,\nsun.*, sunw.*, com.sun.*,\ncom.apple.*, apple.awt.*, apple.laf.*" : // NOI18N
"java.*, javax.*,\nsun.*, sunw.*, com.sun.*"; // NOI18N
}
private static String getDefaultRootsP(Application application) {
if (application == null) return NbBundle.getMessage(
ProfilerPresets.class, "HINT_Define_roots"); // NOI18N
String mainClass = getMainClass(application);
if ("".equals(mainClass)) { // unknown main class
return NbBundle.getMessage(ProfilerPresets.class, "HINT_Define_roots"); // NOI18N
}
int dotIndex = mainClass.lastIndexOf("."); // NOI18N
if (dotIndex == -1) return mainClass; // default package
else return mainClass.substring(0, dotIndex + 1) + "**"; // NOI18N
}
private static String getDefaultFiltersP(String defaultRoots) {
if (defaultRoots.isEmpty())
return !Utilities.isMac() ? "sun.*, sunw.*, com.sun.*" : // NOI18N
"sun.*, sunw.*, com.sun.*,\ncom.apple.*, apple.awt.*, apple.laf.*"; // NOI18N
else
return !Utilities.isMac() ? "java.*, javax.*,\nsun.*, sunw.*, com.sun.*" : // NOI18N
"java.*, javax.*,\nsun.*, sunw.*, com.sun.*,\ncom.apple.*, apple.awt.*, apple.laf.*"; // NOI18N
}
private List<ProfilerPreset> doLoadPresets() {
Preferences p = prefs();
List<ProfilerPreset> loadedPresets = new ArrayList();
int i = 0;
String prefix = i + "_"; // NOI18N
while (p.get(prefix + PROP_PRESET_HEADER, null) != null) {
loadedPresets.add(new ProfilerPreset(p, prefix));
prefix = ++i + "_"; // NOI18N
}
return loadedPresets;
}
private void doSavePresets(PresetsModel toSave) {
Preferences p = prefs();
try { p.clear(); } catch (Exception e) {}
int count = toSave.size();
for (int i = 0; i < count; i++) {
String prefix = i + "_"; // NOI18N
p.put(prefix + PROP_PRESET_HEADER, ""); // NOI18N
ProfilerPreset preset = (ProfilerPreset)toSave.get(i);
preset.toPreferences(p, prefix); // NOI18N
}
}
private synchronized Preferences prefs() {
if (prefs == null) prefs = NbPreferences.forModule(ProfilerPresets.class);
return prefs;
}
private ProfilerPresets() {
presets = new ArrayList();
selectors = new HashSet();
loadPresets();
}
static class PresetsModel extends DefaultListModel {
void addPreset(ProfilerPreset preset) {
addElement(preset);
}
void removePreset(int preset) {
removeElementAt(preset);
}
void movePresetUp(int preset) {
Object o = elementAt(preset);
remove(preset);
add(preset - 1, o);
}
void movePresetDown(int preset) {
Object o = elementAt(preset);
remove(preset);
add(preset + 1, o);
}
public void fireItemChanged(int itemIndex) {
fireContentsChanged(this, itemIndex, itemIndex);
}
}
}