001    /**
002       ##############################################################################
003       ##                                                                          ##
004       ## EnvInfo                                                                  ##
005       ##                                                                          ##
006       ## Copyright (C) 2009  Frederic Roudaut  <frederic.roudaut@free.fr>         ##
007       ##                                                                          ##
008       ## This class is an adaption of the one done by Nicolas Richasse for his    ##
009       ## Java Iperf frontend.                                                     ##
010       ##                                                                          ##
011       ##                                                                          ##
012       ## This program is free software: you can redistribute it and/or modify     ##
013       ## it under the terms of the GNU General Public License as published by     ##
014       ## the Free Software Foundation, either version 3 of the License, or        ##
015       ## (at your option) any later version.                                      ##
016       ##                                                                          ##
017       ## This program is distributed in the hope that it will be useful,          ##
018       ## but WITHOUT ANY WARRANTY; without even the implied warranty of           ##
019       ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            ##
020       ## GNU General Public License for more details.                             ##
021       ##                                                                          ##
022       ## You should have received a copy of the GNU General Public License        ##
023       ## along with this program.  If not, see <http://www.gnu.org/licenses/>.    ##
024       ##                                                                          ##
025       ##                                                                          ##
026       ##############################################################################
027    **/
028    
029    package com.envInfo;
030    
031    import java.awt.BorderLayout;
032    import java.awt.Color;
033    import java.awt.GridLayout;
034    import java.text.SimpleDateFormat;
035    import java.util.Date;
036    import java.util.HashMap;
037    
038    import javax.swing.JLabel;
039    import javax.swing.JPanel;
040    
041    import org.jfree.chart.ChartPanel;
042    import org.jfree.chart.JFreeChart;
043    import org.jfree.chart.axis.AxisLocation;
044    import org.jfree.chart.axis.NumberAxis;
045    import org.jfree.chart.axis.ValueAxis;
046    import org.jfree.chart.plot.CombinedDomainXYPlot;
047    import org.jfree.chart.plot.XYPlot;
048    import org.jfree.chart.renderer.xy.XYItemRenderer;
049    import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
050    import org.jfree.data.xy.XYSeries;
051    import org.jfree.data.xy.XYSeriesCollection;
052    
053    
054    /**
055     * Class used to draw the JVM Memory status charts.
056     * <br/><br/>
057     * This class is an adaption of the one done by Nicolas Richasse for his   
058     * Java Iperf frontend.
059     *
060     **/
061    public class MemoryChartPanel extends AbstractChartPanel
062        implements Runnable
063    {
064    
065             private static final long serialVersionUID = 1L;
066             
067        /**
068         * Class representing a single series of Memory data.
069         * 
070         **/
071        private class SeriesData
072        {
073            public String   seriesId;
074            public String   memoryLegend;
075            public JLabel   seriesLabel;
076            public XYSeries memorySeries;
077            public Color    seriesColor;
078            public String   printfMemoryValueExpression;
079    
080            /**
081             * Constructor.
082             * @param seriesId ID.
083             * @param memoryLegend Memory Legend.
084             * @param seriesColor Color for the chart.
085             * @param printfMemoryValueExpression Content to print under the Chart.
086             *
087             **/
088            public SeriesData (String seriesId, String memoryLegend, Color seriesColor, 
089                               String printfMemoryValueExpression)
090            {
091                this.seriesId = seriesId;
092                this.memoryLegend = memoryLegend;
093                this.memorySeries = new XYSeries(memoryLegend);
094                this.seriesLabel = new JLabel(memoryLegend);
095                this.seriesColor = seriesColor;
096                this.printfMemoryValueExpression = printfMemoryValueExpression;
097                seriesLabel.setForeground(seriesColor);
098            }
099        }
100    
101        private int proportion;
102        private CombinedDomainXYPlot graphSet;
103        private XYItemRenderer memoryRenderer;
104        private XYSeriesCollection memoryCollection;
105        private JPanel panelTextStats = new JPanel(new GridLayout(0, 4));
106        private JLabel labelDate = new JLabel(" ");
107        private double delayInSeconds;
108        private SimpleDateFormat sdf = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss");
109        private HashMap<String, SeriesData>   seriesData = new HashMap<String, SeriesData>();
110        private Thread timeThread = null;
111        private Color backgroundColor, foregroundColor, gridColor;
112        private String memoryUnit;
113        private double timeWindow;
114            
115        /**
116         * Constructor for a set of Memory Charts (ie a set of memory series).
117         * @param title Title of the Memory Charts set. 
118         * @param memoryUnit Memory Unit.
119         * @param timeAxisLabel Time Axis Label (X axis).
120         * @param memoryValueAxisLabel Memory Value Axis Label (Y Axis).
121         * @param delayInSeconds Delay between the date printing above the charts set.
122         * @param timeWindow Time Windows for the charts.
123         * @param backgroundColor BackgroundColor.
124         * @param foregroundColor ForegroundColor.
125         * @param gridColor GridColor.
126         *
127         **/
128        public MemoryChartPanel(String title, String memoryUnit, String timeAxisLabel, 
129                                String memoryValueAxisLabel, double delayInSeconds, double timeWindow, 
130                                Color backgroundColor, Color foregroundColor, Color gridColor)
131        {
132            this.delayInSeconds = delayInSeconds;
133            this.proportion = 1;
134            this.backgroundColor = backgroundColor;
135            this.foregroundColor = foregroundColor;
136            this.gridColor = gridColor;
137    
138            reconfigure(title, memoryUnit, timeAxisLabel, memoryValueAxisLabel, timeWindow);
139        }
140    
141        /**
142         *
143         * Start a Time Thread.
144         *
145         */    
146        public void start()
147        {
148            if (timeThread == null)
149                {
150                    this.timeThread = new Thread(this);
151                    timeThread.start();
152                }
153        }
154    
155        /**
156         *
157         * Check if a Memory Data Series Exists.
158         * @param seriesId A serie ID. 
159         * @return true if the serie exists, false otherwise.
160         *
161         */
162        private boolean seriesExists(String seriesId)
163        {
164            if (seriesData.keySet().contains(seriesId))
165                {
166                    return true;
167                }
168            else
169                {
170                    return false;
171                }
172        }
173    
174        /**
175         *
176         * Add a Memory Data Series.
177         * @param seriesId A serie ID. 
178         * @param seriesLegend the Serie Legend
179         * @param seriesColor a color for the associated chart.
180         *
181         */
182        public void maybeAddNewSeries(String seriesId, String seriesLegend, Color seriesColor)
183        {
184            maybeAddNewSeries(seriesId, seriesLegend, seriesColor, "%4.2f");
185        }
186    
187        /**
188         *
189         * Add a Memory Data Series.
190         * @param seriesId A serie ID. 
191         * @param seriesLegend the Serie Legend
192         * @param seriesColor a color for the associated chart.
193         * @param printfMemoryValueExpression Content to print under the Charts.
194         *
195         */
196        public synchronized void maybeAddNewSeries(String seriesId, String seriesLegend, 
197                                                   Color seriesColor, String printfMemoryValueExpression)
198        {
199            if (!seriesExists(seriesId))
200                {
201                    SeriesData data = new SeriesData(seriesId, seriesLegend, seriesColor, printfMemoryValueExpression);
202                    seriesData.put(seriesId, data);
203                            
204                    memoryCollection.addSeries(data.memorySeries);
205                    memoryRenderer.setSeriesPaint(memoryCollection.getSeriesCount()-1, data.seriesColor);
206    
207                    panelTextStats.add(data.seriesLabel);
208                }
209        }
210    
211        /**
212         *
213         * Reconfigure a Memory Data Charts set.
214         * @param title Title of the Memory Charts set. 
215         * @param memoryUnit Memory Unit.
216         * @param timeAxisLabel Time Axis Label.
217         * @param memoryValueAxisLabel Memory Value Axis Label.
218         * @param timeWindow Time windows for the charts.
219         *
220         */
221        public void reconfigure(String title, String memoryUnit, String timeAxisLabel, String memoryValueAxisLabel, 
222                                double timeWindow)
223        {
224            this.memoryUnit = memoryUnit;
225            this.timeWindow = timeWindow;
226                    
227            // reset the content pane
228            this.removeAll();
229            panelTextStats.removeAll();
230            SeriesColorGenerator.reset();
231    
232            seriesData.clear();
233    
234            // creation of the chart group
235            graphSet = new CombinedDomainXYPlot(new NumberAxis(timeAxisLabel));
236            // space between charts
237            graphSet.setGap(10.0);
238            // creation of the jFreeChart
239            jFreeChart = new JFreeChart(null, JFreeChart.DEFAULT_TITLE_FONT, graphSet, false);
240            jFreeChart.setBackgroundPaint(backgroundColor);
241            if (title != null)
242                {
243                    jFreeChart.setTitle(title);
244                    jFreeChart.getTitle().setPaint(foregroundColor);
245                }
246            // creation of the chart panel
247            chartPanel = new ChartPanel(jFreeChart);
248            chartPanel.setBackground(backgroundColor);
249            // creation of the series set
250            memoryCollection = new XYSeriesCollection();
251            // creation of the renderer
252            memoryRenderer = new XYLineAndShapeRenderer();
253            // set the UI presentation
254            NumberAxis rangeAxis = new NumberAxis(memoryValueAxisLabel);
255            rangeAxis.setLabelPaint(foregroundColor);
256    
257            // creation of the memory plot
258            XYPlot memoryPlot = new XYPlot(memoryCollection, null, rangeAxis, memoryRenderer);
259            memoryPlot.setRangeAxisLocation(AxisLocation.BOTTOM_OR_LEFT);
260            memoryPlot.setDomainCrosshairVisible(false);
261            memoryPlot.setRangeCrosshairVisible(false);
262            memoryPlot.setBackgroundPaint(backgroundColor);
263            memoryPlot.setDomainGridlinePaint(gridColor);
264            memoryPlot.setRangeGridlinePaint(gridColor);
265    
266            // add the plot
267            graphSet.add(memoryPlot, proportion);
268    
269            // set up the domain axis
270            ValueAxis axis = memoryPlot.getDomainAxis();
271            if (timeAxisLabel != null)
272                {
273                    axis.setTickLabelPaint(foregroundColor);
274                    axis.setLabel(timeAxisLabel);
275                    axis.setLabelPaint(foregroundColor);
276                }
277            else
278                {
279                    axis.setVisible(false);
280                }
281            axis.setAutoRange(true);
282            axis.setFixedAutoRange((int)Math.min(timeWindow, 60));
283    
284            // set up the range axis
285            axis = memoryPlot.getRangeAxis();
286            axis.setTickLabelPaint(foregroundColor);
287    
288            // set up the hour&date label presentation
289            labelDate.setHorizontalAlignment(JLabel.RIGHT);
290            labelDate.setForeground(foregroundColor);
291    
292            panelTextStats.setBackground(backgroundColor);
293    
294            this.add(labelDate, BorderLayout.NORTH);
295            this.add(chartPanel, BorderLayout.CENTER);
296            this.add(panelTextStats, BorderLayout.SOUTH);
297    
298            this.setBackground(backgroundColor);
299        }
300    
301        /**
302         *
303         * Add a new measurement to an existing memory data serie.
304         * @param seriesId the sery ID.
305         * @param measurement the measurement to add.
306         *
307         */    
308        public void addSeriesMemoryMeasurement(String seriesId, MemoryMeasurement measurement)
309        {
310            SeriesData data = seriesData.get(seriesId);
311            data.memorySeries.add(measurement.getEndTime(), measurement.getValue());
312            data.seriesLabel.setText(String.format("<html><b>%s</b> " + data.printfMemoryValueExpression + "%s </html>", 
313                                                   data.memoryLegend, measurement.getValue(),
314                                                   " " + measurement.getUnits() +"&nbsp;&nbsp;"));
315        }
316        
317        /**
318         *
319         * Start a Thread to update the date.
320         *
321         */    
322        public void run()
323        {
324            while (true)
325                {
326                    try
327                        {
328                            Date d = new Date();
329                            labelDate.setText(sdf.format(d));
330                            Thread.sleep((int) (delayInSeconds * 1000));
331                        }
332                    catch (Exception ex)
333                        {
334                        }
335                }
336        }
337    }