View Javadoc

1   /**
2    * Copyright (c) 2012, University of Konstanz, Distributed Systems Group
3    * All rights reserved.
4    * 
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions are met:
7    * * Redistributions of source code must retain the above copyright
8    * notice, this list of conditions and the following disclaimer.
9    * * Redistributions in binary form must reproduce the above copyright
10   * notice, this list of conditions and the following disclaimer in the
11   * documentation and/or other materials provided with the distribution.
12   * * Neither the name of the University of Konstanz nor the
13   * names of its contributors may be used to endorse or promote products
14   * derived from this software without specific prior written permission.
15   * 
16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19   * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20   * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   */
27  package org.perfidix.ouput;
28  
29  import java.io.File;
30  import java.io.FileNotFoundException;
31  import java.io.FileOutputStream;
32  import java.io.PrintStream;
33  import java.lang.reflect.Method;
34  import java.util.Hashtable;
35  import java.util.Map;
36  
37  import org.perfidix.exceptions.AbstractPerfidixMethodException;
38  import org.perfidix.meter.AbstractMeter;
39  import org.perfidix.result.BenchmarkResult;
40  import org.perfidix.result.ClassResult;
41  import org.perfidix.result.MethodResult;
42  
43  /**
44   * Getting out the raw-data as csv.
45   * 
46   * @author Sebastian Graf, University of Konstanz
47   */
48  public final class CSVOutput extends AbstractOutput {
49  
50      /**
51       * Separator to distinguish between class, meter and method.
52       */
53      private static final String SEPARATOR = "-";
54  
55      /** Print stream where the result should end. */
56      private transient final File folder;
57  
58      /**
59       * Flag for correct commata for results.
60       */
61      private transient boolean firstResult;
62  
63      /**
64       * Flag for correct commata for exceptions.
65       */
66      private transient boolean firstException;
67  
68      /**
69       * Set for deleting old files in the beginning.
70       */
71      private transient final Map<File, PrintStream> usedFiles;
72  
73      /**
74       * Constructor for piping the result to elsewhere.
75       * 
76       * @param paramFolder
77       *            an {@link File} object which has to be a folder to write to
78       */
79      public CSVOutput(final File paramFolder) {
80          super();
81          folder = paramFolder;
82          if (folder != null && !folder.isDirectory()) {
83              throw new IllegalStateException(new StringBuilder(paramFolder.toString()).append(
84                  " has to be a folder!").toString());
85          }
86          firstResult = true;
87          firstException = true;
88          usedFiles = new Hashtable<File, PrintStream>();
89      }
90  
91      /**
92       * Constructor for output to {@link System#out}.
93       */
94      public CSVOutput() {
95          this(null);
96      }
97  
98      /**
99       * {@inheritDoc}
100      */
101     @Override
102     public boolean listenToResultSet(final Method meth, final AbstractMeter meter, final double data) {
103         final PrintStream stream =
104             setUpNewPrintStream(false, meth.getDeclaringClass().getSimpleName(), meth.getName(), meter
105                 .getName());
106         if (!firstResult) {
107             stream.append(",");
108         }
109         stream.append(Double.toString(data));
110         stream.flush();
111         firstResult = false;
112         return true;
113 
114     }
115 
116     /** {@inheritDoc} */
117     @Override
118     public boolean listenToException(final AbstractPerfidixMethodException exec) {
119         final PrintStream currentWriter = setUpNewPrintStream(false, "Exceptions");
120         if (!firstException) {
121             currentWriter.append("\n");
122         }
123         currentWriter.append(exec.getRelatedAnno().getSimpleName());
124         currentWriter.append(",");
125         if (exec.getMethod() != null) {
126             currentWriter.append(exec.getMethod().getDeclaringClass().getSimpleName());
127             currentWriter.append("#");
128             currentWriter.append(exec.getMethod().getName());
129             currentWriter.append(",");
130         }
131         exec.getExec().printStackTrace(currentWriter);
132         currentWriter.flush();
133         firstException = false;
134         return true;
135 
136     }
137 
138     /** {@inheritDoc} */
139     @Override
140     public void visitBenchmark(final BenchmarkResult res) {
141         // Printing the data
142         for (final ClassResult classRes : res.getIncludedResults()) {
143             for (final MethodResult methRes : classRes.getIncludedResults()) {
144                 for (final AbstractMeter meter : methRes.getRegisteredMeters()) {
145                     final PrintStream currentWriter =
146                         setUpNewPrintStream(true, classRes.getElementName(), methRes.getElementName(), meter
147                             .getName());
148                     boolean first = true;
149                     for (final Double d : methRes.getResultSet(meter)) {
150                         if (first) {
151                             currentWriter.append(d.toString());
152                             first = false;
153                         } else {
154                             currentWriter.append(new StringBuilder(",").append(d.toString()).toString());
155                         }
156                     }
157 
158                     currentWriter.flush();
159                 }
160             }
161         }
162         // Printing the exceptions
163         final PrintStream currentWriter = setUpNewPrintStream(true, "Exceptions");
164 
165         for (final AbstractPerfidixMethodException exec : res.getExceptions()) {
166             currentWriter.append(exec.getRelatedAnno().getSimpleName());
167             if (exec.getMethod() != null) {
168                 currentWriter.append(":");
169                 currentWriter.append(exec.getMethod().getDeclaringClass().getSimpleName());
170                 currentWriter.append("#");
171                 currentWriter.append(exec.getMethod().getName());
172             }
173             currentWriter.append("\n");
174             exec.getExec().printStackTrace(currentWriter);
175         }
176 
177         currentWriter.flush();
178         tearDownAllStreams();
179     }
180 
181     private void tearDownAllStreams() {
182         for (final PrintStream stream : usedFiles.values()) {
183             stream.close();
184         }
185     }
186 
187     /**
188      * Setting up a new {@link PrintStream}.
189      * 
190      * @param visitorStream
191      *            is the stream for the visitor? Because of line breaks after
192      *            the results.
193      * @param names
194      *            the elements of the filename
195      * @return a {@link PrintStream} instance
196      * @throws FileNotFoundException
197      *             if something goes wrong with the file
198      */
199     private PrintStream setUpNewPrintStream(final boolean visitorStream, final String... names) {
200 
201         PrintStream out = System.out;
202 
203         if (folder == null) {
204             if (visitorStream) {
205                 out.println();
206             }
207         } else {
208             final File toWriteTo = new File(folder, buildFileName(names));
209             try {
210                 if (usedFiles.containsKey(toWriteTo)) {
211                     out = usedFiles.get(toWriteTo);
212                 } else {
213                     toWriteTo.delete();
214                     out = new PrintStream(new FileOutputStream(toWriteTo, !visitorStream));
215                     usedFiles.put(toWriteTo, out);
216                     firstResult = true;
217                 }
218             } catch (final FileNotFoundException e) {
219                 throw new IllegalStateException(e);
220             }
221 
222         }
223         return out;
224 
225     }
226 
227     /**
228      * Helper method to build suitable fileNames.
229      * 
230      * @param names
231      *            different names to be combined
232      * @return a String for a suitable file name
233      */
234     private String buildFileName(final String... names) {
235         final StringBuilder builder = new StringBuilder();
236         for (int i = 0; i < names.length; i++) {
237             builder.append(names[i]);
238             if (i < names.length - 1) {
239                 builder.append(SEPARATOR);
240             }
241         }
242         builder.append(".").append("csv");
243         return builder.toString();
244     }
245 
246 }