blob: 4033479c3996ef401814793a8e4f50691b6c807c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.profiler.heapwalk;
import org.netbeans.lib.profiler.heap.*;
import org.netbeans.modules.profiler.heapwalk.ui.HeapFragmentWalkerUI;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.modules.profiler.api.ProfilerDialogs;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
/**
*
* @author Jiri Sedlacek
*/
@NbBundle.Messages({
"HeapFragmentWalker_ComputeRetainedMsg=<html><b>Retained sizes will be computed.</b><br><br>For large heap dumps this operation can take a significant<br>amount of time. Do you want to continue?</html>",
"HeapFragmentWalker_ComputeRetainedCaption=Compute Retained Sizes",
"HeapFragmentWalker_ComputingRetainedMsg=Computing retained sizes...",
"HeapFragmentWalker_ComputingRetainedCaption=Computing Retained Sizes"
})
public class HeapFragmentWalker {
public static final int RETAINED_SIZES_UNSUPPORTED = -1;
public static final int RETAINED_SIZES_UNKNOWN = 0;
public static final int RETAINED_SIZES_CANCELLED = 1;
public static final int RETAINED_SIZES_COMPUTING = 2;
public static final int RETAINED_SIZES_COMPUTED = 3;
//~ Instance fields ----------------------------------------------------------------------------------------------------------
private AnalysisController analysisController;
private OQLController oqlController;
private ClassesController classesController;
private Heap heapFragment; // TODO: Should be HeapFragment
private HeapFragmentWalkerUI walkerUI;
private HeapWalker heapWalker;
private InstancesController instancesController;
private NavigationHistoryManager navigationHistoryManager;
private SummaryController summaryController;
private List<StateListener> stateListeners;
private int retainedSizesStatus;
//~ Constructors -------------------------------------------------------------------------------------------------------------
// --- Constructors ----------------------------------------------------------
public HeapFragmentWalker(Heap heapFragment, HeapWalker heapWalker) {
this(heapFragment, heapWalker, false);
}
public HeapFragmentWalker(Heap heapFragment, HeapWalker heapWalker, boolean supportsRetainedSizes) {
this.heapFragment = heapFragment;
this.heapWalker = heapWalker;
this.retainedSizesStatus = supportsRetainedSizes ? RETAINED_SIZES_UNKNOWN :
RETAINED_SIZES_UNSUPPORTED;
summaryController = new SummaryController(this);
classesController = new ClassesController(this);
instancesController = new InstancesController(this);
analysisController = new AnalysisController(this);
navigationHistoryManager = new NavigationHistoryManager(this);
oqlController = new OQLController(this);
}
//~ Methods ------------------------------------------------------------------------------------------------------------------
public final int computeRetainedSizes(boolean masterAction, boolean interactive) {
synchronized(this) {
if (retainedSizesStatus == RETAINED_SIZES_UNSUPPORTED ||
retainedSizesStatus == RETAINED_SIZES_COMPUTED)
return retainedSizesStatus;
}
if (interactive && !ProfilerDialogs.displayConfirmationDNSA(
Bundle.HeapFragmentWalker_ComputeRetainedMsg(),
Bundle.HeapFragmentWalker_ComputeRetainedCaption(),
null, "HeapFragmentWalker.computeRetainedSizes", false)) { //NOI18N
return changeState(RETAINED_SIZES_CANCELLED, masterAction);
} else {
changeState(RETAINED_SIZES_COMPUTING, masterAction);
List<JavaClass> classes = heapFragment.getAllClasses();
if (classes.size() > 0) {
ProgressHandle pd = interactive ? ProgressHandle.createHandle(Bundle.HeapFragmentWalker_ComputingRetainedMsg()) : null;
if (pd != null) {
pd.start();
}
classes.get(0).getRetainedSizeByClass();
if (pd != null) pd.finish();
}
return changeState(RETAINED_SIZES_COMPUTED, masterAction);
}
}
public synchronized final int getRetainedSizesStatus() {
return retainedSizesStatus;
}
public final void addStateListener(StateListener listener) {
if (stateListeners == null) stateListeners = new ArrayList<StateListener>();
if (!stateListeners.contains(listener)) stateListeners.add(listener);
}
public final void removeStateListener(StateListener listener) {
if (stateListeners == null || !stateListeners.contains(listener)) return;
stateListeners.remove(listener);
if (stateListeners.size() == 0) stateListeners = null;
}
private synchronized int changeState(final int newState, final boolean masterChange) {
retainedSizesStatus = newState;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (stateListeners == null) return;
StateEvent e = new StateEvent(newState, masterChange);
for (StateListener listener : stateListeners)
listener.stateChanged(e);
}
});
return retainedSizesStatus;
}
public AbstractTopLevelController getActiveController() {
HeapFragmentWalkerUI ui = (HeapFragmentWalkerUI) getPanel();
if (ui == null) {
return null; // Debugger overrides getPanel() and always returns null
}
if (ui.isSummaryViewActive()) {
return summaryController;
} else if (ui.isClassesViewActive()) {
return classesController;
} else if (ui.isInstancesViewActive()) {
return instancesController;
} else if (ui.isAnalysisViewActive()) {
return analysisController;
} else if (ui.isOQLViewActive()) {
return oqlController;
}
return null;
}
public OQLController getOQLController() {
return oqlController;
}
public AnalysisController getAnalysisController() {
return analysisController;
}
public ClassesController getClassesController() {
return classesController;
}
// --- Public interface ------------------------------------------------------
public File getHeapDumpFile() {
return heapWalker.getHeapDumpFile();
}
public Lookup.Provider getHeapDumpProject() {
return heapWalker.getHeapDumpProject();
}
public Heap getHeapFragment() {
return heapFragment;
}
public InstancesController getInstancesController() {
return instancesController;
}
public boolean isNavigationBackAvailable() {
return navigationHistoryManager.isNavigationBackAvailable();
}
public boolean isNavigationForwardAvailable() {
return navigationHistoryManager.isNavigationForwardAvailable();
}
public JPanel getPanel() {
if (walkerUI == null) {
walkerUI = new HeapFragmentWalkerUI(this);
}
return walkerUI;
}
public SummaryController getSummaryController() {
return summaryController;
}
public long getTotalLiveBytes() {
return heapFragment.getSummary().getTotalLiveBytes();
}
public long getTotalLiveInstances() {
return heapFragment.getSummary().getTotalLiveInstances();
}
// --- Navigation history support
public void createNavigationHistoryPoint() {
HeapFragmentWalkerUI ui = (HeapFragmentWalkerUI) getPanel();
if (ui == null) {
return; // Debugger overrides getPanel() and always returns null
}
navigationHistoryManager.createNavigationHistoryPoint();
ui.updateNavigationActions();
}
public void navigateBack() {
HeapFragmentWalkerUI ui = (HeapFragmentWalkerUI) getPanel();
if (ui == null) {
return; // Debugger overrides getPanel() and always returns null
}
navigationHistoryManager.navigateBack();
ui.updateNavigationActions();
}
public void navigateForward() {
HeapFragmentWalkerUI ui = (HeapFragmentWalkerUI) getPanel();
if (ui == null) {
return; // Debugger overrides getPanel() and always returns null
}
navigationHistoryManager.navigateForward();
ui.updateNavigationActions();
}
public void showInstancesForClass(JavaClass jClass) {
switchToInstancesView();
instancesController.setClass(jClass);
}
public void switchToOQLView() {
((HeapFragmentWalkerUI) getPanel()).showOQLView();
}
public void switchToAnalysisView() {
((HeapFragmentWalkerUI) getPanel()).showAnalysisView();
}
public void switchToClassesView() {
((HeapFragmentWalkerUI) getPanel()).showClassesView();
}
public void switchToHistoryOQLView() {
((HeapFragmentWalkerUI) getPanel()).showHistoryOQLView();
}
public void switchToHistoryAnalysisView() {
((HeapFragmentWalkerUI) getPanel()).showHistoryAnalysisView();
}
public void switchToHistoryClassesView() {
((HeapFragmentWalkerUI) getPanel()).showHistoryClassesView();
}
public void switchToHistoryInstancesView() {
((HeapFragmentWalkerUI) getPanel()).showHistoryInstancesView();
}
public void switchToHistorySummaryView() {
((HeapFragmentWalkerUI) getPanel()).showHistorySummaryView();
}
public void switchToInstancesView() {
((HeapFragmentWalkerUI) getPanel()).showInstancesView();
}
public void switchToSummaryView() {
((HeapFragmentWalkerUI) getPanel()).showSummaryView();
}
// ---
// --- Internal interface ----------------------------------------------------
NavigationHistoryManager.NavigationHistoryCapable getNavigationHistorySource() {
AbstractTopLevelController activeController = getActiveController();
if (activeController instanceof NavigationHistoryManager.NavigationHistoryCapable) {
return (NavigationHistoryManager.NavigationHistoryCapable) activeController;
}
return null;
}
private Integer classLoaderCount;
public final int countClassLoaders() {
if (this.classLoaderCount != null) {
return this.classLoaderCount;
}
int nclassloaders = 0;
JavaClass cl = heapFragment.getJavaClassByName("java.lang.ClassLoader"); // NOI18N
if (cl != null) {
nclassloaders = cl.getInstancesCount();
Collection<JavaClass> jcs = cl.getSubClasses();
for (JavaClass jc : jcs) {
nclassloaders += jc.getInstancesCount();
}
}
return this.classLoaderCount = nclassloaders;
}
public static interface StateListener {
public void stateChanged(StateEvent e);
}
public static final class StateEvent {
private int retainedSizesStatus;
private boolean masterChange;
StateEvent(int retainedSizesStatus) {
this(retainedSizesStatus, false);
}
StateEvent(int retainedSizesStatus, boolean masterChange) {
this.retainedSizesStatus = retainedSizesStatus;
this.masterChange = masterChange;
}
public int getRetainedSizesStatus() { return retainedSizesStatus; }
public boolean isMasterChange() { return masterChange; }
}
}