root/trunk/src/java/org/jcoderz/phoenix/chart2d/Chart2DHandlerImpl.java

Revision 1011, 40.0 kB (checked in by amandel, 4 years ago)

Aligned svn keyword settings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
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 */
33package org.jcoderz.phoenix.chart2d;
34
35
36import java.awt.AlphaComposite;
37import java.awt.Color;
38import java.awt.Dimension;
39import java.io.BufferedReader;
40import java.io.BufferedWriter;
41import java.io.File;
42import java.io.FileInputStream;
43import java.io.FileReader;
44import java.io.FileWriter;
45import java.io.FilenameFilter;
46import java.io.IOException;
47import java.lang.reflect.Field;
48import java.lang.reflect.Method;
49import java.util.ArrayList;
50import java.util.Arrays;
51import java.util.Collection;
52import java.util.HashMap;
53import java.util.Iterator;
54import java.util.List;
55import java.util.Map;
56import java.util.Set;
57import java.util.TreeSet;
58import java.util.Map.Entry;
59import java.util.logging.Handler;
60import java.util.logging.Level;
61import java.util.logging.Logger;
62import java.util.regex.Matcher;
63import java.util.regex.Pattern;
64
65import javax.xml.parsers.DocumentBuilder;
66import javax.xml.parsers.DocumentBuilderFactory;
67import javax.xml.parsers.ParserConfigurationException;
68
69import net.sourceforge.chart2d.Chart2D;
70import net.sourceforge.chart2d.Chart2DProperties;
71import net.sourceforge.chart2d.Dataset;
72import net.sourceforge.chart2d.GraphChart2D;
73import net.sourceforge.chart2d.GraphChart2DProperties;
74import net.sourceforge.chart2d.GraphProperties;
75import net.sourceforge.chart2d.LBChart2D;
76import net.sourceforge.chart2d.LLChart2D;
77import net.sourceforge.chart2d.LegendProperties;
78import net.sourceforge.chart2d.MultiColorsProperties;
79import net.sourceforge.chart2d.Object2DProperties;
80import net.sourceforge.chart2d.PieChart2D;
81import net.sourceforge.chart2d.PieChart2DProperties;
82import net.sourceforge.chart2d.WarningRegionProperties;
83
84import org.apache.xpath.XPathAPI;
85import org.apache.xpath.objects.XObject;
86import org.jcoderz.commons.types.Date;
87import org.jcoderz.commons.util.Constants;
88import org.jcoderz.commons.util.IoUtil;
89import org.jcoderz.commons.util.LoggingProxy;
90import org.jcoderz.commons.util.LoggingUtils;
91import org.w3c.dom.Document;
92import org.w3c.dom.Node;
93import org.w3c.dom.traversal.NodeIterator;
94import org.xml.sax.Attributes;
95import org.xml.sax.InputSource;
96import 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 *  <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 */
162public 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;
172   private static boolean sDebug = false;
173   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;
180   private final List mDataSets = new ArrayList();
181   private final List mMultiColorsProperties = new ArrayList();
182   private final List mGraphProperties = new ArrayList();
183   private final List mWarningRegionProperties = new ArrayList();
184   private int mWidth = DEFAULT_WIDTH;
185   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;
197   private final Set mFilePatterns = new TreeSet();
198   private final List mXaxis = new ArrayList();
199   private int mXaxisModulus = 1;
200   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)
212   {
213       mDataRepository = dataRepository;
214       if (mDataRepository != null)
215       {
216           collectPatterns(mDataRepository, null);
217           if (mFilePatterns.isEmpty())
218           {
219               throw new RuntimeException("No files found in repository path "
220                       + mDataRepository + ".");
221           }
222           readCache();
223       }
224   }
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   public static void main (String[] args) throws IOException
236   {
237      File[] in;
238      File para;
239
240      if ((args.length < 1) || (args.length > DEBUG_ARG_NUM))
241      {
242         String msg;
243
244         msg = "Usage: java " + Chart2DHandlerImpl.class.getName()
245               + " <input file or directory> [context path] [debug]";
246         log(msg);
247         throw new IllegalArgumentException(msg);
248      }
249
250      if (args.length == DEBUG_ARG_NUM)
251      {
252         sDebug = true;
253      }
254     
255      File dataRepository = null;
256     
257      if (args.length > 1)
258      {
259          if (args[1].equals("debug"))
260          {
261              sDebug = true;
262          }
263          else
264          {
265              dataRepository = new File(args[1]);
266          }
267      }
268     
269      if (sDebug)
270      {
271          LoggingUtils.setGlobalHandlerLogLevel(Level.ALL);
272          Logger.getLogger("org.jcoderz.phoenix.chart2d").setLevel(Level.ALL);
273          Logger.getLogger("").setLevel(Level.ALL);
274      }
275      para = new File(args[0]);
276      if (para.isFile())
277      {
278         in = new File[] {para};
279      }
280      else
281      {
282         final FilenameFilter filter = new FilenameFilter()
283         {
284            public boolean accept (File dir, String name)
285            {
286               return name.endsWith(".xml");
287            }
288         };
289
290         in = para.listFiles(filter);
291      }
292
293      sMultible = in.length > 1;
294
295      final Iterator i = Arrays.asList(in).iterator();
296
297      while (i.hasNext())
298      {
299         final File current = (File) i.next();
300
301         log("in: " + current.getAbsolutePath());
302         try
303         {
304             final Chart2DHandlerImpl handler
305                 = new Chart2DHandlerImpl(dataRepository);
306             Chart2DHandler theHandler = handler;
307             if (sDebug)
308             {
309                 theHandler = (Chart2DHandler) LoggingProxy.getProxy(handler);
310             }
311             Chart2DParser.parse(new InputSource(new FileInputStream(current)),
312                     theHandler);
313            handler.writeCache();
314         }
315         catch (Exception ex)
316         {
317            log("Got exception", ex);
318         }
319      }
320
321      log("Done.");
322   }
323
324
325   /** {@inheritDoc} */
326   public void handleGraphLabelsLinesStyle (final Attributes meta)
327         throws SAXException
328   {
329      //
330   }
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   {
340      if (mCurrentSet.size() < mCurrentLabelText.size())
341      {
342          logDebug("startCategory x = " + mCurrentSet.size() + "/"
343                  + mCurrentLabelText.get(mCurrentSet.size()));
344      }
345      mCurrentCategory = new ArrayList();
346   }
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   {
356      if (mCurrentSet.size() < mCurrentLabelText.size())
357      {
358          logDebug("endCategory x = " 
359                  + mCurrentSet.size() + "/"
360                  + mCurrentLabelText.get(mCurrentSet.size()));
361      }
362      mCurrentSet.add(mCurrentCategory);
363      mCurrentCategory = null; 
364   }
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   {
374      final MultiColorsProperties props = new MultiColorsProperties();
375
376      props.setMultiColorsPropertiesToDefaults();
377
378      setProperties(props, meta);
379
380      mCurrentMultiColorsProperties = props;
381      mCurrentMultiColors = new ArrayList();
382   }
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   {
391      if (!mCurrentMultiColors.isEmpty())
392      {
393         mCurrentMultiColorsProperties
394               .setColorsCustom((Color[]) mCurrentMultiColors
395                     .toArray(new Color[] {}));
396      }
397
398      mMultiColorsProperties.add(mCurrentMultiColorsProperties);
399      mCurrentMultiColors = null;
400   }
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   {
410      mChartType = "LBChart2D";
411   }
412
413   /** {@inheritDoc} */
414   public void endLBChart2D () throws SAXException
415   {
416       //
417   }
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   {
430      if (data.startsWith("!"))
431      {
432          try
433          {
434              final DocumentBuilder builder = getDocumentBuilder();
435              final Document document = builder.parse(
436                  new File(mDataRepository, 
437                      ((Pair) mXaxis.get(mXaxis.size() - 1)).getFileName()));
438              final NodeIterator i
439                  = XPathAPI.selectNodeIterator(
440                      document, data.substring(1));
441              Node node = i.nextNode();
442              while (node != null)
443              {
444                  logDebug("Legend Label: " + node.getNodeValue());
445                  mCurrentLegendLabelsTexts.add(node.getNodeValue());
446                  node = i.nextNode();
447              }
448          }
449          catch (Exception ex)
450          {
451              final SAXException e = new SAXException(ex);
452              e.initCause(ex);
453              throw e;
454          }
455      }
456      else
457      {
458          mCurrentLegendLabelsTexts.add(data);
459      }
460   }
461
462   /** {@inheritDoc} */
463   public void startDataset (final Attributes meta) throws SAXException
464   {
465      mDoConvertToStacked = meta.getIndex("DoConvertToStacked") != -1;
466      mCurrentDataSet = new ArrayList();
467   }
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   {
476      final int zSize
477          = ((List) ((List) mCurrentDataSet.get(0)).get(0)).size();
478      final int ySize
479          = ((List) mCurrentDataSet.get(0)).size();
480     
481      final Dataset dataset = new Dataset(mCurrentDataSet.size(), ySize, zSize);
482
483      if (!sMultible)
484      {
485         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
496      x = 0;
497      i = mCurrentDataSet.iterator();
498      while (i.hasNext())
499      {
500         y = 0;
501         j = ((List) i.next()).iterator();
502         while (j.hasNext())
503         {
504            z = 0;
505            k = ((List) j.next()).iterator();
506            while (k.hasNext())
507            {
508               final float f = ((Float) k.next()).floatValue();
509
510               if (!sMultible)
511               {
512                  log("point[" 
513                          + x + "/" + mCurrentLegendLabelsTexts.get(x) + "][" 
514                          + y + "/" + mCurrentLabelText.get(y) + "][" + z
515                        + "] = " + f);
516               }
517
518               dataset.set(x, y, z, f);
519               z++;
520            }
521            y++;
522         }
523         x++;
524      }
525      if (mDoConvertToStacked)
526      {
527         dataset.doConvertToStacked();
528      }
529
530      mDataSets.add(dataset);
531      mCurrentDataSet = null;
532   }
533
534   /** {@inheritDoc} */
535   public void handlePieChart2DProperties (final Attributes meta)
536         throws SAXException
537   {
538      mPieChart2DProperties = new PieChart2DProperties();
539      mPieChart2DProperties.setPieChart2DPropertiesToDefaults();
540      setProperties(mPieChart2DProperties, meta);
541   }
542
543   /** {@inheritDoc} */
544   public void startGraphChart2DProperties (final Attributes meta)
545         throws SAXException
546   {
547      mGraphChart2DProperties = new GraphChart2DProperties();
548      mGraphChart2DProperties.setGraphChart2DPropertiesToDefaults();
549      setProperties(mGraphChart2DProperties, meta);
550      mCurrentLabelText = new ArrayList();
551   }
552
553   /** {@inheritDoc} */
554   public void endGraphChart2DProperties () throws SAXException
555   {
556      if (!mCurrentLabelText.isEmpty())
557      {
558         mGraphChart2DProperties
559               .setLabelsAxisLabelsTexts((String[]) mCurrentLabelText
560                     .toArray(new String[] {}));
561      }
562   }
563
564   /** {@inheritDoc} */
565   public void handleAxisLabelText (final java.lang.String data,
566         final Attributes meta) throws SAXException
567   {
568      if (data.startsWith("!"))
569      {
570          // Maximum number of builds aggregated in one label
571          final int max = Integer.parseInt(meta.getValue("max"));
572          // number of labels
573          final int count = Integer.parseInt(meta.getValue("count"));
574         
575          Collection map = fileMatcher(data.substring(1));
576         
577          int size = map.size();
578          if (size == 0)
579          {
580              throw new RuntimeException("No files found for pattern "
581                      + data + " in " + mDataRepository + ".");
582          }
583         
584          if (size > max * count)
585          {
586              final List newList = new ArrayList(max * count);
587              final Iterator it = map.iterator();
588              int remove = size - (max * count);
589              while (remove > 0)
590              {
591                  it.next();
592                  remove--;
593              }
594              while (it.hasNext())
595              {
596                  newList.add(it.next());
597              }
598              map = newList;
599              size = map.size();
600          }
601         
602          mXaxisModulus = Math.max(1, size / count);
603          logDebug("Will have " + mXaxisModulus + " enties per category.");
604         
605          mXaxis.addAll(map);
606          final Iterator i = map.iterator();
607          int xPos = 0;
608          while (i.hasNext())
609          {
610              final String label = ((Pair) i.next()).getLabel();
611              if (xPos % mXaxisModulus == 0)
612              {
613                  logDebug("X-Label: " + label);
614                  mCurrentLabelText.add(label);
615              }
616              xPos++;
617          }
618      }
619      else
620      {
621          mCurrentLabelText.add(data);
622      }
623   }
624
625    private List fileMatcher (String filePattern)
626    {
627        final List result = new ArrayList();
628           final Pattern pattern = Pattern.compile(filePattern);
629           final Iterator i = mFilePatterns.iterator();
630           while (i.hasNext())
631           {
632               final String fileName = (String) i.next();
633               final Matcher m = pattern.matcher(fileName);
634               if (m.matches())
635               {
636                  result.add(new Pair(fileName, m.group(1))); 
637               }
638           }
639        return result;
640    }
641
642    /** {@inheritDoc} */
643    public void startChart2D (final Attributes meta) throws SAXException
644   {
645      String value;
646
647      value = meta.getValue("Width");
648      if (value != null)
649      {
650         mWidth = Integer.decode(value).intValue();
651      }
652
653      value = meta.getValue("Height");
654      if (value != null)
655      {
656         mHeight = Integer.decode(value).intValue();
657      }
658
659      value = meta.getValue("Type");
660      if (value != null)
661      {
662         mType = value;
663      }
664
665      value = meta.getValue("Filename");
666      if (value != null)
667      {
668         mFilename = value;
669      }
670   }
671
672    /** {@inheritDoc} */
673   public void endChart2D () throws SAXException
674   {
675      try
676      {
677         Chart2D chart2d = null;
678
679         if ("PieChart2D".equals(mChartType))
680         {
681            final PieChart2D chart = new PieChart2D();
682
683            chart.setObject2DProperties(mObject2DProperties);
684            chart.setChart2DProperties(mChart2DProperties);
685            chart.setPieChart2DProperties(mPieChart2DProperties);
686            chart.setLegendProperties(mLegendProperties);
687            chart.setDataset((Dataset) mDataSets.get(0));
688            chart.setMultiColorsProperties(
689                  (MultiColorsProperties) mMultiColorsProperties.get(0));
690            chart2d = chart;
691         }
692         else if ("LLChart2D".equals(mChartType))
693         {
694            final LLChart2D chart = new LLChart2D();
695            fillChartData(chart);
696            chart2d = chart;
697         }
698         else if ("LBChart2D".equals(mChartType))
699         {
700            final LBChart2D chart = new LBChart2D();
701            fillChartData(chart);
702            chart2d = chart;
703         }
704         else
705         {
706             throw new SAXException("Unknown chart type " + mChartType + ".");
707         }
708
709         final Dimension size = new Dimension(mWidth, mHeight);
710
711         chart2d.setMaximumSize(size);
712         chart2d.setPreferredSize(size);
713
714         if (chart2d.validate(false))
715         {
716            javax.imageio.ImageIO.write(chart2d.getImage(), mType, new File(
717                  mFilename));
718            log("out: " + new File(mFilename).getAbsolutePath());
719         }
720         else
721         {
722            chart2d.validate(true);
723         }
724      }
725      catch (Exception ex)
726      {
727          final SAXException e = new SAXException(ex);
728          e.initCause(ex);
729          throw e;
730      }
731   }
732
733   /** {@inheritDoc} */
734   public void startLLChart2D (final Attributes meta) throws SAXException
735   {
736      mChartType = "LLChart2D";
737   }
738
739   /** {@inheritDoc} */
740   public void endLLChart2D () throws SAXException
741   {
742       //
743   }
744
745   /** {@inheritDoc} */
746   public void handleGraphNumbersLinesStyle (final Attributes meta)
747         throws SAXException
748   {
749       //
750   }
751
752   /** {@inheritDoc} */
753   public void handleData (final java.lang.String data, final Attributes meta)
754         throws SAXException
755   {
756      if (data.startsWith("!"))
757      {
758          // LOOPIT
759          final Iterator z = mCurrentLegendLabelsTexts.iterator();
760          while (z.hasNext())
761          {
762              final String zValue = (String) z.next();
763             
764              int xPos = 0;
765              final Iterator x = mXaxis.iterator();
766              while (x.hasNext())
767              {
768                  final Pair pair = (Pair) x.next();
769                  final String fileName = pair.getFileName();
770                 
771                  String query = data.substring(1);
772                  query = query.replaceAll("\\$z", zValue);
773                 
774                  String value = resolveXpath(fileName, query);
775                  if (value.length() == 0)
776                  {
777                      value = "0";
778                  }
779                  else if (value.indexOf("second") != -1)
780                  {
781                      value = parseAntTime(value);
782                  }
783                  mCurrentCategory.add(new Float(Float.parseFloat(value)));
784                 
785                  xPos++;
786                  while (xPos % mXaxisModulus != 0 && !x.hasNext())
787                  {
788                      xPos++;
789                      // continue chart with last value.
790                      mCurrentCategory.add(new Float(Float.parseFloat(value)));
791                  }
792                  if ((xPos % mXaxisModulus == 0 && x.hasNext())
793                          || (!x.hasNext() && z.hasNext()))
794                  {
795                      endCategory();
796                      // it is save to call startCategory without a entry...
797                      startCategory(null);
798                  }
799              }
800                 
801             
802              if (z.hasNext())
803              {
804                  endSet();
805                  startSet(null);
806                  startCategory(null);
807              }
808          }
809      }
810      else
811      {
812          mCurrentCategory.add(new Float(Float.parseFloat(data)));
813      }
814   }
815
816    private String parseAntTime (String value)
817    {
818        final Pattern pat = Pattern.compile(TIME_PATTERN);
819        final Matcher mat = pat.matcher(value);
820        logDebug("grops " + value);
821        String result = value;
822        if (mat.matches())
823        {
824            int minutes = 0;
825            int seconds = 0;
826            if (mat.group(TIME_PATTERN_MINUTES_GROUP) != null)
827            {
828                minutes = Integer.parseInt(
829                        mat.group(TIME_PATTERN_MINUTES_GROUP));
830            }
831            if (mat.group(TIME_PATTERN_SECONDS_GROUP) != null)
832            {
833                seconds = Integer.parseInt(
834                    mat.group(TIME_PATTERN_SECONDS_GROUP));
835            }
836            result = String.valueOf(
837                    Date.SECONDS_PER_MINUTE * minutes + seconds);
838        }
839        return result;
840    }
841
842   private String resolveXpath (String fileName, String xpath) 
843           throws SAXException
844   {
845       logDebug(xpath + " in "  + fileName);
846       String result = null;
847       final String cacheKey = xpath + "@" + fileName;
848       result = (String) mXpathCache.get(cacheKey);
849       if (result == null)
850       {
851           try
852           {
853               final DocumentBuilder builder = getDocumentBuilder();
854               final Document document = builder.parse(new File(mDataRepository,
855                       fileName));
856               final XObject object = XPathAPI.eval(document, xpath);
857               result = object.str();
858           }
859           catch (Exception ex)
860           {
861               final SAXException e = new SAXException(ex);
862               e.initCause(ex);
863               throw e;
864           }
865           logDebug(" = " + result);
866           mXpathCache.put(cacheKey, result);
867       }
868       else
869       {
870           logDebug(" = " + result + " (cached)");
871       }
872       return result;
873   }
874
875   /** {@inheritDoc} */
876   public void startPieChart2D (final Attributes meta) throws SAXException
877   {
878      mChartType = "PieChart2D";
879   }
880
881   /** {@inheritDoc} */
882   public void endPieChart2D () throws SAXException
883   {
884       //
885   }
886
887   /** {@inheritDoc} */
888   public void handleObject2DProperties (final Attributes meta)
889         throws SAXException
890   {
891      mObject2DProperties = new Object2DProperties();
892      mObject2DProperties.setObject2DPropertiesToDefaults();
893      setProperties(mObject2DProperties, meta);
894   }
895
896   /** {@inheritDoc} */
897   public void handleWarningRegionProperties (final Attributes meta)
898         throws SAXException
899   {
900      final WarningRegionProperties props = new WarningRegionProperties();
901
902      props.setToDefaults();
903      setProperties(props, meta);
904   }
905
906   /** {@inheritDoc} */
907   public void handleChart2DProperties (final Attributes meta)
908         throws SAXException
909   {
910      mChart2DProperties = new Chart2DProperties();
911      mChart2DProperties.setChart2DPropertiesToDefaults();
912      setProperties(mChart2DProperties, meta);
913   }
914
915   /** {@inheritDoc} */
916   public void startSet (final Attributes meta) throws SAXException
917   {
918      if (mCurrentDataSet.size() < mCurrentLegendLabelsTexts.size())
919      {
920          logDebug("startSet z = " + mCurrentDataSet.size() + "/"
921                  + mCurrentLegendLabelsTexts.get(mCurrentDataSet.size()));
922      }
923      mCurrentSet = new ArrayList();
924   }
925
926   /** {@inheritDoc} */
927   public void endSet () throws SAXException
928   {
929      if (mCurrentDataSet.size() < mCurrentLegendLabelsTexts.size())
930      {
931          logDebug("endSet z = " + mCurrentDataSet.size() + "/"
932                  + mCurrentLegendLabelsTexts.get(mCurrentDataSet.size()));
933      }
934      mCurrentDataSet.add(mCurrentSet);
935      mCurrentSet = null;
936   }
937
938   /** {@inheritDoc} */
939   public void startGraphProperties (final Attributes meta) throws SAXException
940   {
941      final GraphProperties props = new GraphProperties();
942
943      props.setGraphPropertiesToDefaults();
944      setProperties(props, meta);
945      mGraphProperties.add(props);
946   }
947
948   /** {@inheritDoc} */
949   public void endGraphProperties () throws SAXException
950   {
951       //
952   }
953
954   /** {@inheritDoc} */
955   public void handleColorsCustom (final java.lang.String data,
956         final Attributes meta) throws SAXException
957   {
958      mCurrentMultiColors.add(getColor(data));
959   }
960
961   /** {@inheritDoc} */
962   public void startLegendProperties (final Attributes meta)
963         throws SAXException
964   {
965      mLegendProperties = new LegendProperties();
966      mLegendProperties.setLegendPropertiesToDefaults();
967      mCurrentLegendLabelsTexts = new ArrayList();
968   }
969
970   /** {@inheritDoc} */
971   public void endLegendProperties () throws SAXException
972   {
973      if (!mCurrentLegendLabelsTexts.isEmpty())
974      {
975         mLegendProperties
976               .setLegendLabelsTexts((String[]) mCurrentLegendLabelsTexts
977                  .toArray(new String[] {}));
978      }
979   }
980
981   private void setProperties (Object props, final Attributes meta)
982   {
983      int i = meta.getLength() - 1;
984
985      for (; i >= 0; i--)
986      {
987         final String key = meta.getQName(i);
988         final String value = meta.getValue(i);
989         Method m;
990         final String setterName = "set" + key;
991
992         try
993         {
994            m = props.getClass().getDeclaredMethod(setterName,
995                  new Class[] {String.class});
996
997            m.invoke(props, new Object[] {value});
998         }
999         catch (Exception ex)
1000         {
1001            m = null;
1002         }
1003
1004         if (m == null)
1005         {
1006            try
1007            {
1008               m = props.getClass().getDeclaredMethod(setterName,
1009                     new Class[] {Boolean.TYPE});
1010
1011               m.invoke(props, new Object[] {Boolean.valueOf(value)});
1012            }
1013            catch (Exception ex)
1014            {
1015               m = null;
1016            }
1017         }
1018
1019         if (m == null)
1020         {
1021            try
1022            {
1023               m = props.getClass().getDeclaredMethod(setterName,
1024                     new Class[] {Integer.TYPE});
1025
1026               m.invoke(props, new Object[] {getInteger(value, props)});
1027            }
1028            catch (Exception ex)
1029            {
1030               m = null;
1031            }
1032         }
1033
1034         if (m == null)
1035         {
1036            try
1037            {
1038               m = props.getClass().getDeclaredMethod(setterName,
1039                     new Class[] {Color.class});
1040
1041               m.invoke(props, new Object[] {getColor(value)});
1042            }
1043            catch (Exception ex)
1044            {
1045               m = null;
1046            }
1047         }
1048
1049         if (m == null)
1050         {
1051            try
1052            {
1053               m = props.getClass().getDeclaredMethod(setterName,
1054                     new Class[] {Float.TYPE});
1055
1056               m.invoke(props, new Object[] {Float.valueOf(value)});
1057            }
1058            catch (Exception ex)
1059            {
1060               m = null;
1061            }
1062         }
1063
1064         if (m == null)
1065         {
1066            try
1067            {
1068               m = props.getClass().getDeclaredMethod(setterName,
1069                     new Class[] {Dimension.class});
1070
1071               m.invoke(props, new Object[] {getDimension(value)});
1072            }
1073            catch (Exception ex)
1074            {
1075               m = null;
1076            }
1077         }
1078
1079         if (m == null)
1080         {
1081            try
1082            {
1083               m = props.getClass().getDeclaredMethod(setterName,
1084                     new Class[] {java.awt.AlphaComposite.class});
1085
1086               m.invoke(props, new Object[] {getAlphaComposite(value, props)});
1087            }
1088            catch (Exception ex)
1089            {
1090               m = null;
1091            }
1092         }
1093
1094         if (m == null)
1095         {
1096            log("Could not set " + props.getClass().getName()
1097                  + "." + setterName + " = " + value);
1098         }
1099      }
1100   }
1101
1102   private Color getColor (String col)
1103   {
1104      Color c = null;
1105
1106      try
1107      {
1108         try
1109         {
1110            c = Color.decode(col);
1111         }
1112         catch (Exception ex)
1113         {
1114            final Field f = Color.class.getField(col);
1115            c = (Color) f.get(null);
1116         }
1117      }
1118      catch (Exception ex)
1119      {
1120          // no match
1121      }
1122
1123      return c;
1124   }
1125
1126   private Dimension getDimension (String val)
1127   {
1128      final double w = Double.parseDouble(val.substring(0, val.indexOf('x')));
1129      final double h = Double.parseDouble(val.substring(1 + val.indexOf('x')));
1130      final Dimension d = new Dimension();
1131      d.setSize(w, h);
1132      return d;
1133   }
1134
1135   private Integer getInteger (String value, Object properties) 
1136       throws Exception
1137   {
1138      int i;
1139
1140      try
1141      {
1142         i = Integer.decode(value).intValue();
1143      }
1144      catch (Exception ex)
1145      {
1146         try
1147         {
1148            final Field f = properties.getClass().getField(value);
1149
1150            i = f.getInt(null);
1151         }
1152         catch (Exception exx)
1153         {
1154            final Field f = java.awt.Font.class.getField(value);
1155
1156            i = f.getInt(null);
1157         }
1158      }
1159
1160      return new Integer(i);
1161   }
1162
1163   private AlphaComposite getAlphaComposite (String value, Object properties)
1164         throws Exception
1165   {
1166      AlphaComposite alpha = null;
1167
1168      try
1169      {
1170         final Field f = properties.getClass().getField(
1171                 value.toUpperCase(Constants.SYSTEM_LOCALE));
1172
1173         alpha = (AlphaComposite) f.get(null);
1174      }
1175      catch (Exception exx)
1176      {
1177         try
1178         {
1179            final Field f = AlphaComposite.class.getField(
1180                    value.toUpperCase(Constants.SYSTEM_LOCALE));
1181            alpha = AlphaComposite.getInstance(f.getInt(null));
1182         }
1183         catch (Exception ex)
1184         {
1185            try
1186            {
1187               final Field f = AlphaComposite.class.getField(value);
1188
1189               alpha = (AlphaComposite) f.get(null);
1190            }
1191            catch (Exception exxx)
1192            {
1193                // no match
1194            }
1195         }
1196      }
1197
1198      return alpha;
1199   }
1200
1201   private void fillChartData (final GraphChart2D chart)
1202   {
1203      chart.setObject2DProperties(mObject2DProperties);
1204      chart.setChart2DProperties(mChart2DProperties);
1205      chart.setGraphChart2DProperties(mGraphChart2DProperties);
1206      chart.setLegendProperties(mLegendProperties);
1207
1208      Iterator i = mDataSets.iterator();
1209      while (i.hasNext())
1210      {
1211         chart.addDataset((Dataset) i.next());
1212      }
1213
1214      i = mMultiColorsProperties.iterator();
1215      while (i.hasNext())
1216      {
1217         chart.addMultiColorsProperties((MultiColorsProperties) i.next());
1218      }
1219
1220      i = mGraphProperties.iterator();
1221      while (i.hasNext())
1222      {
1223         chart.addGraphProperties((GraphProperties) i.next());
1224      }
1225
1226      i = mWarningRegionProperties.iterator();
1227      while (i.hasNext())
1228      {
1229         chart.addWarningRegionProperties(
1230               (WarningRegionProperties) i.next());
1231      }
1232   }
1233   
1234   /**
1235    * Reads the xpath query cache if possible.
1236    */
1237   private void readCache ()
1238   {
1239       BufferedReader reader = null;
1240       try
1241       {
1242           final File inFile = new File(mDataRepository, "stat-cache");
1243           if (inFile.canRead())
1244           {
1245               reader = new BufferedReader(new FileReader(inFile));
1246               String line = reader.readLine();
1247               while (line != null)
1248               {
1249                   if (line.length() > 0)
1250                   {
1251                       final String[] data = line.split("\t");
1252                       if (data.length > 1)
1253                       {
1254                           mXpathCache.put(data[0], data[1]);
1255                       }
1256                       else
1257                       {
1258                           mXpathCache.put(data[0], "");
1259                       }
1260                       line = reader.readLine();
1261                   }
1262               }
1263           }
1264       }
1265       catch (IOException ex)
1266       {
1267           throw new RuntimeException("Failed to read cache.", ex);
1268       }
1269       finally
1270       {
1271           IoUtil.close(reader);
1272       }
1273   }
1274
1275   /**
1276    * Writes the xpath query cache if possible.
1277    */
1278   public void writeCache ()
1279   {
1280       if (mDataRepository != null)
1281       {
1282           BufferedWriter writer = null;
1283           try
1284           {
1285               final File file = new File(mDataRepository, "stat-cache");
1286               writer = new BufferedWriter(new FileWriter(file, false));
1287               final Iterator i = mXpathCache.entrySet().iterator();
1288               while (i.hasNext())
1289               {
1290                   final Entry entry = (Entry) i.next();
1291                   writer.write((String) entry.getKey());
1292                   writer.write('\t');
1293                   writer.write((String) entry.getValue());
1294                   writer.write('\n');
1295               }
1296           }
1297           catch (IOException ex)
1298           {
1299               throw new RuntimeException("Failed to write cache.", ex);
1300           }
1301           finally
1302           {
1303               IoUtil.close(writer);
1304           }
1305       }
1306   }
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;
1316       if (path == null)
1317       {
1318           thisPath = "";
1319       }
1320       else
1321       {
1322           thisPath = path + "/" + dataRepository.getName();
1323       }
1324       if (dataRepository.isFile())
1325       {
1326           mFilePatterns.add(thisPath);
1327       }
1328       else if (dataRepository.isDirectory())
1329       {
1330           final File[] sub = dataRepository.listFiles();
1331           for (int i = 0; i < sub.length; i++)
1332           {
1333               collectPatterns(sub[i], thisPath);
1334           }
1335       }
1336   }
1337   
1338    /** Returns the lazy initialized document builder. */
1339    private DocumentBuilder getDocumentBuilder ()
1340       throws ParserConfigurationException
1341    {
1342        if (mDocumentBuilder == null)
1343        {
1344            mDocumentBuilder = DocumentBuilderFactory.newInstance().
1345                     newDocumentBuilder();
1346        }
1347        return mDocumentBuilder;
1348    }
1349
1350    private static void log (String data)
1351    {
1352        System.out.println(data);
1353    }
1354
1355    private static void log (String data, Throwable thr)
1356    {
1357        System.out.println(data + thr.getMessage());
1358        thr.printStackTrace(System.out);
1359    }
1360
1361
1362    private static void logDebug (String data)
1363    {
1364        if (sDebug)
1365        {
1366            log(data);
1367        }
1368    }
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       {
1376           super();
1377           mFileName = fileName;
1378           mLabel = label;
1379       }
1380       public String getFileName ()
1381       {
1382           return mFileName;
1383       }
1384       public String getLabel ()
1385       {
1386           return mLabel;
1387       }
1388   }
1389}
Note: See TracBrowser for help on using the browser.