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.cpu;
042:
043: import org.netbeans.lib.profiler.TargetAppRunner;
044: import org.netbeans.lib.profiler.global.CommonConstants;
045: import org.netbeans.lib.profiler.global.ProfilingSessionStatus;
046: import org.netbeans.lib.profiler.results.cpu.CPUResultsSnapshot;
047: import org.netbeans.lib.profiler.results.cpu.FlatProfileContainer;
048: import org.netbeans.lib.profiler.results.cpu.FlatProfileProvider;
049: import org.netbeans.lib.profiler.ui.LiveResultsPanel;
050: import org.netbeans.lib.profiler.ui.UIUtils;
051: import org.netbeans.lib.profiler.ui.components.FilterComponent;
052: import java.awt.Dimension;
053: import java.awt.image.BufferedImage;
054: import javax.swing.JPopupMenu;
055: import javax.swing.SwingUtilities;
056: import javax.swing.event.PopupMenuEvent;
057: import javax.swing.event.PopupMenuListener;
058:
059: /**
060: *
061: * @author Jaroslav Bachorik
062: */
063: public class LiveFlatProfileCollectorPanel extends FlatProfilePanel
064: implements LiveResultsPanel {
065: //~ Instance fields ----------------------------------------------------------------------------------------------------------
066:
067: private JPopupMenu popup;
068: private TargetAppRunner runner = null;
069: private boolean firstTime = true;
070: private boolean updateResultsInProgress = false;
071: private boolean updateResultsPending = false;
072:
073: //~ Constructors -------------------------------------------------------------------------------------------------------------
074:
075: public LiveFlatProfileCollectorPanel(TargetAppRunner runner,
076: CPUResUserActionsHandler actionsHandler,
077: CPUSelectionHandler selectionHandler) {
078: super (actionsHandler, selectionHandler);
079: // setCPUSelectionHandler(selectionHandler);
080: this .runner = runner;
081:
082: initComponents();
083: }
084:
085: //~ Methods ------------------------------------------------------------------------------------------------------------------
086:
087: /**
088: * This method is supposed to be used for displaying data in live update mode. The data is initialized using a
089: * "lightweight" flat profile container, not backed by the snapshot, that does not allow any operations listed
090: * above, i.e. switching views, obtaining reverse call graph, and going to method's source.
091: */
092: public void setDataToDisplay(final FlatProfileContainer fpc) {
093: threadId = -1;
094: flatProfileContainer = fpc;
095: collectingTwoTimeStamps = flatProfileContainer
096: .isCollectingTwoTimeStamps();
097:
098: flatProfileContainer.filterOriginalData(FilterComponent
099: .getFilterStrings(filterString), filterType,
100: valueFilterValue);
101:
102: prepareResults(firstTime);
103: firstTime = false;
104:
105: setResultsAvailable(hasData());
106:
107: // flatProfileContainer.sortBy(sortBy, sortOrder); // This will actually create the below-used percent() thing for proper timer
108: }
109:
110: public BufferedImage getViewImage(boolean onlyVisibleArea) {
111: if (onlyVisibleArea) {
112: return UIUtils.createScreenshot(jScrollPane);
113: }
114:
115: return UIUtils.createScreenshot(resTable);
116: }
117:
118: public String getViewName() {
119: return "cpu-live"; // NOI18N
120: }
121:
122: public boolean fitsVisibleArea() {
123: return !jScrollPane.getVerticalScrollBar().isEnabled();
124: }
125:
126: public void handleRemove() {
127: }
128:
129: /**
130: * Called when auto refresh is on and profiling session will finish
131: * to give the panel chance to do some cleanup before asynchrounous
132: * call to updateLiveResults() will happen.
133: *
134: * Currently it closes the context menu if open, which would otherwise
135: * block updating the results.
136: */
137: public void handleShutdown() {
138: // Profiling session will finish and context menu is opened, this would block last live results update -> menu will be closed
139: if ((popup != null) && popup.isVisible()) {
140: updateResultsPending = false; // clear the flag, updateLiveResults() will be called explicitely from outside
141: popup.setVisible(false); // close the context menu
142: }
143: }
144:
145: public boolean hasData() {
146: return (flatProfileContainer != null)
147: && (flatProfileContainer.getNRows() > 0);
148: }
149:
150: public boolean hasView() {
151: return resTable != null;
152: }
153:
154: @Override
155: public void prepareResults() {
156: super .prepareResults();
157: }
158:
159: public boolean supports(int instrumentationType) {
160: return (instrumentationType == CommonConstants.INSTR_RECURSIVE_FULL)
161: || (instrumentationType == CommonConstants.INSTR_RECURSIVE_SAMPLED);
162: }
163:
164: public void updateLiveResults() {
165: if ((popup != null) && popup.isVisible()) {
166: updateResultsPending = true;
167:
168: return;
169: }
170:
171: if (updateResultsInProgress == true) {
172: return;
173: }
174:
175: updateResultsInProgress = true;
176:
177: String selectedRowString = null;
178:
179: if (resTable != null) {
180: int selectedRowIndex = resTable.getSelectedRow();
181:
182: if (selectedRowIndex >= resTable.getRowCount()) {
183: selectedRowIndex = -1;
184: resTable.clearSelection();
185: }
186:
187: if (selectedRowIndex != -1) {
188: selectedRowString = resTable.getValueAt(
189: selectedRowIndex, 0).toString();
190: }
191: }
192:
193: FlatProfileProvider flatProvider = runner.getProfilerClient()
194: .getFlatProfileProvider();
195:
196: if (flatProvider != null) {
197: FlatProfileContainer fpc = flatProvider.createFlatProfile();
198: int retryCounter = 2;
199: boolean doRetry = false;
200:
201: do {
202: doRetry = false;
203:
204: if (fpc != null) {
205: setDataToDisplay(fpc);
206:
207: if (selectedRowString != null) {
208: resTable.selectRowByContents(selectedRowString,
209: 0, false);
210: }
211: } else {
212: doRetry = true;
213: }
214:
215: if (doRetry) {
216: try {
217: Thread.sleep(200);
218: } catch (InterruptedException e) {
219: doRetry = false;
220: }
221: }
222: } while ((--retryCounter > 0) && doRetry);
223: }
224:
225: updateResultsInProgress = false;
226: }
227:
228: protected String[] getMethodClassNameAndSig(int methodId,
229: int currentView) {
230: ProfilingSessionStatus status = runner
231: .getProfilingSessionStatus();
232: String className = status.getInstrMethodClasses()[methodId];
233:
234: if (currentView == CPUResultsSnapshot.METHOD_LEVEL_VIEW) {
235: String methodName = (status.getInstrMethodNames() != null) ? status
236: .getInstrMethodNames()[methodId]
237: : null;
238: String methodSig = (status.getInstrMethodSignatures() != null) ? status
239: .getInstrMethodSignatures()[methodId]
240: : null;
241:
242: return new String[] { className, methodName, methodSig };
243: }
244:
245: return new String[] { className, null, null };
246: }
247:
248: @Override
249: protected JPopupMenu createPopupMenu() {
250: if (popup == null) {
251: popup = super .createPopupMenu();
252: }
253:
254: popup.addPopupMenuListener(new PopupMenuListener() {
255: public void popupMenuCanceled(PopupMenuEvent e) {
256: }
257:
258: public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
259: }
260:
261: public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
262: SwingUtilities.invokeLater(new Runnable() {
263: public void run() {
264: if (updateResultsPending) {
265: updateLiveResults();
266: updateResultsPending = false;
267: }
268: }
269: });
270: }
271: });
272:
273: return popup;
274: }
275:
276: protected void obtainResults() {
277: // If a now-inapplicable setting remained from previous run, reset it
278: if ((!collectingTwoTimeStamps && (sortBy == FlatProfileContainer.SORT_BY_SECONDARY_TIME))) {
279: sortBy = FlatProfileContainer.SORT_BY_TIME;
280: }
281:
282: // Reinit bar max value here - operations necessary for correct bar representation of results
283: flatProfileContainer.filterOriginalData(FilterComponent
284: .getFilterStrings(filterString), filterType,
285: valueFilterValue);
286: flatProfileContainer.sortBy(sortBy, sortOrder); // This will actually create the below-used percent() thing for proper timer
287: }
288:
289: /**
290: * Default implementation throwing IllegalStateException, needs to be overriden by classes that do support showReverseCallGraph
291: */
292: @Override
293: protected void showReverseCallGraph(int threadId, int methodId,
294: int currentView, int sortingColumn, boolean sortingOrder) {
295: throw new IllegalStateException();
296: }
297:
298: protected boolean supportsReverseCallGraph() {
299: return false;
300: }
301:
302: protected boolean supportsSubtreeCallGraph() {
303: return false;
304: }
305:
306: void setSelectedRowString(String rowString) {
307: if (rowString != null) {
308: resTable.selectRowByContents(rowString, 0, false);
309: }
310: }
311:
312: String getSelectedRowString() {
313: String selectedRowString = null;
314:
315: if (resTable != null) {
316: int selectedRowIndex = resTable.getSelectedRow();
317:
318: if (selectedRowIndex >= resTable.getRowCount()) {
319: selectedRowIndex = -1;
320: resTable.clearSelection();
321: }
322:
323: if (selectedRowIndex != -1) {
324: selectedRowString = resTable.getValueAt(
325: selectedRowIndex, 0).toString();
326: }
327: }
328:
329: return selectedRowString;
330: }
331:
332: private void initComponents() {
333: this .setPreferredSize(new Dimension(800, 600));
334: }
335: }
|