001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: * The Original Software is NetBeans. The Initial Developer of the Original
026: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
027: * Microsystems, Inc. All Rights Reserved.
028: *
029: * If you wish your version of this file to be governed by only the CDDL
030: * or only the GPL Version 2, indicate your decision by adding
031: * "[Contributor] elects to include this software in this distribution
032: * under the [CDDL or GPL Version 2] license." If you do not indicate a
033: * single choice of license, a recipient has the option to distribute
034: * your version of this file under either the CDDL, the GPL Version 2 or
035: * to extend the choice of license to its licensees as provided above.
036: * However, if you add GPL Version 2 code and therefore, elected the GPL
037: * Version 2 license, then the option applies only if the new code is
038: * made subject to such option by the copyright holder.
039: */
040:
041: package org.netbeans.lib.profiler.ui.memory;
042:
043: import org.netbeans.lib.profiler.TargetAppRunner;
044: import org.netbeans.lib.profiler.client.ClientUtils;
045: import org.netbeans.lib.profiler.global.CommonConstants;
046: import org.netbeans.lib.profiler.global.ProfilingSessionStatus;
047: import org.netbeans.lib.profiler.results.memory.MemoryCCTProvider;
048: import org.netbeans.lib.profiler.ui.LiveResultsPanel;
049: import org.netbeans.lib.profiler.ui.UIUtils;
050: import java.awt.*;
051: import java.awt.event.ActionEvent;
052: import java.awt.event.ActionListener;
053: import java.awt.image.BufferedImage;
054: import java.util.ResourceBundle;
055: import javax.swing.*;
056: import javax.swing.event.PopupMenuEvent;
057: import javax.swing.event.PopupMenuListener;
058:
059: /**
060: * This class implements presentation frames for Object Allocation Profiling.
061: *
062: * @author Misha Dmitriev
063: * @author Ian Formanek
064: * @author Jiri Sedlacek
065: */
066: public class LiveAllocResultsPanel extends AllocResultsPanel implements
067: LiveResultsPanel, ActionListener {
068: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
069:
070: // -----
071: // I18N String constants
072: private static final ResourceBundle messages = ResourceBundle
073: .getBundle("org.netbeans.lib.profiler.ui.memory.Bundle"); // NOI18N
074: private static final String GO_SOURCE_POPUP_ITEM_NAME = messages
075: .getString("AllocResultsPanel_GoSourcePopupItemName"); // NOI18N
076: private static final String SHOW_STACK_TRACES_POPUP_ITEM_NAME = messages
077: .getString("AllocResultsPanel_LiveShowStackTracesPopupItemName"); // NOI18N
078: private static final String LOG_CLASS_HISTORY = messages
079: .getString("LiveResultsPanel_LogClassHistory"); // NOI18N
080: // -----
081:
082: //~ Instance fields ----------------------------------------------------------------------------------------------------------
083:
084: protected TargetAppRunner runner;
085:
086: //common actions handler
087: ActionsHandler handler;
088: private JMenuItem popupShowSource;
089: private JMenuItem popupShowStacks;
090: private JMenuItem startHisto;
091: private JPopupMenu memoryResPopupMenu;
092: private ProfilingSessionStatus status;
093: private boolean updateResultsInProgress = false;
094: private boolean updateResultsPending = false;
095:
096: //~ Constructors -------------------------------------------------------------------------------------------------------------
097:
098: public LiveAllocResultsPanel(TargetAppRunner runner,
099: MemoryResUserActionsHandler actionsHandler) {
100: this (runner, actionsHandler, null);
101: }
102:
103: public LiveAllocResultsPanel(TargetAppRunner runner,
104: MemoryResUserActionsHandler actionsHandler,
105: ActionsHandler handler) {
106: super (actionsHandler);
107: this .status = runner.getProfilerClient().getStatus();
108: this .runner = runner;
109: this .handler = handler;
110: }
111:
112: //~ Methods ------------------------------------------------------------------------------------------------------------------
113:
114: public BufferedImage getViewImage(boolean onlyVisibleArea) {
115: if (onlyVisibleArea) {
116: return UIUtils.createScreenshot(jScrollPane);
117: } else {
118: return UIUtils.createScreenshot(resTable);
119: }
120: }
121:
122: public String getViewName() {
123: return "memory-allocations-live"; // NOI18N
124: }
125:
126: public void actionPerformed(ActionEvent e) {
127: if (e.getSource() == popupShowStacks) {
128: actionsHandler.showStacksForClass(selectedClassId,
129: getSortingColumn(), getSortingOrder());
130: } else if (e.getSource() == popupShowSource) {
131: showSourceForClass(selectedClassId);
132: } else if ((e.getSource() == startHisto) && (handler != null)) {
133: handler.performAction("history logging", new Object[] {
134: new Integer(selectedClassId),
135: getClassName(selectedClassId), Boolean.FALSE }); // NOI18N
136: }
137: }
138:
139: public void fetchResultsFromTargetApp()
140: throws ClientUtils.TargetAppOrVMTerminated {
141: MemoryCCTProvider oacgb = runner.getProfilerClient()
142: .getMemoryCCTProvider();
143:
144: if (oacgb == null) {
145: throw new ClientUtils.TargetAppOrVMTerminated(
146: ClientUtils.TargetAppOrVMTerminated.VM);
147: } else {
148: totalAllocObjectsSize = oacgb.getAllocObjectNumbers();
149: nTotalAllocObjects = runner.getProfilerClient()
150: .getAllocatedObjectsCountResults();
151:
152: // In some situations nInstrClasses can be already updated, but nTotalAllocObjects.length and/ort totalAllocObjectsSize - not yet.
153: // Take measures to avoid ArrayIndexOutOfBoundsException.
154: nTrackedItems = status.getNInstrClasses();
155:
156: if (nTrackedItems > nTotalAllocObjects.length) {
157: nTrackedItems = nTotalAllocObjects.length;
158: }
159:
160: if (nTrackedItems > totalAllocObjectsSize.length) {
161: nTrackedItems = totalAllocObjectsSize.length;
162: }
163:
164: // Operations necessary for correct bar representation of results
165: maxValue = 0;
166: nTotalBytes = 0;
167: nTotalClasses = 0;
168:
169: for (int i = 0; i < nTrackedItems; i++) {
170: if (maxValue < totalAllocObjectsSize[i]) {
171: maxValue = totalAllocObjectsSize[i];
172: }
173:
174: nTotalBytes += totalAllocObjectsSize[i];
175: nTotalClasses += nTotalAllocObjects[i];
176: }
177:
178: if (handler != null) {
179: handler.performAction("history update", new Object[] {
180: nTotalAllocObjects, totalAllocObjectsSize }); // NOI18N
181: }
182:
183: initDataUponResultsFetch();
184: }
185: }
186:
187: public boolean fitsVisibleArea() {
188: return !jScrollPane.getVerticalScrollBar().isEnabled();
189: }
190:
191: public void handleRemove() {
192: }
193:
194: /**
195: * Called when auto refresh is on and profiling session will finish
196: * to give the panel chance to do some cleanup before asynchrounous
197: * call to updateLiveResults() will happen.
198: *
199: * Currently it closes the context menu if open, which would otherwise
200: * block updating the results.
201: */
202: public void handleShutdown() {
203: // Profiling session will finish and context menu is opened, this would block last live results update -> menu will be closed
204: if ((memoryResPopupMenu != null)
205: && memoryResPopupMenu.isVisible()) {
206: updateResultsPending = false; // clear the flag, updateLiveResults() will be called explicitely from outside
207: memoryResPopupMenu.setVisible(false); // close the context menu
208: }
209: }
210:
211: // --- Save current View action support --------------------------------------
212: public boolean hasView() {
213: return resTable != null;
214: }
215:
216: public boolean supports(int instrumentataionType) {
217: return instrumentataionType == CommonConstants.INSTR_OBJECT_ALLOCATIONS;
218: }
219:
220: public void updateLiveResults() {
221: if ((memoryResPopupMenu != null)
222: && memoryResPopupMenu.isVisible()) {
223: updateResultsPending = true;
224:
225: return;
226: }
227:
228: if (updateResultsInProgress == true) {
229: return;
230: }
231:
232: updateResultsInProgress = true;
233:
234: String selectedRowString = null;
235:
236: if (resTable != null) {
237: int selectedRowIndex = resTable.getSelectedRow();
238:
239: if (selectedRowIndex >= resTable.getRowCount()) {
240: selectedRowIndex = -1;
241: resTable.clearSelection();
242: }
243:
244: if (selectedRowIndex != -1) {
245: selectedRowString = resTable.getValueAt(
246: selectedRowIndex, 0).toString();
247: }
248: }
249:
250: try {
251: if (runner.getProfilingSessionStatus().targetAppRunning) {
252: reset();
253: fetchResultsFromTargetApp();
254: }
255:
256: prepareResults();
257:
258: if (selectedRowString != null) {
259: resTable.selectRowByContents(selectedRowString, 0,
260: false);
261: }
262:
263: if ((resTable != null) && resTable.isFocusOwner()) {
264: resTable.requestFocusInWindow(); // prevents results table from losing focus
265: }
266: } catch (ClientUtils.TargetAppOrVMTerminated targetAppOrVMTerminated) {
267: targetAppOrVMTerminated.printStackTrace(System.err);
268: }
269:
270: updateResultsInProgress = false;
271: }
272:
273: protected String getClassName(int classId) {
274: return status.getClassNames()[classId];
275: }
276:
277: protected String[] getClassNames() {
278: return status.getClassNames();
279: }
280:
281: protected JPopupMenu getPopupMenu() {
282: if (memoryResPopupMenu == null) {
283: memoryResPopupMenu = new JPopupMenu();
284:
285: Font boldfont = memoryResPopupMenu.getFont().deriveFont(
286: Font.BOLD);
287:
288: popupShowSource = new JMenuItem();
289: popupShowSource.setFont(boldfont);
290: popupShowSource.setText(GO_SOURCE_POPUP_ITEM_NAME);
291: memoryResPopupMenu.add(popupShowSource);
292:
293: popupShowSource.addActionListener(this );
294:
295: if (runner.getProfilerEngineSettings()
296: .getAllocStackTraceLimit() != 0) {
297: memoryResPopupMenu.addSeparator();
298: popupShowStacks = new JMenuItem();
299: popupShowStacks
300: .setText(SHOW_STACK_TRACES_POPUP_ITEM_NAME);
301: memoryResPopupMenu.add(popupShowStacks);
302: popupShowStacks.addActionListener(this );
303: }
304:
305: memoryResPopupMenu.addSeparator();
306: startHisto = new JMenuItem();
307: startHisto.setText(LOG_CLASS_HISTORY);
308: memoryResPopupMenu.add(startHisto);
309: startHisto.addActionListener(this );
310: }
311:
312: memoryResPopupMenu
313: .addPopupMenuListener(new PopupMenuListener() {
314: public void popupMenuCanceled(PopupMenuEvent e) {
315: }
316:
317: public void popupMenuWillBecomeVisible(
318: PopupMenuEvent e) {
319: }
320:
321: public void popupMenuWillBecomeInvisible(
322: PopupMenuEvent e) {
323: SwingUtilities.invokeLater(new Runnable() {
324: public void run() {
325: if (updateResultsPending) {
326: updateLiveResults();
327: updateResultsPending = false;
328: }
329: }
330: });
331: }
332: });
333:
334: return memoryResPopupMenu;
335: }
336: }
|