KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > vladium > emma > data > MergeProcessor


1 /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
2  *
3  * This program and the accompanying materials are made available under
4  * the terms of the Common Public License v1.0 which accompanies this distribution,
5  * and is available at http://www.eclipse.org/legal/cpl-v10.html
6  *
7  * $Id: MergeProcessor.java,v 1.1.1.1.2.2 2004/07/16 23:32:29 vlad_r Exp $
8  */

9 package com.vladium.emma.data;
10
11 import java.io.File JavaDoc;
12 import java.io.IOException JavaDoc;
13
14 import com.vladium.logging.Logger;
15 import com.vladium.util.Files;
16 import com.vladium.util.IConstants;
17 import com.vladium.util.IProperties;
18 import com.vladium.util.asserts.$assert;
19 import com.vladium.util.exception.Exceptions;
20 import com.vladium.emma.IAppConstants;
21 import com.vladium.emma.IAppErrorCodes;
22 import com.vladium.emma.EMMAProperties;
23 import com.vladium.emma.EMMARuntimeException;
24 import com.vladium.emma.Processor;
25
26 // ----------------------------------------------------------------------------
27
/*
28  * This class was not meant to be public by design. It is made to to work around
29  * access bugs in reflective invocations.
30  */

31 /**
32  * @author Vlad Roubtsov, (C) 2003
33  */

