Project Report: fawkez

Packagesummary org.jcoderz.phoenix.chart2d

org.jcoderz.phoenix.chart2d.Chart2DHandlerImpl

LineHitsNoteSource
1  /*
2   * $Id: Chart2DHandlerImpl.java 1011 2008-06-16 17:57:36Z amandel $
3   *
4   * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5   *
6   * Redistribution and use in source and binary forms, with or without
7   * modification, are permitted provided that the following conditions are
8   * met:
9   *
10   *    * Redistributions of source code must retain the above copyright
11   *      notice, this list of conditions and the following disclaimer.
12   *    * Redistributions in binary form must reproduce the above
13   *      copyright notice, this list of conditions and the following
14   *      disclaimer in the documentation and/or other materials
15   *      provided with the distribution.
16   *    * Neither the name of the jCoderZ.org Project nor the names of
17   *      its contributors may be used to endorse or promote products
18   *      derived from this software without specific prior written
19   *      permission.
20   *
21   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32   */
33  package org.jcoderz.phoenix.chart2d;
34  
35  
36  import java.awt.AlphaComposite;
37  import java.awt.Color;
38  import java.awt.Dimension;
39  import java.io.BufferedReader;
40  import java.io.BufferedWriter;
41  import java.io.File;
42  import java.io.FileInputStream;
43  import java.io.FileReader;
44  import java.io.FileWriter;
45  import java.io.FilenameFilter;
46  import java.io.IOException;
47  import java.lang.reflect.Field;
48  import java.lang.reflect.Method;
49  import java.util.ArrayList;
50  import java.util.Arrays;
51  import java.util.Collection;
52  import java.util.HashMap;
53  import java.util.Iterator;
54  import java.util.List;
55  import java.util.Map;
56  import java.util.Set;
57  import java.util.TreeSet;
58  import java.util.Map.Entry;
59 (1)import java.util.logging.Handler;
60  import java.util.logging.Level;
61  import java.util.logging.Logger;
62  import java.util.regex.Matcher;
63  import java.util.regex.Pattern;
64  
65  import javax.xml.parsers.DocumentBuilder;
66  import javax.xml.parsers.DocumentBuilderFactory;
67  import javax.xml.parsers.ParserConfigurationException;
68  
69  import net.sourceforge.chart2d.Chart2D;
70  import net.sourceforge.chart2d.Chart2DProperties;
71  import net.sourceforge.chart2d.Dataset;
72  import net.sourceforge.chart2d.GraphChart2D;
73  import net.sourceforge.chart2d.GraphChart2DProperties;
74  import net.sourceforge.chart2d.GraphProperties;
75  import net.sourceforge.chart2d.LBChart2D;
76  import net.sourceforge.chart2d.LLChart2D;
77  import net.sourceforge.chart2d.LegendProperties;
78  import net.sourceforge.chart2d.MultiColorsProperties;
79  import net.sourceforge.chart2d.Object2DProperties;
80  import net.sourceforge.chart2d.PieChart2D;
81  import net.sourceforge.chart2d.PieChart2DProperties;
82  import net.sourceforge.chart2d.WarningRegionProperties;
83  
84  import org.apache.xpath.XPathAPI;
85  import org.apache.xpath.objects.XObject;
86  import org.jcoderz.commons.types.Date;
87  import org.jcoderz.commons.util.Constants;
88  import org.jcoderz.commons.util.IoUtil;
89  import org.jcoderz.commons.util.LoggingProxy;
90  import org.jcoderz.commons.util.LoggingUtils;
91  import org.w3c.dom.Document;
92  import org.w3c.dom.Node;
93  import org.w3c.dom.traversal.NodeIterator;
94  import org.xml.sax.Attributes;
95  import org.xml.sax.InputSource;
96  import org.xml.sax.SAXException;
97  
98  
99  /**
100   * Generated implementation for documents valid against
101   * the chart2d dtd.
102   * 
103   * Also give the ability to collect input data from a certain set of 
104   * xml files.
105   * The format is currently quite tailored to the needs of a cruise 
106   * control log file analysis. This might be opened up if further
107   * requirements come up.
108   * 
109   *  The format is given by the chart2d api. Look there 
110   *  http://chart2d.sourceforge.net/ for details.
111   *  
112   *  The special data collection is always started with a ! do 
113   *  mark the special format. 
114   *  
115   *  For the <code>AxisLabelText</code> there are 2 additional
116   *  attributes:
117   *   
118   *  <code>count</code>: The number of labels on the x-Axis.
119   *  If the dataset contains <code>count * 2</code> or more
120   *  entries, n (= <i>number of datasets</i> / count) are put
121   *  together in one label. 
122   *    
123   *  <code>max</code>: The maximum number of datasets that are
124   *  allowed to be put together under one label. If the number of 
125   *  available datasets is more than <code>count * max</code> the
126   *  elder datasets are discarded.
127   *  
128   *  The element of <code>AxisLabelText</code> can contain a regular
129   *  expression, that is used to search for the logfiles used as 
130   *  input datasets. The search is started recursive from the 
131   *  given <i>context path</i>. Path separators must be given
132   *  as '/' characters if needed. The first group on the regular
133   *  expression is used as label for the dataset. An example could
134   *  be <code>!.*log.*BUILD_([0-9]*)\.xml</code> with would use the
135   *  number after the <code>BUILD_</code> as labeltext.
136   *  
137   *  The element of <code>LegendLabelsTexts</code> is the z-Axis.
138   *  If the element starts with a <code>!</code> character the
139   *  rest must be a xpath expression returning a node set. Each
140   *  node of the nodeset will build a element (and label) 
141   *  on the z-Axis. A valid expression could be:
142   *  <code>!/cruisecontrol/findingsummary/servicelevelxml/service/@name</code>.
143   *  
144   *  The element of <code>Data</code> could also be an xpath
145   *  expression. The handler then iterates over this for each 
146   *  file (dataset) and each value available for the z-Axis. The string
147   *  $z is replaced by the current z-Axis value before the xpath 
148   *  expression is evaluated against the current file (dataset). The
149   *  handler takes care for the <code>Set</code>, <code>Category</code>,
150   *  <code>Data</code> element nesting. A valid expression could be:
151 (2) *  <code>!/cruisecontrol/findingsummary/servicelevelxml/service[@name = '$z']/@quality</code>.
152   *  The expression should evaluate to a node that can be parsed as a 
153   *  float using <code>Float.parseFloat</code> or to a ant timestring
154   *  matching the regular pattern 
155   *  <code>"(([0-9]+) minutes? )?([0-9]+) seconds?"</code> the timestring
156   *  will be converted into the number of seconds. Other formats might be
157   *  added.
158   * 
159   * @author Andreas Mandel
160   * @author Netbeans Code generator.
161   */
162  public class Chart2DHandlerImpl implements Chart2DHandler
163  {
164     private static final int DEFAULT_WIDTH = 768;
165     private static final int DEFAULT_HEIGHT = 1024;
166     private static final int DEBUG_ARG_NUM = 3;
167  
168     private static final String TIME_PATTERN
169         = "(([0-9]+) minutes? )?([0-9]+) seconds?";
170     private static final int TIME_PATTERN_MINUTES_GROUP = 2;
171     private static final int TIME_PATTERN_SECONDS_GROUP = 3;
1720    private static boolean sDebug = false;
1730    private static boolean sMultible = false;
174     private Object2DProperties mObject2DProperties;
175     private Chart2DProperties mChart2DProperties;
176     private GraphChart2DProperties mGraphChart2DProperties;
177     private List mCurrentLabelText;
178     private PieChart2DProperties mPieChart2DProperties;
179     private LegendProperties mLegendProperties;
1800    private final List mDataSets = new ArrayList();
1810    private final List mMultiColorsProperties = new ArrayList();
1820    private final List mGraphProperties = new ArrayList();
1830    private final List mWarningRegionProperties = new ArrayList();
1840    private int mWidth = DEFAULT_WIDTH;
1850    private int mHeight = DEFAULT_HEIGHT;
186     private String mFilename;
187     private String mType;
188     private List mCurrentDataSet;
189     private List mCurrentSet;
190     private List mCurrentCategory;
191     private MultiColorsProperties mCurrentMultiColorsProperties;
192     private List mCurrentMultiColors;
193     private String mChartType;
194     private List mCurrentLegendLabelsTexts;
195     private boolean mDoConvertToStacked;
196     private final File mDataRepository;
1970    private final Set mFilePatterns = new TreeSet();
1980    private final List mXaxis = new ArrayList();
1990    private int mXaxisModulus = 1;
2000    private final Map mXpathCache = new HashMap();
201     private DocumentBuilder mDocumentBuilder;
202  
203     /**
204      * A new handler for cart2d files. 
205      * The repository directory is used to read input xml files and to
206      * read and store a cache file.
207      * 
208      * @param dataRepository the directory to the logfiles,
209      *           can be null.
210      */
211     public Chart2DHandlerImpl (File dataRepository)
2120    {
2130        mDataRepository = dataRepository;
2140        if (mDataRepository != null)
215         {
2160            collectPatterns(mDataRepository, null);
2170            if (mFilePatterns.isEmpty())
218             {
2190                throw new RuntimeException("No files found in repository path "
220                         + mDataRepository + ".");
221             }
2220            readCache();
223         }
2240    }
225  
226  
227     /**
228      * Commandline interface to this handler.
229      * Parameters should be 
230      * &lt;input file or dir> [context path] [debug]
231      * 
232      * @param args args the commandline aruments.
233      * @throws IOException if a io problem occures.
234      */
235 (3)   public static void main (String[] args) throws IOException
236     {
237        File[] in;
238        File para;
239  
2400       if ((args.length < 1) || (args.length > DEBUG_ARG_NUM))
241        {
242           String msg;
243  
2440          msg = "Usage: java " + Chart2DHandlerImpl.class.getName()
245                 + " <input file or directory> [context path] [debug]";
2460          log(msg);
2470          throw new IllegalArgumentException(msg);
248        }
249  
2500       if (args.length == DEBUG_ARG_NUM)
251        {
2520          sDebug = true;
253        }
254        
2550       File dataRepository = null;
256        
2570       if (args.length > 1)
258        {
2590(4)          if (args[1].equals("debug"))
260            {
2610               sDebug = true;
262            }
263            else
264            {
2650               dataRepository = new File(args[1]);
266            }
267        }
268        
2690       if (sDebug)
270        {
2710           LoggingUtils.setGlobalHandlerLogLevel(Level.ALL);
2720           Logger.getLogger("org.jcoderz.phoenix.chart2d").setLevel(Level.ALL);
2730           Logger.getLogger("").setLevel(Level.ALL);
274        }
2750       para = new File(args[0]);
2760       if (para.isFile())
277        {
2780          in = new File[] {para};
279        }
280        else
281        {
2820          final FilenameFilter filter = new FilenameFilter()
2830          {
284              public boolean accept (File dir, String name)
285              {
2860                return name.endsWith(".xml");
287              }
288           };
289  
2900          in = para.listFiles(filter);
291        }
292  
2930       sMultible = in.length > 1;
294  
2950       final Iterator i = Arrays.asList(in).iterator();
296  
2970       while (i.hasNext())
298        {
2990          final File current = (File) i.next();
300  
3010          log("in: " + current.getAbsolutePath());
302           try
303           {
3040              final Chart2DHandlerImpl handler
305                   = new Chart2DHandlerImpl(dataRepository);
3060              Chart2DHandler theHandler = handler;
3070              if (sDebug)
308               {
3090                  theHandler = (Chart2DHandler) LoggingProxy.getProxy(handler);
310               }
3110              Chart2DParser.parse(new InputSource(new FileInputStream(current)),
312                       theHandler);
3130             handler.writeCache();
314           }
3150          catch (Exception ex)
316           {
3170             log("Got exception", ex);
3180          }
3190       }
320  
3210       log("Done.");
3220    }
323  
324  
325     /** {@inheritDoc} */
326     public void handleGraphLabelsLinesStyle (final Attributes meta)
327           throws SAXException
328     {
329        //
3300    }
331  
332     /**
333      * Handles opening of Category a new ArrayList is created to 
334      * collect inner Data elements.
335      * @param meta the attributes that come with the element.
336      * @throws SAXException never.
337      */
338     public void startCategory (final Attributes meta) throws SAXException
339     {
3400       if (mCurrentSet.size() < mCurrentLabelText.size())
341        {
3420           logDebug("startCategory x = " + mCurrentSet.size() + "/"
343                    + mCurrentLabelText.get(mCurrentSet.size()));
344        }
3450       mCurrentCategory = new ArrayList();
3460    }
347  
348     /**
349      * Handles the closing of Category. 
350      * The Category data, containing the collected Data elements 
351      * is added to the corrent Set.
352      * @throws SAXException never.
353      */
354     public void endCategory () throws SAXException
355     {
3560       if (mCurrentSet.size() < mCurrentLabelText.size())
357        {
3580           logDebug("endCategory x = "
359                    + mCurrentSet.size() + "/"
360                    + mCurrentLabelText.get(mCurrentSet.size()));
361        }
3620       mCurrentSet.add(mCurrentCategory);
3630       mCurrentCategory = null;
3640    }
365  
366     /**
367      * Handles opening of MultiColorsProperties.
368      * @param meta the attributes that come with the element.
369      * @throws SAXException never.
370      */
371     public void startMultiColorsProperties (final Attributes meta)
372           throws SAXException
373     {
3740       final MultiColorsProperties props = new MultiColorsProperties();
375  
3760       props.setMultiColorsPropertiesToDefaults();
377  
3780       setProperties(props, meta);
379  
3800       mCurrentMultiColorsProperties = props;
3810       mCurrentMultiColors = new ArrayList();
3820    }
383  
384     /**
385      * Handles the end of the MultiColorsProperties element.
386      * Adds the collected MultiColors to the properties.
387      * @throws SAXException never.
388      */
389     public void endMultiColorsProperties () throws SAXException
390     {
3910       if (!mCurrentMultiColors.isEmpty())
392        {
3930(5)         mCurrentMultiColorsProperties
394                 .setColorsCustom((Color[]) mCurrentMultiColors
395                       .toArray(new Color[] {}));
396        }
397  
3980       mMultiColorsProperties.add(mCurrentMultiColorsProperties);
3990       mCurrentMultiColors = null;
4000    }
401  
402     /**
403      * Handles opening of LBChart2D and registeres the chart type 
404      * accordingly.
405      * @param meta the attributes that come with the element.
406      * @throws SAXException never.
407      */
408     public void startLBChart2D (final Attributes meta) throws SAXException
409     {
4100       mChartType = "LBChart2D";
4110    }
412  
413     /** {@inheritDoc} */
414     public void endLBChart2D () throws SAXException
415     {
416         //
4170    }
418  
419     /**
420      * Handles the content of the LegentLablesTexts element.
421      * Special handling for xpath expressions is done here. 
422      * See {@link Chart2DHandlerImpl} for details.
423      * @param data the element content.
424      * @param meta attributes set with the element.
425      * @throws SAXException if an error occurs.
426      */
427     public void handleLegendLabelsTexts (final String data,
428           final Attributes meta) throws SAXException
429     {
4300(6)      if (data.startsWith("!"))
431        {
432            try
433            {
4340               final DocumentBuilder builder = getDocumentBuilder();
4350               final Document document = builder.parse(
436                    new File(mDataRepository,
437                        ((Pair) mXaxis.get(mXaxis.size() - 1)).getFileName()));
4380               final NodeIterator i
439                    = XPathAPI.selectNodeIterator(
440                        document, data.substring(1));
4410               Node node = i.nextNode();
4420               while (node != null)
443                {
4440                   logDebug("Legend Label: " + node.getNodeValue());
4450                   mCurrentLegendLabelsTexts.add(node.getNodeValue());
4460                   node = i.nextNode();
447                }
448            }
4490           catch (Exception ex)
450            {
4510               final SAXException e = new SAXException(ex);
4520               e.initCause(ex);
4530               throw e;
4540           }
455        }
456        else
457        {
4580           mCurrentLegendLabelsTexts.add(data);
459        }
4600    }
461  
462     /** {@inheritDoc} */
463     public void startDataset (final Attributes meta) throws SAXException
464     {
4650       mDoConvertToStacked = meta.getIndex("DoConvertToStacked") != -1;
4660       mCurrentDataSet = new ArrayList();
4670    }
468  
469     /**
470      * Called at the end of a dataset.
471      * The collected data is passed to chart2d.
472      * @throws SAXException if an error occures.
473      */
474     public void endDataset () throws SAXException
475     {
4760       final int zSize
477            = ((List) ((List) mCurrentDataSet.get(0)).get(0)).size();
4780       final int ySize
479            = ((List) mCurrentDataSet.get(0)).size();
480        
4810       final Dataset dataset = new Dataset(mCurrentDataSet.size(), ySize, zSize);
482  
4830       if (!sMultible)
484        {
4850          log("Dimension: [" + mCurrentDataSet.size() + "]["
486                 + ySize + "][" + zSize + "]");
487        }
488  
489        Iterator i;
490        Iterator j;
491        Iterator k;
492        int x;
493        int y;
494        int z;
495  
4960       x = 0;
4970       i = mCurrentDataSet.iterator();
4980       while (i.hasNext())
499        {
5000          y = 0;
5010          j = ((List) i.next()).iterator();
5020          while (j.hasNext())
503           {
5040             z = 0;
5050             k = ((List) j.next()).iterator();
5060             while (k.hasNext())
507              {
5080                final float f = ((Float) k.next()).floatValue();
509  
5100                if (!sMultible)
511                 {
5120                   log("point["
513                            + x + "/" + mCurrentLegendLabelsTexts.get(x) + "]["
514                            + y + "/" + mCurrentLabelText.get(y) + "][" + z
515                          + "] = " + f);
516                 }
517  
5180                dataset.set(x, y, z, f);
5190                z++;
5200             }
5210             y++;
522           }
5230          x++;
524        }
5250       if (mDoConvertToStacked)
526        {
5270          dataset.doConvertToStacked();
528        }
529  
5300       mDataSets.add(dataset);
5310       mCurrentDataSet = null;
5320    }
533  
534     /** {@inheritDoc} */
535     public void handlePieChart2DProperties (final Attributes meta)
536           throws SAXException
537     {
5380       mPieChart2DProperties = new PieChart2DProperties();
5390       mPieChart2DProperties.setPieChart2DPropertiesToDefaults();
5400       setProperties(mPieChart2DProperties, meta);
5410    }
542  
543     /** {@inheritDoc} */
544     public void startGraphChart2DProperties (final Attributes meta)
545           throws SAXException
546     {
5470       mGraphChart2DProperties = new GraphChart2DProperties();
5480       mGraphChart2DProperties.setGraphChart2DPropertiesToDefaults();
5490       setProperties(mGraphChart2DProperties, meta);
5500       mCurrentLabelText = new ArrayList();
5510    }
552  
553     /** {@inheritDoc} */
554     public void endGraphChart2DProperties () throws SAXException
555     {
5560       if (!mCurrentLabelText.isEmpty())
557        {
5580(7)         mGraphChart2DProperties
559                 .setLabelsAxisLabelsTexts((String[]) mCurrentLabelText
560                       .toArray(new String[] {}));
561        }
5620    }
563  
564     /** {@inheritDoc} */
565     public void handleAxisLabelText (final java.lang.String data,
566           final Attributes meta) throws SAXException
567     {
5680(8)      if (data.startsWith("!"))
569        {
570            // Maximum number of builds aggregated in one label
5710           final int max = Integer.parseInt(meta.getValue("max"));
572            // number of labels
5730           final int count = Integer.parseInt(meta.getValue("count"));
574            
5750           Collection map = fileMatcher(data.substring(1));
576            
5770           int size = map.size();
5780           if (size == 0)
579            {
5800               throw new RuntimeException("No files found for pattern "
581                        + data + " in " + mDataRepository + ".");
582            }
583            
5840           if (size > max * count)
585            {
5860               final List newList = new ArrayList(max * count);
5870               final Iterator it = map.iterator();
5880               int remove = size - (max * count);
5890               while (remove > 0)
590                {
5910                   it.next();
5920                   remove--;
593                }
5940               while (it.hasNext())
595                {
5960(9)                  newList.add(it.next());
597                }
5980               map = newList;
5990               size = map.size();
600            }
601            
6020           mXaxisModulus = Math.max(1, size / count);
6030           logDebug("Will have " + mXaxisModulus + " enties per category.");
604            
6050           mXaxis.addAll(map);
6060           final Iterator i = map.iterator();
6070           int xPos = 0;
6080           while (i.hasNext())
609            {
6100               final String label = ((Pair) i.next()).getLabel();
6110               if (xPos % mXaxisModulus == 0)
612                {
6130                   logDebug("X-Label: " + label);
6140                   mCurrentLabelText.add(label);
615                }
6160               xPos++;
6170           }
6180       }
619        else
620        {
6210           mCurrentLabelText.add(data);
622        }
6230    }
624  
625      private List fileMatcher (String filePattern)
626      {
6270         final List result = new ArrayList();
6280            final Pattern pattern = Pattern.compile(filePattern);
6290            final Iterator i = mFilePatterns.iterator();
6300            while (i.hasNext())
631             {
6320                final String fileName = (String) i.next();
6330                final Matcher m = pattern.matcher(fileName);
6340                if (m.matches())
635                 {
6360                   result.add(new Pair(fileName, m.group(1)));
637                 }
6380            }
6390         return result;
640      }
641  
642      /** {@inheritDoc} */
643      public void startChart2D (final Attributes meta) throws SAXException
644     {
645        String value;
646  
6470       value = meta.getValue("Width");
6480       if (value != null)
649        {
6500          mWidth = Integer.decode(value).intValue();
651        }
652  
6530       value = meta.getValue("Height");
6540       if (value != null)
655        {
6560          mHeight = Integer.decode(value).intValue();
657        }
658  
6590       value = meta.getValue("Type");
6600       if (value != null)
661        {
6620          mType = value;
663        }
664  
6650       value = meta.getValue("Filename");
6660       if (value != null)
667        {
6680          mFilename = value;
669        }
6700    }
671  
672      /** {@inheritDoc} */
673     public void endChart2D () throws SAXException
674     {
675        try
676        {
6770          Chart2D chart2d = null;
678  
6790          if ("PieChart2D".equals(mChartType))
680           {
6810             final PieChart2D chart = new PieChart2D();
682  
6830             chart.setObject2DProperties(mObject2DProperties);
6840             chart.setChart2DProperties(mChart2DProperties);
6850             chart.setPieChart2DProperties(mPieChart2DProperties);
6860             chart.setLegendProperties(mLegendProperties);
6870             chart.setDataset((Dataset) mDataSets.get(0));
6880             chart.setMultiColorsProperties(
689                    (MultiColorsProperties) mMultiColorsProperties.get(0));
6900             chart2d = chart;
6910          }
6920          else if ("LLChart2D".equals(mChartType))
693           {
6940             final LLChart2D chart = new LLChart2D();
6950             fillChartData(chart);
6960             chart2d = chart;
6970          }
6980          else if ("LBChart2D".equals(mChartType))
699           {
7000             final LBChart2D chart = new LBChart2D();
7010             fillChartData(chart);
7020             chart2d = chart;
7030          }
704           else
705           {
7060              throw new SAXException("Unknown chart type " + mChartType + ".");
707           }
708  
7090          final Dimension size = new Dimension(mWidth, mHeight);
710  
7110          chart2d.setMaximumSize(size);
7120          chart2d.setPreferredSize(size);
713  
7140          if (chart2d.validate(false))
715           {
7160             javax.imageio.ImageIO.write(chart2d.getImage(), mType, new File(
717                    mFilename));
7180             log("out: " + new File(mFilename).getAbsolutePath());
719           }
720           else
721           {
7220             chart2d.validate(true);
723           }
724        }
7250       catch (Exception ex)
726        {
7270           final SAXException e = new SAXException(ex);
7280           e.initCause(ex);
7290           throw e;
7300       }
7310    }
732  
733     /** {@inheritDoc} */
734     public void startLLChart2D (final Attributes meta) throws SAXException
735     {
7360       mChartType = "LLChart2D";
7370    }
738  
739     /** {@inheritDoc} */
740     public void endLLChart2D () throws SAXException
741     {
742         //
7430    }
744  
745     /** {@inheritDoc} */
746     public void handleGraphNumbersLinesStyle (final Attributes meta)
747           throws SAXException
748     {
749         //
7500    }
751  
752     /** {@inheritDoc} */
753 (10)   public void handleData (final java.lang.String data, final Attributes meta)
754           throws SAXException
755     {
7560(11)      if (data.startsWith("!"))
757        {
758            // LOOPIT
7590           final Iterator z = mCurrentLegendLabelsTexts.iterator();
7600           while (z.hasNext())
761            {
7620               final String zValue = (String) z.next();
763                
7640               int xPos = 0;
7650               final Iterator x = mXaxis.iterator();
7660               while (x.hasNext())
767                {
7680                   final Pair pair = (Pair) x.next();
7690                   final String fileName = pair.getFileName();
770                    
7710                   String query = data.substring(1);
7720                   query = query.replaceAll("\\$z", zValue);
773                    
7740                   String value = resolveXpath(fileName, query);
7750                   if (value.length() == 0)
776                    {
7770                       value = "0";
778                    }
7790                   else if (value.indexOf("second") != -1)
780                    {
7810                       value = parseAntTime(value);
782                    }
7830(12)                  mCurrentCategory.add(new Float(Float.parseFloat(value)));
784                    
7850                   xPos++;
7860                   while (xPos % mXaxisModulus != 0 && !x.hasNext())
787                    {
7880                       xPos++;
789                        // continue chart with last value.
7900(13)                      mCurrentCategory.add(new Float(Float.parseFloat(value)));
791                    }
7920                   if ((xPos % mXaxisModulus == 0 && x.hasNext())
793                            || (!x.hasNext() && z.hasNext()))
794                    {
7950                       endCategory();
796                        // it is save to call startCategory without a entry...
7970                       startCategory(null);
798                    }
7990               }
800                    
801                
8020               if (z.hasNext())
803                {
8040                   endSet();
8050                   startSet(null);
8060                   startCategory(null);
807                }
8080           }
8090       }
810        else
811        {
8120(14)          mCurrentCategory.add(new Float(Float.parseFloat(data)));
813        }
8140    }
815  
816      private String parseAntTime (String value)
817      {
8180         final Pattern pat = Pattern.compile(TIME_PATTERN);
8190         final Matcher mat = pat.matcher(value);
8200         logDebug("grops " + value);
8210         String result = value;
8220         if (mat.matches())
823          {
8240             int minutes = 0;
8250             int seconds = 0;
8260             if (mat.group(TIME_PATTERN_MINUTES_GROUP) != null)
827              {
8280                 minutes = Integer.parseInt(
829                          mat.group(TIME_PATTERN_MINUTES_GROUP));
830              }
8310             if (mat.group(TIME_PATTERN_SECONDS_GROUP) != null)
832              {
8330                 seconds = Integer.parseInt(
834                      mat.group(TIME_PATTERN_SECONDS_GROUP));
835              }
8360             result = String.valueOf(
837                      Date.SECONDS_PER_MINUTE * minutes + seconds);
838          }
8390         return result;
840      }
841  
842     private String resolveXpath (String fileName, String xpath)
843             throws SAXException
844     {
8450        logDebug(xpath + " in " + fileName);
8460        String result = null;
8470        final String cacheKey = xpath + "@" + fileName;
8480        result = (String) mXpathCache.get(cacheKey);
8490        if (result == null)
850         {
851             try
852             {
8530                final DocumentBuilder builder = getDocumentBuilder();
8540                final Document document = builder.parse(new File(mDataRepository,
855                         fileName));
8560                final XObject object = XPathAPI.eval(document, xpath);
8570                result = object.str();
858             }
8590            catch (Exception ex)
860             {
8610                final SAXException e = new SAXException(ex);
8620                e.initCause(ex);
8630                throw e;
8640            }
8650            logDebug(" = " + result);
8660            mXpathCache.put(cacheKey, result);
867         }
868         else
869         {
8700            logDebug(" = " + result + " (cached)");
871         }
8720        return result;
873     }
874  
875     /** {@inheritDoc} */
876     public void startPieChart2D (final Attributes meta) throws SAXException
877     {
8780       mChartType = "PieChart2D";
8790    }
880  
881     /** {@inheritDoc} */
882     public void endPieChart2D () throws SAXException
883     {
884         //
8850    }
886  
887     /** {@inheritDoc} */
888     public void handleObject2DProperties (final Attributes meta)
889           throws SAXException
890     {
8910       mObject2DProperties = new Object2DProperties();
8920       mObject2DProperties.setObject2DPropertiesToDefaults();
8930       setProperties(mObject2DProperties, meta);
8940    }
895  
896     /** {@inheritDoc} */
897     public void handleWarningRegionProperties (final Attributes meta)
898           throws SAXException
899     {
9000       final WarningRegionProperties props = new WarningRegionProperties();
901  
9020       props.setToDefaults();
9030       setProperties(props, meta);
9040    }
905  
906     /** {@inheritDoc} */
907     public void handleChart2DProperties (final Attributes meta)
908           throws SAXException
909     {
9100       mChart2DProperties = new Chart2DProperties();
9110       mChart2DProperties.setChart2DPropertiesToDefaults();
9120       setProperties(mChart2DProperties, meta);
9130    }
914  
915     /** {@inheritDoc} */
916     public void startSet (final Attributes meta) throws SAXException
917     {
9180       if (mCurrentDataSet.size() < mCurrentLegendLabelsTexts.size())
919        {
9200           logDebug("startSet z = " + mCurrentDataSet.size() + "/"
921                    + mCurrentLegendLabelsTexts.get(mCurrentDataSet.size()));
922        }
9230       mCurrentSet = new ArrayList();
9240    }
925  
926     /** {@inheritDoc} */
927     public void endSet () throws SAXException
928     {
9290       if (mCurrentDataSet.size() < mCurrentLegendLabelsTexts.size())
930        {
9310           logDebug("endSet z = " + mCurrentDataSet.size() + "/"
932                    + mCurrentLegendLabelsTexts.get(mCurrentDataSet.size()));
933        }
9340       mCurrentDataSet.add(mCurrentSet);
9350       mCurrentSet = null;
9360    }
937  
938     /** {@inheritDoc} */
939     public void startGraphProperties (final Attributes meta) throws SAXException
940     {
9410       final GraphProperties props = new GraphProperties();
942  
9430       props.setGraphPropertiesToDefaults();
9440       setProperties(props, meta);
9450       mGraphProperties.add(props);
9460    }
947  
948     /** {@inheritDoc} */
949     public void endGraphProperties () throws SAXException
950     {
951         //
9520    }
953  
954     /** {@inheritDoc} */
955     public void handleColorsCustom (final java.lang.String data,
956           final Attributes meta) throws SAXException
957     {
9580       mCurrentMultiColors.add(getColor(data));
9590    }
960  
961     /** {@inheritDoc} */
962     public void startLegendProperties (final Attributes meta)
963           throws SAXException
964     {
9650       mLegendProperties = new LegendProperties();
9660       mLegendProperties.setLegendPropertiesToDefaults();
9670       mCurrentLegendLabelsTexts = new ArrayList();
9680    }
969  
970     /** {@inheritDoc} */
971     public void endLegendProperties () throws SAXException
972     {
9730       if (!mCurrentLegendLabelsTexts.isEmpty())
974        {
9750(15)         mLegendProperties
976                 .setLegendLabelsTexts((String[]) mCurrentLegendLabelsTexts
977                    .toArray(new String[] {}));
978        }
9790    }
980  
981 (16)(17)(18)   private void setProperties (Object props, final Attributes meta)
982     {
9830       int i = meta.getLength() - 1;
984  
9850       for (; i >= 0; i--)
986        {
9870          final String key = meta.getQName(i);
9880          final String value = meta.getValue(i);
989           Method m;
9900          final String setterName = "set" + key;
991  
992           try
993           {
9940             m = props.getClass().getDeclaredMethod(setterName,
995                    new Class[] {String.class});
996  
9970             m.invoke(props, new Object[] {value});
998           }
9990          catch (Exception ex)
1000           {
10010             m = null;
10020          }
1003  
10040          if (m == null)
1005           {
1006              try
1007              {
10080                m = props.getClass().getDeclaredMethod(setterName,
1009                       new Class[] {Boolean.TYPE});
1010  
10110                m.invoke(props, new Object[] {Boolean.valueOf(value)});
1012              }
10130             catch (Exception ex)
1014              {
10150                m = null;
10160             }
1017           }
1018  
10190          if (m == null)
1020           {
1021              try
1022              {
10230                m = props.getClass().getDeclaredMethod(setterName,
1024                       new Class[] {Integer.TYPE});
1025  
10260                m.invoke(props, new Object[] {getInteger(value, props)});
1027              }
10280             catch (Exception ex)
1029              {
10300                m = null;
10310             }
1032           }
1033  
10340          if (m == null)
1035           {
1036              try
1037              {
10380                m = props.getClass().getDeclaredMethod(setterName,
1039                       new Class[] {Color.class});
1040  
10410                m.invoke(props, new Object[] {getColor(value)});
1042              }
10430             catch (Exception ex)
1044              {
10450                m = null;
10460             }
1047           }
1048  
10490          if (m == null)
1050           {
1051              try
1052              {
10530                m = props.getClass().getDeclaredMethod(setterName,
1054                       new Class[] {Float.TYPE});
1055  
10560                m.invoke(props, new Object[] {Float.valueOf(value)});
1057              }
10580             catch (Exception ex)
1059              {
10600                m = null;
10610             }
1062           }
1063  
10640          if (m == null)
1065           {
1066              try
1067              {
10680                m = props.getClass().getDeclaredMethod(setterName,
1069                       new Class[] {Dimension.class});
1070  
10710                m.invoke(props, new Object[] {getDimension(value)});
1072              }
10730             catch (Exception ex)
1074              {
10750                m = null;
10760             }
1077           }
1078  
10790          if (m == null)
1080           {
1081              try
1082              {
10830                m = props.getClass().getDeclaredMethod(setterName,
1084                       new Class[] {java.awt.AlphaComposite.class});
1085  
10860                m.invoke(props, new Object[] {getAlphaComposite(value, props)});
1087              }
10880             catch (Exception ex)
1089              {
10900                m = null;
10910             }
1092           }
1093  
10940          if (m == null)
1095           {
10960             log("Could not set " + props.getClass().getName()
1097                    + "." + setterName + " = " + value);
1098           }
1099        }
11000    }
1101  
1102     private Color getColor (String col)
1103     {
11040       Color c = null;
1105  
1106        try
1107        {
1108           try
1109           {
11100             c = Color.decode(col);
1111           }
11120          catch (Exception ex)
1113           {
11140             final Field f = Color.class.getField(col);
11150             c = (Color) f.get(null);
11160          }
1117        }
11180       catch (Exception ex)
1119        {
1120            // no match
11210       }
1122  
11230       return c;
1124     }
1125  
1126     private Dimension getDimension (String val)
1127     {
11280       final double w = Double.parseDouble(val.substring(0, val.indexOf('x')));
11290       final double h = Double.parseDouble(val.substring(1 + val.indexOf('x')));
11300       final Dimension d = new Dimension();
11310       d.setSize(w, h);
11320       return d;
1133     }
1134  
1135     private Integer getInteger (String value, Object properties)
1136 (19)       throws Exception
1137     {
1138        int i;
1139  
1140        try
1141        {
11420          i = Integer.decode(value).intValue();
1143        }
11440       catch (Exception ex)
1145        {
1146           try
1147           {
11480             final Field f = properties.getClass().getField(value);
1149  
11500             i = f.getInt(null);
1151           }
11520          catch (Exception exx)
1153           {
11540             final Field f = java.awt.Font.class.getField(value);
1155  
11560             i = f.getInt(null);
11570          }
11580       }
1159  
11600       return new Integer(i);
1161     }
1162  
1163     private AlphaComposite getAlphaComposite (String value, Object properties)
1164 (20)         throws Exception
1165     {
11660       AlphaComposite alpha = null;
1167  
1168        try
1169        {
11700          final Field f = properties.getClass().getField(
1171                   value.toUpperCase(Constants.SYSTEM_LOCALE));
1172  
11730          alpha = (AlphaComposite) f.get(null);
1174        }
11750       catch (Exception exx)
1176        {
1177           try
1178           {
11790             final Field f = AlphaComposite.class.getField(
1180                      value.toUpperCase(Constants.SYSTEM_LOCALE));
11810             alpha = AlphaComposite.getInstance(f.getInt(null));
1182           }
11830          catch (Exception ex)
1184           {
1185              try
1186              {
11870                final Field f = AlphaComposite.class.getField(value);
1188  
11890                alpha = (AlphaComposite) f.get(null);
1190              }
11910             catch (Exception exxx)
1192              {
1193                  // no match
11940             }
11950          }
11960       }
1197  
11980       return alpha;
1199     }
1200  
1201     private void fillChartData (final GraphChart2D chart)
1202     {
12030       chart.setObject2DProperties(mObject2DProperties);
12040       chart.setChart2DProperties(mChart2DProperties);
12050       chart.setGraphChart2DProperties(mGraphChart2DProperties);
12060       chart.setLegendProperties(mLegendProperties);
1207  
12080       Iterator i = mDataSets.iterator();
12090       while (i.hasNext())
1210        {
12110          chart.addDataset((Dataset) i.next());
1212        }
1213  
12140       i = mMultiColorsProperties.iterator();
12150       while (i.hasNext())
1216        {
12170          chart.addMultiColorsProperties((MultiColorsProperties) i.next());
1218        }
1219  
12200       i = mGraphProperties.iterator();
12210       while (i.hasNext())
1222        {
12230          chart.addGraphProperties((GraphProperties) i.next());
1224        }
1225  
12260       i = mWarningRegionProperties.iterator();
12270       while (i.hasNext())
1228        {
12290          chart.addWarningRegionProperties(
1230                 (WarningRegionProperties) i.next());
1231        }
12320    }
1233     
1234     /**
1235      * Reads the xpath query cache if possible.
1236      */
1237     private void readCache ()
1238     {
12390        BufferedReader reader = null;
1240         try
1241         {
12420            final File inFile = new File(mDataRepository, "stat-cache");
12430            if (inFile.canRead())
1244             {
12450                reader = new BufferedReader(new FileReader(inFile));
12460                String line = reader.readLine();
12470                while (line != null)
1248                 {
12490                    if (line.length() > 0)
1250                     {
12510                        final String[] data = line.split("\t");
12520                        if (data.length > 1)
1253                         {
12540(21)                           mXpathCache.put(data[0], data[1]);
1255                         }
1256                         else
1257                         {
12580                            mXpathCache.put(data[0], "");
1259                         }
12600                        line = reader.readLine();
12610                    }
1262                 }
1263             }
1264         }
12650        catch (IOException ex)
1266         {
12670            throw new RuntimeException("Failed to read cache.", ex);
1268         }
1269         finally
1270         {
12710            IoUtil.close(reader);
12720        }
12730    }
1274  
1275     /**
1276      * Writes the xpath query cache if possible.
1277      */
1278     public void writeCache ()
1279     {
12800        if (mDataRepository != null)
1281         {
12820            BufferedWriter writer = null;
1283             try
1284             {
12850                final File file = new File(mDataRepository, "stat-cache");
12860                writer = new BufferedWriter(new FileWriter(file, false));
12870                final Iterator i = mXpathCache.entrySet().iterator();
12880                while (i.hasNext())
1289                 {
12900                    final Entry entry = (Entry) i.next();
12910                    writer.write((String) entry.getKey());
12920                    writer.write('\t');
12930                    writer.write((String) entry.getValue());
12940                    writer.write('\n');
12950                }
1296             }
12970            catch (IOException ex)
1298             {
12990                throw new RuntimeException("Failed to write cache.", ex);
1300             }
1301             finally
1302             {
13030                IoUtil.close(writer);
13040            }
1305         }
13060    }
1307     
1308     /**
1309      * Collects files available in the given path.
1310      * @param dataRepository the path to look in
1311      * @param path the pattern representation of the path;
1312      */
1313     private void collectPatterns (File dataRepository, String path)
1314     {
1315         final String thisPath;
13160        if (path == null)
1317         {
13180            thisPath = "";
1319         }
1320         else
1321         {
13220            thisPath = path + "/" + dataRepository.getName();
1323         }
13240        if (dataRepository.isFile())
1325         {
13260            mFilePatterns.add(thisPath);
1327         }
13280        else if (dataRepository.isDirectory())
1329         {
13300            final File[] sub = dataRepository.listFiles();
13310            for (int i = 0; i < sub.length; i++)
1332             {
13330                collectPatterns(sub[i], thisPath);
1334             }
1335         }
13360    }
1337     
1338      /** Returns the lazy initialized document builder. */
1339      private DocumentBuilder getDocumentBuilder ()
1340         throws ParserConfigurationException
1341      {
13420         if (mDocumentBuilder == null)
1343          {
13440             mDocumentBuilder = DocumentBuilderFactory.newInstance().
1345                       newDocumentBuilder();
1346          }
13470         return mDocumentBuilder;
1348      }
1349  
1350      private static void log (String data)
1351      {
13520         System.out.println(data);
13530     }
1354  
1355      private static void log (String data, Throwable thr)
1356      {
13570         System.out.println(data + thr.getMessage());
13580         thr.printStackTrace(System.out);
13590     }
1360  
1361  
1362      private static void logDebug (String data)
1363      {
13640         if (sDebug)
1365          {
13660             log(data);
1367          }
13680     }
1369      
1370      private static class Pair
1371      {
1372         private final String mFileName;
1373         private final String mLabel;
1374         public Pair (final String fileName, final String label)
1375         {
13760            super();
13770            mFileName = fileName;
13780            mLabel = label;
13790        }
1380         public String getFileName ()
1381         {
13820(22)           return mFileName;
1383         }
1384         public String getLabel ()
1385         {
13860            return mLabel;
1387         }
1388     }
1389  }

