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: AppRunner.java,v 1.1.1.1.2.2 2004/07/16 23:32:03 vlad_r Exp $
8f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project */
9f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectpackage com.vladium.emma.rt;
10f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
11f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.File;
12f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.lang.reflect.InvocationTargetException;
13f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.lang.reflect.Method;
14f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.net.MalformedURLException;
15f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.util.HashMap;
16f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.util.Iterator;
17f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.util.ArrayList;
18f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.util.List;
19f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.util.Map;
20f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
21f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.logging.Logger;
22f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.util.Files;
23f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.util.IConstants;
24f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.util.IProperties;
25f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.util.Property;
26f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.util.SoftValueMap;
27f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.util.Strings;
28f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.util.asserts.$assert;
29f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.util.exception.Exceptions;
30f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.util.exit.ExitHookManager;
31f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.AppLoggers;
32f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.IAppConstants;
33f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.IAppErrorCodes;
34f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.EMMAProperties;
35f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.EMMARuntimeException;
36f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.Processor;
37f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.filter.IInclExclFilter;
38f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.data.CoverageOptionsFactory;
39f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.data.IMetaData;
40f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.data.ICoverageData;
41f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.data.DataFactory;
42f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.data.ISessionData;
43f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.data.SessionData;
44f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.report.AbstractReportGenerator;
45f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.report.IReportGenerator;
46f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.report.SourcePathCache;
47f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
48f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project// ----------------------------------------------------------------------------
49f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project/**
50f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * @author Vlad Roubtsov, (C) 2003
51f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project */
52f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectpublic
53f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectfinal class AppRunner extends Processor
54f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                      implements IAppErrorCodes
55f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project{
56f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // public: ................................................................
57f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
58f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
59f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static AppRunner create (final ClassLoader delegate)
60f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
61f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        return new AppRunner (delegate);
62f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
63f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
64f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
65f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public synchronized void run ()
66f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
67f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        validateState ();
68f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
69f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // disable Runtime's own exit hook:
70f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        RTSettings.setStandaloneMode (false); // an optimization to disable RT's static init code [this line must precede any reference to RT]
71f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        RT.reset (true, false); // reset RT [RT creates 'cdata' and loads app properties]
72f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
73f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // load tool properties:
74f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final IProperties toolProperties;
75f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
76f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            IProperties appProperties = RT.getAppProperties (); // try to use app props consistent with RT's view of them
77f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (appProperties == null) appProperties = EMMAProperties.getAppProperties (); // don't use combine()
78f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
79f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            toolProperties = IProperties.Factory.combine (m_propertyOverrides, appProperties);
80f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
81f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if ($assert.ENABLED) $assert.ASSERT (toolProperties != null, "toolProperties is null"); // can be empty, though
82f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
83f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final Logger current = Logger.getLogger ();
84f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final Logger log = AppLoggers.create (m_appName, toolProperties, current);
85f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
86f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (log.atTRACE1 ())
87f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
88f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            log.trace1 ("run", "complete tool properties:");
89f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            toolProperties.list (log.getWriter ());
90f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
91f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
92f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        try
93f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
94f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            Logger.push (log);
95f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_log = log;
96f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
97f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            _run (toolProperties);
98f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
99f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        finally
100f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
101f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (m_log != null)
102f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
103f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                Logger.pop (m_log);
104f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                m_log = null;
105f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
106f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
107f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
108f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
109f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
110f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
111f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param path [null is equivalent to empty array]
112f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param canonical
113f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
114f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public synchronized void setCoveragePath (String [] path, final boolean canonical)
115f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
116f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if ((path == null) || (path.length == 0))
117f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_coveragePath = IConstants.EMPTY_FILE_ARRAY;
118f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else
119f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_coveragePath = Files.pathToFiles (path, canonical);
120f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
121f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        m_canonical = canonical;
122f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
123f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
124f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public synchronized void setScanCoveragePath (final boolean scan)
125f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
126f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        m_scanCoveragePath = scan;
127f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
128f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
129f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
130f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param path [null is equivalent to no source path]
131f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
132f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public synchronized void setSourcePath (final String [] path)
133f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
134f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (path == null)
135f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_sourcePath = null;
136f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else
137f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_sourcePath = Files.pathToFiles (path, true); // always canonicalize source path
138f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
139f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
140f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
141f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
142f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param specs [null is equivalent to no filtering (everything is included)]
143f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
144f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public synchronized final void setInclExclFilter (final String [] specs)
145f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
146f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (specs == null)
147f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_coverageFilter = null;
148f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else
149f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_coverageFilter = IInclExclFilter.Factory.create (specs);
150f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
151f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
152f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
153f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
154f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param className [may not be null or empty]
155f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param args [null is equivalent to an empty array]
156f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
157f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public synchronized void setAppClass (final String className, final String [] args)
158f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
159f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if ((className == null) || (className.length () == 0))
160f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            throw new IllegalArgumentException ("null/empty input: className");
161f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
162f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (args != null)
163f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
164f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final String [] _args = (String []) args.clone ();
165f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
166f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            for (int a = 0; a < _args.length; ++ a)
167f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (_args [a] == null) throw new IllegalArgumentException ("null input: args[" + a + "]");
168f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
169f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_appArgs = _args;
170f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
171f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else
172f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
173f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_appArgs = IConstants.EMPTY_STRING_ARRAY;
174f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
175f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
176f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        m_appClassName = className;
177f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
178f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
179f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public synchronized void setDumpSessionData (final boolean dump)
180f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
181f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        m_dumpSessionData = dump;
182f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
183f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
184f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
185f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
186f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param fileName [null unsets the previous override setting]
187f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
188f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public synchronized final void setSessionOutFile (final String fileName)
189f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
190f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (fileName == null)
191f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_sdataOutFile = null;
192f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else
193f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
194f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final File _file = new File (fileName);
195f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
196f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (_file.exists () && ! _file.isFile ())
197f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                throw new IllegalArgumentException ("not a file: [" + _file.getAbsolutePath () + "]");
198f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
199f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_sdataOutFile = _file;
200f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
201f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
202f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
203f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
204f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
205f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param merge [null unsets the previous override setting]
206f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
207f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public synchronized final void setSessionOutMerge (final Boolean merge)
208f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
209f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        m_sdataOutMerge = merge;
210f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
211f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
212f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /**
213f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     *
214f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * @param types [may not be null]
215f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
216f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public synchronized void setReportTypes (final String [] types)
217f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
218f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (types == null) throw new IllegalArgumentException ("null input: types");
219f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
220f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final String [] reportTypes = Strings.removeDuplicates (types, true);
221f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (reportTypes.length == 0) throw new IllegalArgumentException ("empty input: types");
222f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
223f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if ($assert.ENABLED) $assert.ASSERT (reportTypes != null && reportTypes.length  > 0);
224f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
225f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
226f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final IReportGenerator [] reportGenerators = new IReportGenerator [reportTypes.length];
227f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        for (int t = 0; t < reportTypes.length; ++ t)
228f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
229f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            reportGenerators [t] = AbstractReportGenerator.create (reportTypes [t]);
230f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
231f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
232f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        m_reportGenerators = reportGenerators;
233f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
234f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
235f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // protected: .............................................................
236f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
237f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
238f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    protected void validateState ()
239f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
240f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        super.validateState ();
241f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
242f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if ((m_appClassName == null) || (m_appClassName.length () == 0))
243f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            throw new IllegalStateException ("application class name not set");
244f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
245f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (m_appArgs == null)
246f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            throw new IllegalStateException ("application arguments not set");
247f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
248f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (m_coveragePath == null)
249f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            throw new IllegalStateException ("coverage path not set");
250f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
251f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // [m_coverageFilter can be null]
252f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
253f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // [m_sdataOutFile can be null]
254f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // [m_sdataOutMerge can be null]
255f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
256f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if ((m_reportGenerators == null) || (m_reportGenerators.length == 0))
257f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            throw new IllegalStateException ("report types not set");
258f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
259f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // [m_sourcePath can be null/empty]
260f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
261f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // [m_propertyOverrides can be null]
262f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
263f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
264f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
265f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    protected void _run (final IProperties toolProperties)
266f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
267f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final Logger log = m_log;
268f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
269f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final boolean verbose = log.atVERBOSE ();
270f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (verbose)
271f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
272f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            log.verbose (IAppConstants.APP_VERBOSE_BUILD_ID);
273f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
274f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // [assertion: m_coveragePath != null]
275f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            log.verbose ("coverage path:");
276f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            log.verbose ("{");
277f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            for (int p = 0; p < m_coveragePath.length; ++ p)
278f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
279f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                final File f = m_coveragePath [p];
280f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                final String nonexistent = f.exists () ? "" : "{nonexistent} ";
281f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
282f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                log.verbose ("  " + nonexistent + f.getAbsolutePath ());
283f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
284f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            log.verbose ("}");
285f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
286f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if ((m_sourcePath == null) || (m_sourcePath.length == 0))
287f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
288f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                log.verbose ("source path not set");
289f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
290f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            else
291f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
292f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                log.verbose ("source path:");
293f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                log.verbose ("{");
294f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                for (int p = 0; p < m_sourcePath.length; ++ p)
295f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
296f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final File f = m_sourcePath [p];
297f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final String nonexistent = f.exists () ? "" : "{nonexistent} ";
298f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
299f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    log.verbose ("  " + nonexistent + f.getAbsolutePath ());
300f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
301f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                log.verbose ("}");
302f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
303f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
304f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
305f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // get the data out settings [note: this is not conditioned on m_dumpRawData]:
306f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        File sdataOutFile = m_sdataOutFile;
307f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        Boolean sdataOutMerge = m_sdataOutMerge;
308f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
309f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (sdataOutFile == null)
310f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                sdataOutFile = new File (toolProperties.getProperty (EMMAProperties.PROPERTY_SESSION_DATA_OUT_FILE,
311f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                                                     EMMAProperties.DEFAULT_SESSION_DATA_OUT_FILE));
312f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
313f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (sdataOutMerge == null)
314f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
315f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                final String _dataOutMerge = toolProperties.getProperty (EMMAProperties.PROPERTY_SESSION_DATA_OUT_MERGE,
316f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                                                         EMMAProperties.DEFAULT_SESSION_DATA_OUT_MERGE.toString ());
317f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                sdataOutMerge = Property.toBoolean (_dataOutMerge) ? Boolean.TRUE : Boolean.FALSE;
318f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
319f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
320f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
321f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (verbose && m_dumpSessionData)
322f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
323f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            log.verbose ("session data output file: " + sdataOutFile.getAbsolutePath ());
324f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            log.verbose ("session data output merge mode: " + sdataOutMerge);
325f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
326f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
327f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // get instr class loader delegation filter settings:
328f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final IInclExclFilter forcedDelegationFilter
329f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            = IInclExclFilter.Factory.create (toolProperties.getProperty (InstrClassLoader.PROPERTY_FORCED_DELEGATION_FILTER),
330f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                              COMMA_DELIMITERS, FORCED_DELEGATION_FILTER_SPECS);
331f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final IInclExclFilter throughDelegationFilter
332f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            = IInclExclFilter.Factory.create (toolProperties.getProperty (InstrClassLoader.PROPERTY_THROUGH_DELEGATION_FILTER),
333f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                              COMMA_DELIMITERS, null);
334f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
335f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
336f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // TODO: consider injecting Runtime straight into appLoader namespace...
337f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // TODO: create a thread group for all exit hooks?
338f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
339f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
340f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // get a handle to exit hook manager singleton:
341f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        ExitHookManager runnerExitHookManager = null;
342f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        try
343f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
344f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            runnerExitHookManager = ExitHookManager.getSingleton (); // can throw
345f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
346f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        catch (Exception e)
347f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
348f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // TODO: log/handle/warn
349f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            e.printStackTrace (System.out);
350f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
351f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
352f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        AppRunnerExitHook runnerExitHook = null;
353f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        RuntimeException failure = null;
354f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
355f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        try
356f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
357f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            SourcePathCache srcpathCache = null;
358f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (m_sourcePath != null) srcpathCache = new SourcePathCache (m_sourcePath, true); // ignore non-existent source dirs
359f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
360f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // create session data containers:
361f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            ICoverageData cdata = RT.getCoverageData ();
362f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if ($assert.ENABLED) $assert.ASSERT (cdata != null, "cdata is null");
363f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
364f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            IMetaData mdata = DataFactory.newMetaData (CoverageOptionsFactory.create (toolProperties));
365f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
366f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            runnerExitHook = new AppRunnerExitHook (log, m_dumpSessionData, sdataOutFile, sdataOutMerge.booleanValue (), mdata, cdata, m_reportGenerators, srcpathCache, toolProperties);
367f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
368f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (runnerExitHookManager != null)
369f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                runnerExitHookManager.addExitHook (runnerExitHook);
370f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
371f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // --------------[ start of exit hook-protected section ]--------------
372f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
373f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            Map classIOCache = null;
374f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
375f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // scan the classpath to populate the initial metadata:
376f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (m_scanCoveragePath)
377f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
378f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (USE_SOFT_CACHE)
379f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    classIOCache = new SoftValueMap (INIT_CACHE_CAPACITY, 0.75F, SOFT_CACHE_READ_CHK_FREQUENCY, SOFT_CACHE_WRITE_CHK_FREQUENCY);
380f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                else
381f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    classIOCache = new HashMap (INIT_CACHE_CAPACITY, 0.75F);
382f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
383f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                final ClassPathProcessorST processor = new ClassPathProcessorST (m_coveragePath, m_canonical, mdata, m_coverageFilter, classIOCache);
384f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
385f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // with a bit of work [ClassPathProcessorST needs to lock on the
386f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // metadata, etc] this could be run concurrently with the app
387f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // itself to improve perceived performance, however, I am not
388f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // going to invest time in this;
389f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
390f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // populate 'cache' [optional] and 'mdata':
391f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                processor.run ();
392f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
393f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (log.atTRACE1 ())
394f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
395f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    log.trace1 ("run", "class cache size after cp scan: " + classIOCache.size ());
396f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    log.trace1 ("run", "metadata size after cp scan: " + mdata.size ());
397f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
398f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
399f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
400f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
401f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // app runner does not need these handles anymore [only the exit hook runner maintains them]:
402f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            srcpathCache = null;
403f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            cdata = null;
404f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
405f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final ClassLoader appLoader;
406f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
407f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                final IClassLoadHook loadHook = new InstrClassLoadHook (m_coverageFilter, mdata);
408f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
409f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                try
410f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
411f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    appLoader = new InstrClassLoader (m_delegate, m_coveragePath, forcedDelegationFilter, throughDelegationFilter, loadHook, classIOCache);
412f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
413f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                catch (SecurityException se)
414f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
415f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    throw new EMMARuntimeException (SECURITY_RESTRICTION, new String [] {IAppConstants.APP_NAME}, se);
416f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
417f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                catch (MalformedURLException mue)
418f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
419f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    throw new EMMARuntimeException (mue);
420f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
421f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
422f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
423f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // app runner does not need these handles anymore:
424f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            mdata = null;
425f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            classIOCache = null;
426f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
427f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
428f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final ClassLoader contextLoader;
429f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            boolean contextLoaderSet = false;
430f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (SET_CURRENT_CONTEXT_LOADER)
431f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
432f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                try
433f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
434f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final Thread currentThread = Thread.currentThread ();
435f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
436f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    // TODO: rethink if this is the right place to do this
437f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    contextLoader = currentThread.getContextClassLoader ();
438f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    currentThread.setContextClassLoader (appLoader);
439f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
440f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    contextLoaderSet = true;
441f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
442f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                catch (SecurityException se)
443f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
444f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    throw new EMMARuntimeException (SECURITY_RESTRICTION, new String [] {IAppConstants.APP_NAME}, se);
445f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
446f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
447f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
448f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
449f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            ThreadGroup appThreadGroup = null;
450f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            try
451f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
452f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // load [and possibly initialize] the app class:
453f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
454f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                final Class appClass;
455f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                try
456f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
457f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    // load [and force early initialization if INIT_AT_LOAD_TIME is 'true']:
458f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    appClass = Class.forName (m_appClassName, INIT_AT_LOAD_TIME, appLoader);
459f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
460f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                catch (ClassNotFoundException cnfe)
461f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
462f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    // TODO: dump the classloader tree into the error message as well
463f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    throw new EMMARuntimeException (MAIN_CLASS_NOT_FOUND, new String [] {m_appClassName}, cnfe);
464f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
465f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                catch (ExceptionInInitializerError eiie) // this should not happen for INIT_AT_LOAD_TIME=false
466f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
467f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final Throwable cause = eiie.getException ();
468f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
469f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    throw new EMMARuntimeException (MAIN_CLASS_LOAD_FAILURE, new String [] {m_appClassName, cause.toString ()}, cause);
470f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
471f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                catch (Throwable t)
472f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
473f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    throw new EMMARuntimeException (MAIN_CLASS_NOT_FOUND, new String [] {m_appClassName}, t);
474f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
475f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
476f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // ensure that the app is bootstrapped using appLoader:
477f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
478f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final ClassLoader actualLoader = appClass.getClassLoader ();
479f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (actualLoader != appLoader)
480f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
481f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        final String loaderName = actualLoader != null ?  actualLoader.getClass ().getName () : "<PRIMORDIAL>";
482f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
483f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        throw new EMMARuntimeException (MAIN_CLASS_BAD_DELEGATION, new String [] {IAppConstants.APP_NAME, m_appClassName, loaderName});
484f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
485f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
486f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
487f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // run the app's main():
488f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
489f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                final Method appMain;
490f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                try
491f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
492f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    // this causes initialization on some non-Sun-compatible JVMs [ignore]:
493f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    appMain = appClass.getMethod ("main", MAIN_TYPE); // Sun JVMs do not seem to require the method to be declared
494f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
495f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                catch (Throwable t)
496f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
497f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    throw new EMMARuntimeException (MAIN_METHOD_NOT_FOUND, new String [] {m_appClassName}, t);
498f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
499f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
500f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                Invoker invoker = new Invoker (appMain, null, new Object [] {m_appArgs});
501f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
502f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                appThreadGroup = new ThreadGroup (IAppConstants.APP_NAME + " thread group [" + m_appClassName + "]");
503f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                appThreadGroup.setDaemon (true);
504f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
505f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                Thread appThread = new Thread (appThreadGroup, invoker, IAppConstants.APP_NAME + " main() thread");
506f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                appThread.setContextClassLoader (appLoader);
507f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
508f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // --- [app start] ----
509f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
510f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                appThread.start ();
511f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
512f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                try {appThread.join (); } catch (InterruptedException ignore) {}
513f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                appThread = null;
514f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
515f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                joinNonDeamonThreads (appThreadGroup);
516f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
517f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // --- [app end] ----
518f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
519f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (log.atTRACE1 ())
520f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
521f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (appLoader instanceof InstrClassLoader) ((InstrClassLoader) appLoader).debugDump (log.getWriter ());
522f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
523f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
524f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                final Throwable mainFailure = invoker.getFailure ();
525f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                invoker = null;
526f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
527f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (mainFailure != null)
528f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
529f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (mainFailure instanceof InvocationTargetException)
530f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
531f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        final Throwable cause = ((InvocationTargetException) mainFailure).getTargetException ();
532f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
533f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        throw new EMMARuntimeException (MAIN_METHOD_FAILURE, new String [] {m_appClassName, cause.toString ()}, cause);
534f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
535f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    else if (mainFailure instanceof ExceptionInInitializerError)
536f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
537f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        // this catch block is never entered if INIT_AT_LOAD_TIME is 'true'
538f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        final Throwable cause = ((ExceptionInInitializerError) mainFailure).getException ();
539f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
540f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        throw new EMMARuntimeException (MAIN_METHOD_FAILURE, new String [] {m_appClassName, cause.toString ()}, cause);
541f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
542f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    else if ((mainFailure instanceof IllegalAccessException)   ||
543f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                             (mainFailure instanceof IllegalArgumentException) ||
544f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                             (mainFailure instanceof NullPointerException))
545f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
546f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        throw new EMMARuntimeException (MAIN_METHOD_NOT_FOUND, new String [] {m_appClassName}, mainFailure);
547f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
548f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    else
549f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
550f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        throw new EMMARuntimeException (MAIN_METHOD_FAILURE, new String [] {m_appClassName, mainFailure.toString ()}, mainFailure);
551f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
552f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
553f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
554f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            catch (SecurityException se)
555f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
556f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                throw new EMMARuntimeException (SECURITY_RESTRICTION, new String [] {IAppConstants.APP_NAME}, se);
557f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
558f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            finally
559f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
560f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (SET_CURRENT_CONTEXT_LOADER && contextLoaderSet)
561f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
562f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    try
563f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
564f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        Thread.currentThread ().setContextClassLoader (contextLoader);
565f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
566f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    catch (Throwable ignore) {}
567f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
568f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
569f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if ((appThreadGroup != null) && ! appThreadGroup.isDestroyed ())
570f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                try
571f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
572f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    appThreadGroup.destroy ();
573f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    appThreadGroup = null;
574f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
575f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                catch (Throwable ignore) {}
576f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
577f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
578f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        catch (RuntimeException re)
579f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
580f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            failure = re; // should be EMMARuntimeException only if there are no errors above
581f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
582f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        finally
583f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
584f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            RT.reset (false, false);
585f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
586f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
587f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if ($assert.ENABLED) $assert.ASSERT (runnerExitHook != null, "reportExitHook = null");
588f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        runnerExitHook.run (); // that this may be a noop (if the shutdown sequence got there first)
589f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
590f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // [assertion: the report exit hook is done]
591f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
592f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (runnerExitHookManager != null)
593f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
594f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            runnerExitHookManager.removeExitHook (runnerExitHook); // Ok if this fails
595f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            runnerExitHookManager = null;
596f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
597f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
598f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // ---------------[ end of exit hook-protected section ]---------------
599f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
600f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
601f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final Throwable exitHookDataDumpFailure = runnerExitHook.getDataDumpFailure ();
602f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final List /* Throwable */ exitHookReportFailures = runnerExitHook.getReportFailures ();
603f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        runnerExitHook = null;
604f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
605f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (failure != null) // 'failure' takes precedence over any possible exit hook's problems
606f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
607f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            throw wrapFailure (failure);
608f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
609f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else if ((exitHookDataDumpFailure != null) || (exitHookReportFailures != null))
610f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
611f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (exitHookDataDumpFailure != null)
612f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                log.log (Logger.SEVERE, "exception while persisting raw session data:", exitHookDataDumpFailure);
613f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
614f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            Throwable firstReportFailure = null;
615f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (exitHookReportFailures != null)
616f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
617f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                for (Iterator i = exitHookReportFailures.iterator (); i.hasNext (); )
618f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
619f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final Throwable reportFailure = (Throwable) i.next ();
620f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (firstReportFailure == null) firstReportFailure = reportFailure;
621f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
622f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    log.log (Logger.SEVERE, "exception while creating a report:", reportFailure);
623f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
624f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
625f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
626f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (exitHookDataDumpFailure != null)
627f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                throw wrapFailure (exitHookDataDumpFailure);
628f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            else if (firstReportFailure != null) // redundant check
629f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                throw wrapFailure (firstReportFailure);
630f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
631f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
632f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
633f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
634f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // package: ...............................................................
635f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
636f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // private: ...............................................................
637f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
638f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
639f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final class Invoker implements Runnable
640f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
641f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        Invoker (final Method method, final Object target, final Object [] args)
642f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
643f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (method == null) throw new IllegalArgumentException ("null input: method");
644f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (args == null) throw new IllegalArgumentException ("null input: args");
645f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
646f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_method = method;
647f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_target = target;
648f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_args = args;
649f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
650f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
651f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        public void run ()
652f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
653f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            try
654f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
655f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                m_method.invoke (m_target, m_args);
656f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
657f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            catch (Throwable t)
658f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
659f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                m_failure = t;
660f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
661f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
662f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
663f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        Throwable getFailure ()
664f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
665f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return m_failure;
666f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
667f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
668f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
669f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        private final Method m_method;
670f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        private final Object m_target;
671f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        private final Object [] m_args;
672f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        private Throwable m_failure;
673f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
674f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    } // end of nested class
675f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
676f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
677f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final class AppRunnerExitHook implements Runnable
678f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
679f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        public synchronized void run ()
680f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
681f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            try
682f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
683f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (! m_done)
684f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
685f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    // grab data snapshots:
686f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
687f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final IMetaData mdataSnashot = m_mdata.shallowCopy ();
688f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    m_mdata = null;
689f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final ICoverageData cdataSnapshot = m_cdata.shallowCopy ();
690f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    m_cdata = null;
691f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
692f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (mdataSnashot.isEmpty ())
693f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
694f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        m_log.warning ("no metadata collected at runtime [no reports generated]");
695f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
696f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        return;
697f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
698f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
699f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (cdataSnapshot.isEmpty ())
700f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
701f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        m_log.warning ("no coverage data collected at runtime [all reports will be empty]");
702f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
703f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
704f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final ISessionData sdata = new SessionData (mdataSnashot, cdataSnapshot);
705f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
706f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    // if requested, dump raw data before running report generators:
707f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    // [note that the raw dumps and reports will be consistent wrt
708f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    // the session data they represent]
709f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
710f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (m_dumpRawData && (m_sdataOutFile != null))
711f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
712f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                       try
713f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        {
714f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            final boolean info = m_log.atINFO ();
715f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
716f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            final long start = info ? System.currentTimeMillis () : 0;
717f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            {
718f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                DataFactory.persist (sdata, m_sdataOutFile, m_sdataOutMerge);
719f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            }
720f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            if (info)
721f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            {
722f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                final long end = System.currentTimeMillis ();
723f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
724f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                m_log.info ("raw session data " + (m_sdataOutMerge ? "merged into" : "written to") + " [" + m_sdataOutFile.getAbsolutePath () + "] {in " + (end - start) + " ms}");
725f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            }
726f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        }
727f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        catch (Throwable t)
728f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        {
729f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            m_dataDumpFailure = t;
730f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        }
731f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
732f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
733f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    for (int g = 0; g < m_generators.length; ++ g)
734f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
735f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        final IReportGenerator generator = m_generators [g];
736f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
737f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        if (generator != null)
738f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        {
739f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            try
740f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            {
741f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                generator.process (mdataSnashot, cdataSnapshot, m_cache, m_properties);
742f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            }
743f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            catch (Throwable t)
744f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            {
745f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                if (m_reportFailures == null) m_reportFailures = new ArrayList ();
746f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                m_reportFailures.add (t);
747f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
748f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                continue;
749f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            }
750f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            finally
751f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            {
752f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                try { generator.cleanup (); } catch (Throwable ignore) {}
753f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                m_generators [g] = null;
754f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            }
755f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        }
756f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
757f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
758f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
759f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            finally
760f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
761f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                m_generators = null;
762f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                m_mdata = null;
763f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                m_cdata = null;
764f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                m_properties = null;
765f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                m_cache = null;
766f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
767f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                m_done = true;
768f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
769f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
770f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
771f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // note: because ExitHookManager is a lazily created static singleton the
772f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // correct thing to do is to pass an explicit Logger into each exit hook runner
773f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // instead of relying on thread inheritance:
774f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
775f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        AppRunnerExitHook (final Logger log,
776f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                           final boolean dumpRawData, final File sdataOutFile, final boolean sdataOutMerge,
777f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                           final IMetaData mdata, final ICoverageData cdata,
778f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                           final IReportGenerator [] generators,
779f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                           final SourcePathCache cache, final IProperties properties)
780f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
781f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (log == null) throw new IllegalArgumentException ("null input: log");
782f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if ((generators == null) || (generators.length == 0)) throw new IllegalArgumentException ("null/empty input: generators");
783f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (mdata == null) throw new IllegalArgumentException ("null input: mdata");
784f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (cdata == null) throw new IllegalArgumentException ("null input: cdata");
785f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (properties == null) throw new IllegalArgumentException ("null input: properties");
786f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
787f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_log = log;
788f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
789f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_dumpRawData = dumpRawData;
790f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_sdataOutFile = sdataOutFile;
791f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_sdataOutMerge = sdataOutMerge;
792f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
793f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_generators = (IReportGenerator []) generators.clone ();
794f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_mdata = mdata;
795f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_cdata = cdata;
796f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_cache = cache;
797f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_properties = properties;
798f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
799f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
800f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
801f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        synchronized Throwable getDataDumpFailure ()
802f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
803f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return m_dataDumpFailure;
804f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
805f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
806f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        synchronized List /* Throwable */ getReportFailures ()
807f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
808f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return m_reportFailures;
809f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
810f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
811f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
812f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        private final Logger m_log;
813f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        private final boolean m_dumpRawData;
814f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        private final File m_sdataOutFile;
815f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        private final boolean m_sdataOutMerge;
816f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
817f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        private IReportGenerator [] m_generators;
818f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        private IMetaData m_mdata;
819f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        private ICoverageData m_cdata;
820f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        private SourcePathCache m_cache;
821f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        private IProperties m_properties;
822f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        private boolean m_done;
823f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        private Throwable m_dataDumpFailure;
824f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        private List /* Throwable */ m_reportFailures;
825f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
826f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    } // end of nested class
827f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
828f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
829f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private AppRunner (final ClassLoader delegate)
830f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
831f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        m_delegate = delegate;
832f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        m_coveragePath = IConstants.EMPTY_FILE_ARRAY;
833f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
834f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
835f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
836f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static void joinNonDeamonThreads (final ThreadGroup group)
837f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
838f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (group == null) throw new IllegalArgumentException ("null input: group");
839f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
840f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final List threads = new ArrayList ();
841f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        while (true)
842f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
843f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            threads.clear ();
844f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
845f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // note: group.activeCount() is only an estimate as more threads
846f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // could get created while we are doing this [if 'aliveThreads'
847f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // array is too short, the extra threads are silently ignored]:
848f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
849f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            Thread [] aliveThreads;
850f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final int aliveCount;
851f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
852f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // enumerate [recursively] all threads in 'group':
853f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            synchronized (group)
854f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
855f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                aliveThreads = new Thread [group.activeCount () << 1];
856f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                aliveCount = group.enumerate (aliveThreads, true);
857f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
858f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
859f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            for (int t = 0; t < aliveCount; t++)
860f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
861f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (! aliveThreads [t].isDaemon ())
862f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    threads.add (aliveThreads [t]);
863f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
864f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            aliveThreads = null;
865f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
866f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (threads.isEmpty ())
867f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                break; // note: this logic does not work if daemon threads are spawning non-daemon ones
868f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            else
869f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
870f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                for (Iterator i = threads.iterator (); i.hasNext (); )
871f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
872f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    try
873f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
874f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        ((Thread) i.next ()).join ();
875f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
876f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    catch (InterruptedException ignore) {}
877f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
878f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
879f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
880f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
881f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
882f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static RuntimeException wrapFailure (final Throwable t)
883f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
884f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (Exceptions.unexpectedFailure (t, EXPECTED_FAILURES))
885f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return new EMMARuntimeException (UNEXPECTED_FAILURE,
886f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                            new Object [] {t.toString (), IAppConstants.APP_BUG_REPORT_LINK},
887f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                            t);
888f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else if (t instanceof RuntimeException)
889f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return (RuntimeException) t;
890f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else
891f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return new EMMARuntimeException (t);
892f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
893f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
894f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
895f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // caller-settable state [scoped to this runner instance]:
896f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
897f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private final ClassLoader m_delegate;
898f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
899f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private String m_appClassName;      // required to be non-null for run()
900f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private String [] m_appArgs;        // required to be non-null for run()
901f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
902f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private File [] m_coveragePath;     // required to be non-null/non-empty for run()
903f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private boolean m_canonical;
904f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private boolean m_scanCoveragePath;
905f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private IInclExclFilter m_coverageFilter; // can be null for run()
906f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
907f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private boolean m_dumpSessionData;
908f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private File m_sdataOutFile; // user override; can be null for run()
909f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private Boolean m_sdataOutMerge; // user override; can be null for run()
910f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
911f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private IReportGenerator [] m_reportGenerators; // required to be non-null for run()
912f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private File [] m_sourcePath;                   // can be null/empty for run()
913f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
914f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // it is attractive to detect errors at load time, but this may allow
915f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // threads created by <clinit> code to escape; on the other hand, classes
916f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // that do not override main() will not get initialized this way and will
917f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // not register with our runtime [which seems a minor problem at this point]:
918f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final boolean INIT_AT_LOAD_TIME = false;
919f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
920f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // setting the context loader on AppRunner's thread should not
921f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // be necessary since the app is run in a dedicated thread group;
922f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // however, if INIT_AT_LOAD_TIME=true the app's <clinit> code
923f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // should run with an adjusted context loader:
924f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final boolean SET_CURRENT_CONTEXT_LOADER = INIT_AT_LOAD_TIME;
925f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
926f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // a soft cache is ideal for managing class definitions that are read during
927f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // the initial classpath scan; however, the default LRU policy parameters for
928f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // clearing SoftReferences in Sun's J2SDK 1.3+ render them next to useless
929f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // in the client HotSpot JVM (in which this tool will probably run most often);
930f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // using a hard cache guarantees 100% cache hit rate but can also raise the
931f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // memory requirements significantly beyond the needs of the original app.
932f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // [see bug refs 4471453, 4806720, 4888056, 4239645]
933f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    //
934f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // resolution for now: use a soft cache anyway and doc that to make it useful
935f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // for non-trivial apps the user should use -Xms or -XX:SoftRefLRUPolicyMSPerMB
936f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // JVM options or use a server HotSpot JVM
937f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final boolean USE_SOFT_CACHE = true;
938f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
939f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final int INIT_CACHE_CAPACITY = 2003; // prime
940f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final int SOFT_CACHE_READ_CHK_FREQUENCY = 100;
941f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final int SOFT_CACHE_WRITE_CHK_FREQUENCY = 100;
942f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
943f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final String [] FORCED_DELEGATION_FILTER_SPECS; // set in <clinit>
944f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final Class [] MAIN_TYPE = new Class [] {String [].class};
945f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
946f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final Class [] EXPECTED_FAILURES; // set in <clinit>
947f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
948f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    protected static final String COMMA_DELIMITERS    = "," + Strings.WHITE_SPACE;
949f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    protected static final String PATH_DELIMITERS     = ",".concat (File.pathSeparator);
950f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
951f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    static
952f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
953f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        EXPECTED_FAILURES = new Class []
954f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
955f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            EMMARuntimeException.class,
956f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            IllegalArgumentException.class,
957f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            IllegalStateException.class,
958f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        };
959f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
960f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        FORCED_DELEGATION_FILTER_SPECS = new String [] {"+" + IAppConstants.APP_PACKAGE + ".*"};
961f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
962f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
963f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project} // end of class
964f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project// ----------------------------------------------------------------------------