View Javadoc

1   /*
2    * Copyright 2008 Eric Caspole
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
5    * file except in compliance with the License. You may obtain a copy of the License at
6    * 
7    * http://www.apache.org/licenses/LICENSE-2.0
8    * 
9    * Unless required by applicable law or agreed to in writing, software distributed under
10   * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11   * KIND, either express or implied. See the License for the specific language governing
12   * permissions and limitations under the License.
13   */
14   package net.sf.madmap;
15  
16  import java.io.*;
17  import java.util.*;
18  import java.awt.*;
19  import java.awt.event.*;
20  import javax.swing.*;
21  import javax.swing.event.*;
22  import javax.swing.filechooser.*;
23  
24  public class MainWindow extends JPanel implements ActionListener, ItemListener {
25    static private final String newline = "\n";
26    public  JTextArea   log;
27    JTabbedPane   tabbedPane;
28    JFileChooser  fc;
29    JFileChooser  saveChooser;
30    JProgressBar  pb;
31    JLabel        pbl;
32    JProgressBar  mpb;
33    JLabel        mpbl;
34    JMenuItem     newWindowItem;
35    JMenuItem     openItem;
36    JMenuItem     saveItem;
37    JMenuItem     quitItem;
38    JMenuItem     classSizeItem;
39    JMenuItem     memberNamesItem;
40    JMenuItem     verboseItem;
41    JMenuItem     helpItem;
42    JFrame        frame;
43    Madmap        document = null;
44  
45    ILogger	_logger = (ILogger)(MadmapMain.appContext()).getBean("logger");
46    IResources	_resources = (IResources)(MadmapMain.appContext()).getBean("resources");
47    
48    public static File getCWD(){
49      return new File(System.getProperty("user.dir"));
50    }
51  
52    public JMenuBar createMenuBar() {
53      JMenuBar  menuBar;
54      JMenu     menu;
55      
56      menuBar = new JMenuBar();
57  
58      menu = new JMenu(_resources.getString("fileMenu"));
59      menuBar.add(menu);
60  
61      newWindowItem = new JMenuItem(_resources.getString("newItem"));
62      newWindowItem.getAccessibleContext().setAccessibleDescription(_resources.getString("newDescription"));
63      menu.add(newWindowItem);
64      newWindowItem.addActionListener(this);
65  
66      openItem = new JMenuItem(_resources.getString("openItem"));
67      openItem.getAccessibleContext().setAccessibleDescription(_resources.getString("openDescription"));
68      menu.add(openItem);
69      openItem.addActionListener(this);
70  
71      saveItem = new JMenuItem(_resources.getString("saveItem"));
72      saveItem.getAccessibleContext().setAccessibleDescription(_resources.getString("saveDescription"));
73      menu.add(saveItem);
74      saveItem.addActionListener(this);
75  
76      quitItem = new JMenuItem(_resources.getString("quitItem"));
77      quitItem.getAccessibleContext().setAccessibleDescription(_resources.getString("quitDescription"));
78      menu.add(quitItem);
79      quitItem.addActionListener(this);
80      
81      menu = new JMenu(_resources.getString("helpMenu"));
82      menuBar.add(menu);
83      
84      //classSizeItem = new JMenuItem(_resources.getString("classSizeItem"));
85      //classSizeItem.getAccessibleContext().setAccessibleDescription(_resources.getString("helpDescription"));
86      //menu.add(classSizeItem);
87      //classSizeItem.addActionListener(this);
88  
89      memberNamesItem = new JCheckBoxMenuItem(_resources.getString("memberNamesItem"));
90      //classSizeItem.getAccessibleContext().setAccessibleDescription(_resources.getString("helpDescription"));
91      menu.add(memberNamesItem);
92      memberNamesItem.addItemListener(this);
93      memberNamesItem.setSelected(MadmapMain.getSaveMemberNames());
94  
95      verboseItem = new JCheckBoxMenuItem(_resources.getString("verboseItem"));
96      //verboseItem.getAccessibleContext().setAccessibleDescription(_resources.getString("helpDescription"));
97      menu.add(verboseItem);
98      //verboseItem.addActionListener(this);
99      verboseItem.addItemListener(this);
100     verboseItem.setSelected(MadmapMain.verbose());
101 
102     helpItem = new JMenuItem(_resources.getString("helpItem"));
103     helpItem.getAccessibleContext().setAccessibleDescription(_resources.getString("helpDescription"));
104     menu.add(helpItem);
105     helpItem.addActionListener(this);
106 
107     return menuBar;
108   }
109   
110   
111   public MainWindow(JFrame theFrame) {
112     super(new BorderLayout());
113     frame = theFrame;
114 
115     //Create the log first, because the action listeners
116     //need to refer to it.
117     log = new JTextArea();
118     log.setMargin(new Insets(5,5,5,5));
119     log.setEditable(false);
120     
121     //Create the progress bar
122     pb = new JProgressBar(0,100);
123     pb.setStringPainted(true);
124     pbl = new JLabel( "Ready. " );
125 
126     //Create the progress bar for the memory
127     mpb = new JProgressBar(0,100);
128     mpb.setStringPainted(true);
129     mpbl = new JLabel( "Heap used: " );
130 
131     mpb.setMinimum(0);
132     mpb.setMaximum(100);
133     mpb.setValue(0);
134     
135     fc = new JFileChooser(getCWD());
136     saveChooser = new JFileChooser(getCWD());
137 
138     JPanel buttonPanel = new JPanel();
139     buttonPanel.add(pbl);
140     buttonPanel.add(pb);
141     buttonPanel.add(mpbl);
142     buttonPanel.add(mpb);
143 
144     tabbedPane = new JTabbedPane();
145     
146     JComponent panel1 = makeLogPanel();
147     panel1.setPreferredSize(new Dimension(600, 200));
148     tabbedPane.addTab("Report", null, panel1,
149             "Progress and diagnostic messages. You can save the report by the Save Button");
150 
151     add(buttonPanel, BorderLayout.PAGE_END);
152     add(tabbedPane, BorderLayout.CENTER);
153   }
154 
155   protected JComponent makeTextPanel(String text) {
156     JPanel panel = new JPanel(false);
157     JLabel filler = new JLabel(text);
158     filler.setHorizontalAlignment(JLabel.CENTER);
159     panel.setLayout(new GridLayout(1, 1));
160     panel.add(filler);
161     return panel;
162   }
163 
164   protected JComponent makeLogPanel() {
165     JPanel panel = new JPanel(false);
166     JScrollPane logScrollPane = new JScrollPane(log);
167     panel.setLayout(new GridLayout(1, 1));
168     panel.add(logScrollPane);
169     return panel;
170   }
171 
172   public void addLiveHeapTab( java.util.List<HprofClassElement> liveHeap, long liveSize ) {
173     JPanel panel2 = new JPanel(false);
174     JTable table = new JTable(new LiveHeapTableModel(liveHeap, liveSize));
175     JScrollPane scrollpane = new JScrollPane(table);
176     panel2.setLayout(new GridLayout(1, 1));
177     panel2.add(scrollpane);
178     tabbedPane.addTab("Live Heap", null, panel2,
179             "Display live heap table with size and count");
180   }
181     
182   public void addRetainedByClassTab( Madmap m, ArrayList liveHeap, long liveSize, String title ) {
183     JPanel panel = new JPanel(false);
184     JTable table = new JTable(new CumulativeRetainedHeapTableModel(m, liveHeap, liveSize));
185     JScrollPane scrollpane = new JScrollPane(table);
186     panel.setLayout(new GridLayout(1, 1));
187     panel.add(scrollpane);
188     tabbedPane.addTab(new String("Ret by Class: " + title), null, panel,
189             "Display classes retaining the most cumulative size when roots sorted by " + title);
190   }
191 
192   public void addRetainedHeapTab( Madmap m, ArrayList liveHeap, long liveSize, String title ) {
193     JPanel panel2 = new JPanel(false);
194     JTextArea retLog = new JTextArea();
195     JTable table = new JTable(new RetainedHeapTableModel(m, liveHeap, liveSize, retLog));
196     
197     table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
198     table.getSelectionModel().addListSelectionListener(new RowListener(table));      
199     
200     JScrollPane scrollpane = new JScrollPane(table);
201     panel2.setLayout(new GridLayout(2, 0));
202     panel2.add(scrollpane, BorderLayout.PAGE_START);
203     
204     retLog.setMargin(new Insets(5,5,5,5));
205     retLog.setEditable(false);
206     JScrollPane retScrollPane = new JScrollPane(retLog);
207     panel2.add(retScrollPane, BorderLayout.PAGE_END);
208     
209     retLog.setText("Click on a row to see the allocation site.");
210       tabbedPane.addTab(new String( "Ret: " + title ), null, panel2,
211               "Display objects retaining the most size when roots sorted by " + title);
212   }
213     
214   private void outputSelection(JTable  table) {        
215       int selectedRow[] = table.getSelectedRows();
216       
217       assert selectedRow.length == 1 : "Should set selection model to single";
218       
219       JTextArea retLog = ((RetainedHeapTableModel)table.getModel()).getLog();
220       java.util.List stk = ((RetainedHeapTableModel)table.getModel()).getStack( selectedRow[0] );
221       
222       retLog.setText( "" );
223       retLog.setText( "Allocation site:\n" );
224       if ( stk != null ) {
225         for (int i = 0; i < stk.size(); i++ ) {
226           String output = new String( "  " + ((String) stk.get(i)) + "\n" );
227           retLog.append(output);
228         }
229       } else {
230           String output = new String( "  <no stack trace available>" + "\n" );
231           retLog.append(output);
232       }
233 
234       retLog.append("\n");
235       
236       String summary = ((RetainedHeapTableModel)table.getModel()).childrenSummary( selectedRow[0] );
237       if ( summary != null ) {
238           retLog.append(summary);
239       } else {
240           String output = new String( "  <no member data available>" + "\n" );
241           retLog.append(output);
242       }
243       
244       retLog.updateUI();
245       updateMemoryProgressBar();
246   }
247 
248   private class RowListener implements ListSelectionListener {
249       JTable  _parent;
250       public RowListener( JTable t ) {
251         _parent = t;
252       }
253       public void valueChanged(ListSelectionEvent event) {
254           if (event.getValueIsAdjusting()) {
255               return;
256           }
257           outputSelection(_parent);
258       }
259   }
260 
261 
262   public void addFinalizerHeapTab( java.util.List<HprofClassElement> finalizableHeap ) {
263     JPanel panel2 = new JPanel(false);
264     JTable table = new JTable(new FinalizerTableModel(finalizableHeap));
265     JScrollPane scrollpane = new JScrollPane(table);
266     panel2.setLayout(new GridLayout(1, 1));
267     panel2.add(scrollpane);
268     tabbedPane.addTab("Finalizable Objects", null, panel2,
269               "Display finalizable objects table with size and count");
270   }
271 
272   public void addThreadsTab( TreeSet threads ) {
273     JPanel panel2 = new JPanel(false);
274     JTable table = new JTable(new ThreadTableModel(threads));
275     JScrollPane scrollpane = new JScrollPane(table);
276     panel2.setLayout(new GridLayout(1, 1));
277     panel2.add(scrollpane);
278     tabbedPane.addTab("Threads", null, panel2,
279               "Display threads appearing in the profile. Not all the threads may be live at the time the heap dump was written.");
280   }
281 
282     public void itemStateChanged(ItemEvent e) {
283       if (e.getSource() == verboseItem) {
284         boolean curr = verboseItem.isSelected();
285         //log.append("Verbose: was " + !curr + "." + newline);
286         MadmapMain.setVerbose(curr);
287         //log.append("Verbose: now " + MadmapMain.verbose() + "." + newline);
288       } else if (e.getSource() == memberNamesItem) {
289         boolean curr = memberNamesItem.isSelected();
290         MadmapMain.setSaveMemberNames(curr);
291       }
292     }
293 
294   public void actionPerformed(ActionEvent e) {
295 	  if (e.getSource() == openItem) {
296 		  if (document == null) {
297 			  int returnVal = fc.showOpenDialog(MainWindow.this);
298 			  if (returnVal == JFileChooser.APPROVE_OPTION) {
299 				  File file = fc.getSelectedFile();
300 				  log.append("Opening: " + file.getName() + "." + newline);
301 				  frame.setTitle( "Madmap: " + file.getName() );
302 				  (new Thread( document = new Madmap(file, this))).start();
303 			  }
304 			  log.setCaretPosition(log.getDocument().getLength());
305 		  } else {
306 			  // If there is already a file open in the current window, 
307 			  // open the chosen document in a new window 
308 			  int returnVal = fc.showOpenDialog(MainWindow.this);
309 			  if (returnVal == JFileChooser.APPROVE_OPTION) {
310 				  File file = fc.getSelectedFile();
311 				  JFrame frame = new JFrame("Madmap");
312 				  frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
313 				  newContentPane = new MainWindow(frame);
314 				  newContentPane.setOpaque(true); //content panes must be opaque
315 				  frame.setContentPane(newContentPane);
316 				  frame.setJMenuBar(newContentPane.createMenuBar());
317 				  frame.pack();
318 				  frame.setVisible(true);
319 				  frame.setTitle( "Madmap: " + file.getName() );
320 				  (new Thread( document = new Madmap(file, newContentPane))).start();
321 			  }
322 		  }
323     } else if (e.getSource() == newWindowItem) {
324       init();
325     } else if (e.getSource() == saveItem) {
326       int returnVal = saveChooser.showSaveDialog(MainWindow.this);
327       if (returnVal == JFileChooser.APPROVE_OPTION) {
328         File file = saveChooser.getSelectedFile();
329         log.append("Saving: " + file.getName() + "." + newline);            
330         _logger.saveConsoleLog( this, file );
331       } else {
332         log.append("Save command cancelled by user." + newline);
333       }
334       log.setCaretPosition(log.getDocument().getLength());
335     } else if (e.getSource() == helpItem) {
336       // get help text from resource bundle
337       log.append( _resources.getString("helpText") );
338       log.append( _resources.getString("usageStrs") );
339     } else if (e.getSource() == saveItem) {
340     } else if (e.getSource() == quitItem) {
341       System.err.println("goodbye!");
342       System.exit(0);
343     }
344   }
345 
346   static MainWindow newContentPane = null;
347   
348   public static MainWindow getToolUI() { return newContentPane; }
349   
350 
351   private static void createAndShowGUI() {
352     JFrame frame = new JFrame("Madmap");
353     frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
354 
355     newContentPane = new MainWindow(frame);
356     newContentPane.setOpaque(true); //content panes must be opaque
357     frame.setContentPane(newContentPane);
358 
359     frame.setJMenuBar(newContentPane.createMenuBar());
360 
361     //Display the window.
362     frame.pack();
363     frame.setVisible(true);
364   }
365 
366   public static void init() {
367     javax.swing.SwingUtilities.invokeLater(new Runnable() {
368         public void run() {
369             createAndShowGUI();
370             MadmapMain.guiNotify();
371         }
372     });
373   }
374     
375   public JProgressBar getProgressBar() { 
376     return pb;
377   }
378   
379   public JLabel getLabelForProgressBar() { 
380     return pbl;
381   }
382   
383   public void updateMemoryProgressBar() {
384 	  long total = Runtime.getRuntime().totalMemory();
385 	  long free = Runtime.getRuntime().freeMemory();
386 	  int usedPct = (int)( (double)(total - free)/((double)total) * (double)100.0 );
387 	  mpb.setValue(usedPct);
388   }
389 }
390