1f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
2f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project *
3f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * This program and the accompanying materials are made available under
4f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * the terms of the Common Public License v1.0 which accompanies this distribution,
5f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * and is available at http://www.eclipse.org/legal/cpl-v10.html
6f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project *
7f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * $Id: MergeProcessor.java,v 1.1.1.1.2.2 2004/07/16 23:32:29 vlad_r Exp $
8f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project */
9f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectpackage com.vladium.emma.data;
10f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
11f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.File;
12f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.IOException;
13f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
14f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.logging.Logger;
15f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.util.Files;
16f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.util.IConstants;
17f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.util.IProperties;
18f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.util.asserts.$assert;
19f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.util.exception.Exceptions;
20f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.IAppConstants;
21f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.IAppErrorCodes;
22f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.EMMAProperties;
23f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.EMMARuntimeException;
24f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.Processor;
25f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
26f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project// ----------------------------------------------------------------------------
27f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project/*
28f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * This class was not meant to be public by design. It is made to to work around
29f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * access bugs in reflective invocations.
30f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project */
31f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project/**
32f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * @author Vlad Roubtsov, (C) 2003
33f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project */
34f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectpublic
35f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectfinal class MergeProcessor extends Processor
36f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                           implements IAppErrorCodes
37f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project{
38f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // public: ................................................................
39f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
40f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static MergeProcessor create ()
41f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
42f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        return new MergeProcessor ();
43f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
44f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
45f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
46f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
47f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param path [null is equivalent to an empty array]
48f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
49f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public synchronized final void setDataPath (final String [] path)
50f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
51f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if ((path == null) || (path.length == 0))
52f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_dataPath = IConstants.EMPTY_FILE_ARRAY;
53f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else
54f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_dataPath = Files.pathToFiles (path, true);
55f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
56f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
57f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
58f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * NOTE: there is no setter for merge attribute because this processor
59f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * always overwrites the out file [to ensure compaction]
60f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
61f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param fileName [null unsets the previous override setting]
62f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
63f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public synchronized final void setSessionOutFile (final String fileName)
64f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
65f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (fileName == null)
66f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_sdataOutFile = null;
67f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else
68f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
69f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final File _file = new File (fileName);
70f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
71f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (_file.exists () && ! _file.isFile ())
72f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                throw new IllegalArgumentException ("not a file: [" + _file.getAbsolutePath () + "]");
73f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
74f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_sdataOutFile = _file;
75f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
76f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
77f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
78f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // protected: .............................................................
79f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
80f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
81f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    protected void validateState ()
82f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
83f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        super.validateState ();
84f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
85f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (m_dataPath == null)
86f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            throw new IllegalStateException ("data path not set");
87f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
88f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // [m_sdataOutFile can be null]
89f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
90f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // [m_propertyOverrides can be null]
91f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
92f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
93f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
94f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    protected void _run (final IProperties toolProperties)
95f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
96f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final Logger log = m_log;
97f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
98f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final boolean verbose = m_log.atVERBOSE ();
99f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (verbose)
100f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
101f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            log.verbose (IAppConstants.APP_VERBOSE_BUILD_ID);
102f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
103f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // [assertion: m_dataPath != null]
104f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            log.verbose ("input data path:");
105f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            log.verbose ("{");
106f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            for (int p = 0; p < m_dataPath.length; ++ p)
107f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
108f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                final File f = m_dataPath [p];
109f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                final String nonexistent = f.exists () ? "" : "{nonexistent} ";
110f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
111f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                log.verbose ("  " + nonexistent + f.getAbsolutePath ());
112f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
113f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            log.verbose ("}");
114f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
115f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else
116f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
117f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            log.info ("processing input files ...");
118f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
119f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
120f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // get the data out settings:
121f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        File sdataOutFile = m_sdataOutFile;
122f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
123f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (sdataOutFile == null)
124f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                sdataOutFile = new File (toolProperties.getProperty (EMMAProperties.PROPERTY_SESSION_DATA_OUT_FILE,
125f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                                                     EMMAProperties.DEFAULT_SESSION_DATA_OUT_FILE));
126f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
127f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
128f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        RuntimeException failure = null;
129f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        try
130f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
131f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            IMetaData mdata = null;
132f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            ICoverageData cdata = null;
133f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
134f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // merge all data files:
135f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            try
136f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
137f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                final long start = log.atINFO () ? System.currentTimeMillis () : 0;
138f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
139f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                for (int f = 0; f < m_dataPath.length; ++ f)
140f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
141f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final File dataFile = m_dataPath [f];
142f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (verbose) log.verbose ("processing input file [" + dataFile.getAbsolutePath () + "] ...");
143f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
144f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final IMergeable [] fileData = DataFactory.load (dataFile);
145f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
146f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final IMetaData _mdata = (IMetaData) fileData [DataFactory.TYPE_METADATA];
147f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (_mdata != null)
148f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
149f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        if (verbose) log.verbose ("  loaded " + _mdata.size () + " metadata entries");
150f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
151f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        if (mdata == null)
152f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            mdata = _mdata;
153f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        else
154f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            mdata = (IMetaData) mdata.merge (_mdata); // note: later datapath entries override earlier ones
155f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
156f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
157f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final ICoverageData _cdata = (ICoverageData) fileData [DataFactory.TYPE_COVERAGEDATA];
158f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (_cdata != null)
159f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
160f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        if (verbose) log.verbose ("  loaded " + _cdata.size () + " coverage data entries");
161f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
162f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        if (cdata == null)
163f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            cdata = _cdata;
164f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        else
165f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            cdata = (ICoverageData) cdata.merge (_cdata); // note: later datapath entries override earlier ones
166f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
167f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
168f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    ++ m_dataFileCount;
169f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
170f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
171f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (log.atINFO ())
172f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
173f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final long end = System.currentTimeMillis ();
174f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
175f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    log.info (m_dataFileCount + " file(s) read and merged in " + (end - start) + " ms");
176f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
177f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
178f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (((mdata == null) || mdata.isEmpty ()) && ((cdata == null) || cdata.isEmpty ()))
179f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
180f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    log.warning ("nothing to do: no metadata or coverage data found in any of the input files");
181f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
182f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    // TODO: throw exception or exit quietly?
183f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    return;
184f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
185f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
186f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            catch (IOException ioe)
187f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
188f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // TODO: handle
189f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                ioe.printStackTrace (System.out);
190f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
191f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
192f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
193f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (verbose)
194f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
195f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (mdata != null)
196f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
197f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    log.verbose ("  merged metadata contains " + mdata.size () + " entries");
198f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
199f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
200f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (cdata != null)
201f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
202f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    log.verbose ("  merged coverage data contains " + cdata.size () + " entries");
203f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
204f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
205f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
206f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // write merged data into output file:
207f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
208f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                $assert.ASSERT (sdataOutFile != null, "sdataOutFile not null");
209f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
210f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // the case of the output file being one of the input files is
211f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // supported; however, for safety reasons we create output in
212f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // a temp file and rename it only when the data is safely persisted:
213f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
214f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                boolean rename = false;
215f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                File tempDataOutFile = null;
216f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
217f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                final File canonicalDataOutFile = Files.canonicalizeFile (sdataOutFile);
218f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
219f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                for (int f = 0; f < m_dataPath.length; ++ f)
220f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
221f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final File canonicalDataFile = Files.canonicalizeFile (m_dataPath [f]);
222f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (canonicalDataOutFile.equals (canonicalDataFile))
223f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
224f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        rename = true;
225f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        break;
226f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
227f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
228f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
229f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (rename) // create a temp out file
230f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
231f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    File tempFileDir = canonicalDataOutFile.getParentFile ();
232f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (tempFileDir == null) tempFileDir = new File ("");
233f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
234f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    // length > 3:
235f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final String tempFileName = Files.getFileName (canonicalDataOutFile) + IAppConstants.APP_NAME_LC;
236f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final String tempFileExt = EMMAProperties.PROPERTY_TEMP_FILE_EXT;
237f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
238f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    try
239f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
240f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        tempDataOutFile = Files.createTempFile (tempFileDir, tempFileName, tempFileExt);
241f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
242f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    catch (IOException ioe)
243f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
244f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        // TODO: error code
245f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        throw new EMMARuntimeException (ioe);
246f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
247f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
248f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    log.warning ("the specified output file is one of the input files [" + canonicalDataOutFile + "]");
249f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    log.warning ("all merged data will be written to a temp file first [" + tempDataOutFile.getAbsolutePath ()  + "]");
250f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
251f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
252f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // persist merged session data:
253f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
254f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final long start = log.atINFO () ? System.currentTimeMillis () : 0;
255f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
256f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    File persistFile = null;
257f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    try
258f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
259f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        persistFile = tempDataOutFile != null ? tempDataOutFile : canonicalDataOutFile;
260f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
261f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        // TODO: the persister API is ugly, redesign
262f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
263f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        if ((mdata == null) || mdata.isEmpty ())
264f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            DataFactory.persist (cdata, persistFile, false); // never merge to enforce compaction behavior
265f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        else if ((cdata == null) || cdata.isEmpty ())
266f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            DataFactory.persist (mdata, persistFile, false); // never merge to enforce compaction behavior
267f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        else
268f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            DataFactory.persist (new SessionData (mdata, cdata), persistFile, false); // never merge to enforce compaction behavior
269f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
270f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    catch (IOException ioe)
271f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
272f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        if (persistFile != null) persistFile.delete ();
273f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
274f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        // TODO: error code
275f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        throw new EMMARuntimeException (ioe);
276f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
277f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    catch (Error e)
278f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
279f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        if (persistFile != null) persistFile.delete ();
280f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
281f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        throw e; // re-throw
282f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
283f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
284f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (rename) // rename-with-delete temp out file into the desired out file
285f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
286f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        if (! Files.renameFile (tempDataOutFile, canonicalDataOutFile, true)) // overwrite the original archive
287f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        {
288f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            // error code
289f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            throw new EMMARuntimeException ("could not rename temporary file [" + tempDataOutFile.getAbsolutePath () + "] to [" + canonicalDataOutFile + "]: make sure the original file is not locked and can be deleted");
290f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        }
291f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
292f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
293f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (log.atINFO ())
294f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
295f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        final long end = System.currentTimeMillis ();
296f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
297f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        log.info ("merged/compacted data written to [" + canonicalDataOutFile + "] {in " + (end - start) + " ms}");
298f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
299f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
300f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
301f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
302f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        catch (SecurityException se)
303f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
304f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            failure = new EMMARuntimeException (SECURITY_RESTRICTION, new String [] {IAppConstants.APP_NAME}, se);
305f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
306f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        catch (RuntimeException re)
307f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
308f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            failure = re;
309f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
310f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        finally
311f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
312f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            reset ();
313f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
314f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
315f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (failure != null)
316f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
317f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (Exceptions.unexpectedFailure (failure, EXPECTED_FAILURES))
318f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
319f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                throw new EMMARuntimeException (UNEXPECTED_FAILURE,
320f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                                new Object [] {failure.toString (), IAppConstants.APP_BUG_REPORT_LINK},
321f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                                failure);
322f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
323f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            else
324f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                throw failure;
325f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
326f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
327f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
328f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
329f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // package: ...............................................................
330f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
331f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // private: ...............................................................
332f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
333f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
334f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private MergeProcessor ()
335f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
336f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        m_dataPath = IConstants.EMPTY_FILE_ARRAY;
337f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
338f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
339f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
340f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private void reset ()
341f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
342f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        m_dataFileCount = 0;
343f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
344f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
345f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
346f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // caller-settable state [scoped to this runner instance]:
347f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
348f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private File [] m_dataPath; // required to be non-null for run() [is set to canonicalized form]
349f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private File m_sdataOutFile; // user override; can be null for run()
350f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
351f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // internal run()-scoped state:
352f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
353f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private int m_dataFileCount;
354f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
355f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final Class [] EXPECTED_FAILURES; // set in <clinit>
356f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
357f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    static
358f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
359f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        EXPECTED_FAILURES = new Class []
360f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
361f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            EMMARuntimeException.class,
362f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            IllegalArgumentException.class,
363f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            IllegalStateException.class,
364f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        };
365f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
366f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
367f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project} // end of class
368f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project// ----------------------------------------------------------------------------