34 public
35 final class MergeProcessor extends Processor
36                            implements IAppErrorCodes
37 {
38     // public: ................................................................
39

40     public static MergeProcessor create ()
41     {
42         return new MergeProcessor ();
43     }
44
45     /**
46      *
47      * @param path [null is equivalent to an empty array]
48      */

49     public synchronized final void setDataPath (final String JavaDoc [] path)
50     {
51         if ((path == null) || (path.length == 0))
52             m_dataPath = IConstants.EMPTY_FILE_ARRAY;
53         else
54             m_dataPath = Files.pathToFiles (path, true);
55     }
56     
57     /**
58      * NOTE: there is no setter for merge attribute because this processor
59      * always overwrites the out file [to ensure compaction]
60      *
61      * @param fileName [null unsets the previous override setting]
62      */

63     public synchronized final void setSessionOutFile (final String JavaDoc fileName)
64     {
65         if (fileName == null)
66             m_sdataOutFile = null;
67         else
68         {
69             final File JavaDoc _file = new File JavaDoc (fileName);
70                 
71             if (_file.exists () && ! _file.isFile ())
72                 throw new IllegalArgumentException JavaDoc ("not a file: [" + _file.getAbsolutePath () + "]");
73                 
74             m_sdataOutFile = _file;
75         }
76     }
77     
78     // protected: .............................................................
79

80     
81     protected void validateState ()
82     {
83         super.validateState ();
84         
85         if (m_dataPath == null)
86             throw new IllegalStateException JavaDoc ("data path not set");
87         
88         // [m_sdataOutFile can be null]
89

90         // [m_propertyOverrides can be null]
91
}
92     
93     
94     protected void _run (final IProperties toolProperties)
95     {
96         final Logger log = m_log;
97
98         final boolean verbose = m_log.atVERBOSE ();
99         if (verbose)
100         {
101             log.verbose (IAppConstants.APP_VERBOSE_BUILD_ID);
102             
103             // [assertion: m_dataPath != null]
104
log.verbose ("input data path:");
105             log.verbose ("{");
106             for (int p = 0; p < m_dataPath.length; ++ p)
107             {
108                 final File JavaDoc f = m_dataPath [p];
109                 final String JavaDoc nonexistent = f.exists () ? "" : "{nonexistent} ";
110                 
111                 log.verbose (" " + nonexistent + f.getAbsolutePath ());
112             }
113             log.verbose ("}");
114         }
115         else
116         {
117             log.info ("processing input files ...");
118         }
119         
120         // get the data out settings:
121
File JavaDoc sdataOutFile = m_sdataOutFile;
122         {
123             if (sdataOutFile == null)
124                 sdataOutFile = new File JavaDoc (toolProperties.getProperty (EMMAProperties.PROPERTY_SESSION_DATA_OUT_FILE,
125                                                                      EMMAProperties.DEFAULT_SESSION_DATA_OUT_FILE));
126         }
127                 
128         RuntimeException JavaDoc failure = null;
129         try
130         {
131             IMetaData mdata = null;
132             ICoverageData cdata = null;
133             
134             // merge all data files:
135
try
136             {
137                 final long start = log.atINFO () ? System.currentTimeMillis () : 0;
138                 
139                 for (int f = 0; f < m_dataPath.length; ++ f)
140                 {
141                     final File JavaDoc dataFile = m_dataPath [f];
142                     if (verbose) log.verbose ("processing input file [" + dataFile.getAbsolutePath () + "] ...");
143                     
144                     final IMergeable [] fileData = DataFactory.load (dataFile);
145                     
146                     final IMetaData _mdata = (IMetaData) fileData [DataFactory.TYPE_METADATA];
147                     if (_mdata != null)
148                     {
149                         if (verbose) log.verbose (" loaded " + _mdata.size () + " metadata entries");
150                         
151                         if (mdata == null)
152                             mdata = _mdata;
153                         else
154                             mdata = (IMetaData) mdata.merge (_mdata); // note: later datapath entries override earlier ones
155
}
156                     
157                     final ICoverageData _cdata = (ICoverageData) fileData [DataFactory.TYPE_COVERAGEDATA];
158                     if (_cdata != null)
159                     {
160                         if (verbose) log.verbose (" loaded " + _cdata.size () + " coverage data entries");
161                         
162                         if (cdata == null)
163                             cdata = _cdata;
164                         else
165                             cdata = (ICoverageData) cdata.merge (_cdata); // note: later datapath entries override earlier ones
166
}
167                     
168                     ++ m_dataFileCount;
169                 }
170                 
171                 if (log.atINFO ())
172                 {
173                     final long end = System.currentTimeMillis ();
174                     
175                     log.info (m_dataFileCount + " file(s) read and merged in " + (end - start) + " ms");
176                 }
177                 
178                 if (((mdata == null) || mdata.isEmpty ()) && ((cdata == null) || cdata.isEmpty ()))
179                 {
180                     log.warning ("nothing to do: no metadata or coverage data found in any of the input files");
181                     
182                     // TODO: throw exception or exit quietly?
183
return;
184                 }
185             }
186             catch (IOException JavaDoc ioe)
187             {
188                 // TODO: handle
189
ioe.printStackTrace (System.out);
190             }
191             
192
193             if (verbose)
194             {
195                 if (mdata != null)
196                 {
197                     log.verbose (" merged metadata contains " + mdata.size () + " entries");
198                 }
199                 
200                 if (cdata != null)
201                 {
202                     log.verbose (" merged coverage data contains " + cdata.size () + " entries");
203                 }
204             }
205             
206             // write merged data into output file:
207
{
208                 $assert.ASSERT (sdataOutFile != null, "sdataOutFile not null");
209                     
210                 // the case of the output file being one of the input files is
211
// supported; however, for safety reasons we create output in
212
// a temp file and rename it only when the data is safely persisted:
213

214                 boolean rename = false;
215                 File JavaDoc tempDataOutFile = null;
216                 
217                 final File JavaDoc canonicalDataOutFile = Files.canonicalizeFile (sdataOutFile);
218                 
219                 for (int f = 0; f < m_dataPath.length; ++ f)
220                 {
221                     final File JavaDoc canonicalDataFile = Files.canonicalizeFile (m_dataPath [f]);
222                     if (canonicalDataOutFile.equals (canonicalDataFile))
223                     {
224                         rename = true;
225                         break;
226                     }
227                 }
228                 
229                 if (rename) // create a temp out file
230
{
231                     File JavaDoc tempFileDir = canonicalDataOutFile.getParentFile ();
232                     if (tempFileDir == null) tempFileDir = new File JavaDoc ("");
233                     
234                     // length > 3:
235
final String JavaDoc tempFileName = Files.getFileName (canonicalDataOutFile) + IAppConstants.APP_NAME_LC;
236                     final String JavaDoc tempFileExt = EMMAProperties.PROPERTY_TEMP_FILE_EXT;
237                 
238                     try
239                     {
240                         tempDataOutFile = Files.createTempFile (tempFileDir, tempFileName, tempFileExt);
241                     }
242                     catch (IOException JavaDoc ioe)
243                     {
244                         // TODO: error code
245
throw new EMMARuntimeException (ioe);
246                     }
247                     
248                     log.warning ("the specified output file is one of the input files [" + canonicalDataOutFile + "]");
249                     log.warning ("all merged data will be written to a temp file first [" + tempDataOutFile.getAbsolutePath () + "]");
250                 }
251                 
252                 // persist merged session data:
253
{
254                     final long start = log.atINFO () ? System.currentTimeMillis () : 0;
255                     
256                     File JavaDoc persistFile = null;
257                     try
258                     {
259                         persistFile = tempDataOutFile != null ? tempDataOutFile : canonicalDataOutFile;
260                         
261                         // TODO: the persister API is ugly, redesign
262

263                         if ((mdata == null) || mdata.isEmpty ())
264                             DataFactory.persist (cdata, persistFile, false); // never merge to enforce compaction behavior
265
else if ((cdata == null) || cdata.isEmpty ())
266                             DataFactory.persist (mdata, persistFile, false); // never merge to enforce compaction behavior
267
else
268                             DataFactory.persist (new SessionData (mdata, cdata), persistFile, false); // never merge to enforce compaction behavior
269
}
270                     catch (IOException JavaDoc ioe)
271                     {
272                         if (persistFile != null) persistFile.delete ();
273                         
274                         // TODO: error code
275
throw new EMMARuntimeException (ioe);
276                     }
277                     catch (Error JavaDoc e)
278                     {
279                         if (persistFile != null) persistFile.delete ();
280                         
281                         throw e; // re-throw
282
}
283                     
284                     if (rename) // rename-with-delete temp out file into the desired out file
285
{
286                         if (! Files.renameFile (tempDataOutFile, canonicalDataOutFile, true)) // overwrite the original archive
287
{
288                             // error code
289
throw new EMMARuntimeException ("could not rename temporary file [" + tempDataOutFile.getAbsolutePath () + "] to [" + canonicalDataOutFile + "]: make sure the original file is not locked and can be deleted");
290                         }
291                     }
292                     
293                     if (log.atINFO ())
294                     {
295                         final long end = System.currentTimeMillis ();
296                         
297                         log.info ("merged/compacted data written to [" + canonicalDataOutFile + "] {in " + (end - start) + " ms}");
298                     }
299                 }
300             }
301         }
302         catch (SecurityException JavaDoc se)
303         {
304             failure = new EMMARuntimeException (SECURITY_RESTRICTION, new String JavaDoc [] {IAppConstants.APP_NAME}, se);
305         }
306         catch (RuntimeException JavaDoc re)
307         {
308             failure = re;
309         }
310         finally
311         {
312             reset ();
313         }
314         
315         if (failure != null)
316         {
317             if (Exceptions.unexpectedFailure (failure, EXPECTED_FAILURES))
318             {
319                 throw new EMMARuntimeException (UNEXPECTED_FAILURE,
320                                                 new Object JavaDoc [] {failure.toString (), IAppConstants.APP_BUG_REPORT_LINK},
321                                                 failure);
322             }
323             else
324                 throw failure;
325         }
326     }
327
328
329     // package: ...............................................................
330

331     // private: ...............................................................
332

333     
334     private MergeProcessor ()
335     {
336         m_dataPath = IConstants.EMPTY_FILE_ARRAY;
337     }
338     
339     
340     private void reset ()
341     {
342         m_dataFileCount = 0;
343     }
344     
345     
346     // caller-settable state [scoped to this runner instance]:
347

348     private File JavaDoc [] m_dataPath; // required to be non-null for run() [is set to canonicalized form]
349
private File JavaDoc m_sdataOutFile; // user override; can be null for run()
350

351     // internal run()-scoped state:
352

353     private int m_dataFileCount;
354     
355     private static final Class JavaDoc [] EXPECTED_FAILURES; // set in <clinit>
356

357     static
358     {
359         EXPECTED_FAILURES = new Class JavaDoc []
360         {
361             EMMARuntimeException.class,
362             IllegalArgumentException JavaDoc.class,
363             IllegalStateException JavaDoc.class,
364         };
365     }
366
367 } // end of class
368
// ----------------------------------------------------------------------------
Popular Tags