Findings in this File

f (23) System.out.print is used main class
f (24) System.out.print is used main class
c (1) 59 : 8 Unused import - java.util.logging.Handler.
c (2) 151 : 0 Line is longer than 80 characters.
c (3) 235 : 18 The method main() has an NPath complexity of 288
i (4) 259 : 0 method org.jcoderz.phoenix.chart2d.Chart2DHandlerImpl.main(String[]) makes literal string comparisons passing the literal as an argument
i (5) 393 : 0 Method org.jcoderz.phoenix.chart2d.Chart2DHandlerImpl.endMultiColorsProperties() uses Collection.toArray() with zero-length array argument
c (6) 430 : 11 This call to String.startsWith can be rewritten using String.charAt(0)
i (7) 558 : 0 Method org.jcoderz.phoenix.chart2d.Chart2DHandlerImpl.endGraphChart2DProperties() uses Collection.toArray() with zero-length array argument
c (8) 568 : 11 This call to String.startsWith can be rewritten using String.charAt(0)
w (9) 596 : 0 method org.jcoderz.phoenix.chart2d.Chart2DHandlerImpl.handleAxisLabelText(String, Attributes) uses simple loop to copy contents of one colleciton to another
c (10) 753 : 4 Cyclomatic Complexity is 13 (max allowed is 12).
c (11) 756 : 11 This call to String.startsWith can be rewritten using String.charAt(0)
w (12) 783 : 0 method org.jcoderz.phoenix.chart2d.Chart2DHandlerImpl.handleData(String, Attributes) passes parsed string to primitive wrapper constructor
w (13) 790 : 0 method org.jcoderz.phoenix.chart2d.Chart2DHandlerImpl.handleData(String, Attributes) passes parsed string to primitive wrapper constructor
w (14) 812 : 0 method org.jcoderz.phoenix.chart2d.Chart2DHandlerImpl.handleData(String, Attributes) passes parsed string to primitive wrapper constructor
i (15) 975 : 0 Method org.jcoderz.phoenix.chart2d.Chart2DHandlerImpl.endLegendProperties() uses Collection.toArray() with zero-length array argument
c (16) 981 : 4 Cyclomatic Complexity is 16 (max allowed is 12).
d (17) 981 : 4 Method length is 119 lines (max allowed is 100).
c (18) 981 : 12 The method setProperties() has an NPath complexity of 2917
d (19) 1136 : 15 A method/constructor shouldn't explicitly throw java.lang.Exception
d (20) 1164 : 17 A method/constructor shouldn't explicitly throw java.lang.Exception
w (21) 1254 : 0 method org.jcoderz.phoenix.chart2d.Chart2DHandlerImpl.readCache() accesses list or array with constant index
i (22) 1382 : 0 Confusing to have methods org.jcoderz.phoenix.chart2d.Chart2DHandlerImpl$Pair.getFileName() and org.jcoderz.phoenix.coverage.jaxb.impl.ClassTypeImpl.getFilename()