001/* A tableau for displaying JVM information
002
003 Copyright (c) 2001-2014 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026 */
027package ptolemy.actor.gui;
028
029import java.awt.BorderLayout;
030import java.awt.event.ActionEvent;
031import java.awt.event.ActionListener;
032import java.lang.reflect.Method;
033import java.util.ArrayList;
034import java.util.Collections;
035import java.util.Enumeration;
036import java.util.Iterator;
037import java.util.Properties;
038
039import javax.swing.BoxLayout;
040import javax.swing.JButton;
041import javax.swing.JPanel;
042import javax.swing.JScrollPane;
043import javax.swing.JTextArea;
044
045import ptolemy.kernel.CompositeEntity;
046import ptolemy.kernel.util.IllegalActionException;
047import ptolemy.kernel.util.NameDuplicationException;
048import ptolemy.kernel.util.NamedObj;
049
050///////////////////////////////////////////////////////////////////
051//// JVMTableau
052
053/**
054 A tableau that displays Java Virtual Machine information such
055 as the version number and other properties.
056
057 @author Christopher Hylands
058 @version $Id$
059 @since Ptolemy II 2.0
060 @Pt.ProposedRating Red (cxh)
061 @Pt.AcceptedRating Red (cxh)
062 */
063public class JVMTableau extends Tableau {
064    /** Create a new control panel displaying the JVM properties
065     *  The tableau is itself an entity contained by the effigy
066     *  and having the specified name.  The frame is not made visible
067     *  automatically.  You must call show() to make it visible.
068     *  @param container The containing effigy.
069     *  @param name The name of this tableau within the specified effigy.
070     *  @exception IllegalActionException If the tableau is not acceptable
071     *   to the specified container.
072     *  @exception NameDuplicationException If the container already contains
073     *   an entity with the specified name.
074     */
075    public JVMTableau(PtolemyEffigy container, String name)
076            throws IllegalActionException, NameDuplicationException {
077        super(container, name);
078
079        NamedObj model = container.getModel();
080
081        JVMFrame frame = new JVMFrame((CompositeEntity) model, this);
082        setFrame(frame);
083    }
084
085    ///////////////////////////////////////////////////////////////////
086    ////                         inner classes                     ////
087
088    /** The frame that is created by an instance of JVMTableau.
089     */
090    @SuppressWarnings("serial")
091    public class JVMFrame extends PtolemyFrame {
092        /** Construct a frame to display JVM properties.
093         *  After constructing this, it is necessary
094         *  to call setVisible(true) to make the frame appear.
095         *  This is typically accomplished by calling show() on
096         *  enclosing tableau.
097         *  @param model The model to put in this frame, or null if none.
098         *  @param tableau The tableau responsible for this frame.
099         *  @exception IllegalActionException If the model rejects the
100         *   configuration attribute.
101         *  @exception NameDuplicationException If a name collision occurs.
102         */
103        public JVMFrame(final CompositeEntity model, Tableau tableau)
104                throws IllegalActionException, NameDuplicationException {
105            super(model, tableau);
106
107            JPanel component = new JPanel();
108            component.setLayout(new BoxLayout(component, BoxLayout.Y_AXIS));
109
110            // Display total memory and free memory.
111            final JTextArea memoryArea = new JTextArea("", 1, 100);
112            updateMemoryStatistics(memoryArea);
113            memoryArea.setEditable(false);
114            component.add(memoryArea);
115
116            // Button to request GC.
117            JButton GCButton = new JButton("Request Garbage Collection");
118            GCButton.addActionListener(new ActionListener() {
119                @Override
120                public void actionPerformed(ActionEvent event) {
121                    // FindBugs warns about System.gc, but it is ok
122                    System.gc();
123                    updateMemoryStatistics(memoryArea);
124                }
125            });
126            component.add(GCButton);
127
128            // Display system properties
129            String lineSeparator = System.getProperty("line.separator");
130            StringBuffer propertyBuffer = new StringBuffer();
131
132            try {
133                Properties properties = System.getProperties();
134                Enumeration propertyNamesEnumeration = properties
135                        .propertyNames();
136
137                // Sort by property name
138                ArrayList propertyNamesList = Collections
139                        .list(propertyNamesEnumeration);
140                Collections.sort(propertyNamesList);
141
142                Iterator propertyNames = propertyNamesList.iterator();
143
144                while (propertyNames.hasNext()) {
145                    String propertyName = (String) propertyNames.next();
146                    propertyBuffer.append(propertyName + " = "
147                            + properties.getProperty(propertyName)
148                            + lineSeparator);
149                }
150            } catch (java.security.AccessControlException accessControl) {
151                propertyBuffer.append("AccessControlException, probably from "
152                        + "System.getProperties():\n" + accessControl);
153            }
154
155            try {
156                // Use reflection to get the thread info so that we
157                // don't have to inciude non-UCB code in this package.
158                Class printThreadsClass = Class
159                        .forName("util.testsuite.PrintThreads");
160
161                Method allThreads = printThreadsClass.getMethod("allThreads",
162                        new Class[] { boolean.class });
163                propertyBuffer.append("\nThreads:\n" + (String) allThreads
164                        .invoke(null, new Object[] { Boolean.TRUE }));
165            } catch (Throwable throwable) {
166                // Ignore.
167            }
168
169            final JTextArea messageArea = new JTextArea(
170                    propertyBuffer.toString(), 20, 100);
171
172            messageArea.setEditable(false);
173
174            JScrollPane scrollPane = new JScrollPane(messageArea);
175            component.add(scrollPane);
176            getContentPane().add(component, BorderLayout.CENTER);
177        }
178    }
179
180    /** A factory that creates a control panel to display JVM Properties.
181     */
182    public static class Factory extends TableauFactory {
183        /** Create a factory with the given name and container.
184         *  @param container The container.
185         *  @param name The name.
186         *  @exception IllegalActionException If the container is incompatible
187         *   with this attribute.
188         *  @exception NameDuplicationException If the name coincides with
189         *   an attribute already in the container.
190         */
191        public Factory(NamedObj container, String name)
192                throws IllegalActionException, NameDuplicationException {
193            super(container, name);
194        }
195
196        ///////////////////////////////////////////////////////////////////
197        ////                         public methods                    ////
198
199        /** Create a new instance of JVMTableau in the specified
200         *  effigy. If the specified effigy is not an
201         *  instance of PtolemyEffigy, then do not create a tableau
202         *  and return null. It is the responsibility of callers of
203         *  this method to check the return value and call show().
204         *
205         *  @param effigy The model effigy.
206         *  @return A new control panel tableau if the effigy is
207         *    a PtolemyEffigy, or null otherwise.
208         *  @exception Exception If the factory should be able to create a
209         *   tableau for the effigy, but something goes wrong.
210         */
211        @Override
212        public Tableau createTableau(Effigy effigy) throws Exception {
213            if (effigy instanceof PtolemyEffigy) {
214                // First see whether the effigy already contains a tableau
215                JVMTableau tableau = (JVMTableau) effigy
216                        .getEntity("JVMTableau");
217
218                if (tableau == null) {
219                    tableau = new JVMTableau((PtolemyEffigy) effigy,
220                            "JVMTableau");
221                }
222
223                return tableau;
224            } else {
225                return null;
226            }
227        }
228    }
229
230    ///////////////////////////////////////////////////////////////////
231    ////                         private methods                   ////
232    // Update the memory statistics in textArea.
233    private void updateMemoryStatistics(JTextArea textArea) {
234        // Report memory usage statistics.
235        Runtime runtime = Runtime.getRuntime();
236        long totalMemory = runtime.totalMemory() / 1024;
237        long freeMemory = runtime.freeMemory() / 1024;
238        long maxMemory = runtime.maxMemory() / 1024;
239
240        textArea.setText("Memory: " + totalMemory + "K Free: " + freeMemory
241                + "K ("
242                + Math.round((double) freeMemory / (double) totalMemory * 100.0)
243                + "%) Max: " + maxMemory + "K ("
244                + Math.round((double) totalMemory / (double) maxMemory * 100.0)
245                + "%)");
246    }
247}