File: RT.java

package info (click to toggle)
emma-coverage 2.0.5312%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd, stretch, wheezy
  • size: 2,000 kB
  • ctags: 3,667
  • sloc: java: 23,109; xml: 414; makefile: 22
file content (255 lines) | stat: -rw-r--r-- 9,561 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
 * 
 * This program and the accompanying materials are made available under
 * the terms of the Common Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/cpl-v10.html
 * 
 * $Id: RT.java,v 1.2.2.3 2004/07/16 23:32:03 vlad_r Exp $
 */
package com.vladium.emma.rt;

import java.io.File;

import com.vladium.logging.Logger;
import com.vladium.util.IProperties;
import com.vladium.util.Property;
import com.vladium.util.exit.ExitHookManager;
import com.vladium.emma.IAppConstants;
import com.vladium.emma.EMMAProperties;
import com.vladium.emma.data.ICoverageData;
import com.vladium.emma.data.DataFactory;

// ----------------------------------------------------------------------------
/**
 * @author Vlad Roubtsov, (C) 2003
 */
public
abstract class RT implements IAppConstants
{
    // public: ................................................................
    
    
    public static synchronized ICoverageData reset (final boolean createCoverageData, final boolean createExitHook)
    {
        // reload the app properties [needs to be done to accomodate classloader rearrangements]:
        
        // avoid the call context tricks at runtime in case security causes problems,
        // use an explicit caller parameter for getAppProperties():
        
        ClassLoader loader = RT.class.getClassLoader ();
        if (loader == null) loader = ClassLoader.getSystemClassLoader (); 
        
        IProperties appProperties = null;
        try
        {
            appProperties = EMMAProperties.getAppProperties (loader);
        }
        catch (Throwable t)
        {
            // TODO: handle better
            t.printStackTrace (System.out);
        }
        s_appProperties = appProperties;


        if (EXIT_HOOK_MANAGER != null)
        {
            // disable/remove the current hook, if any:
            
            if (s_exitHook != null)
            {
                 // note: no attempt is made to execute the existing hook, so its coverage
                 // data may be simply discarded
                
                EXIT_HOOK_MANAGER.removeExitHook (s_exitHook);
                s_exitHook = null;
            }
        }
        
        ICoverageData cdata = s_cdata; // no sync accessor needed
        if (createCoverageData)
        {
            cdata = DataFactory.newCoverageData ();
            s_cdata = cdata;
        }
        else
        {
            s_cdata = null;
        }
        
        if (EXIT_HOOK_MANAGER != null)
        {
            if (createExitHook && (cdata != null))
            {
                final Runnable exitHook = new RTExitHook (RT.class, cdata, getCoverageOutFile (), getCoverageOutMerge ());

                // FR SF978671: fault all classes that we might need to do coverage
                // data dumping (this forces classdefs to be loaded into classloader
                // class cache and allows output file writing to succeed even if
                // the RT classloader is some component loader (e.g, in a J2EE container)
                // that gets invalidated by the time the exit hook thread is run:
                
                RTExitHook.createClassLoaderClosure ();
                
                if (EXIT_HOOK_MANAGER.addExitHook (exitHook))
                {
                    s_exitHook = exitHook;
                }
                // else TODO: log/warn
            }
        }
        
        return cdata;
    }
    
    public static void r (final boolean [][] coverage, final String classVMName, final long stamp)
    {
        // note that we use class names, not the actual Class objects, as the keys here. This
        // is not the best possible solution because it is not capable of supporting
        // multiply (re)loaded classes within the same app, but the rest of the toolkit
        // isn't designed to support this anyway. Furthermore, this does not interfere
        // with class unloading.

        final ICoverageData cdata = getCoverageData (); // need to use accessor for JMM reasons

        // ['cdata' can be null if a previous call to dumpCoverageData() disabled data collection]
        
        if (cdata != null)
        {
            synchronized (cdata.lock ())
            {
                // TODO: could something useful be communicated back to the class
                // by returning something here [e.g., unique class ID (solves the
                // issues of class name collisions and class reloading) or RT.class
                // (to prevent RT reloading)]
                
                cdata.addClass (coverage, classVMName, stamp);
            }
        }
    }

    public static synchronized ICoverageData getCoverageData ()
    {
        return s_cdata;
    }
    
    public static synchronized IProperties getAppProperties ()
    {
        return s_appProperties;
    }
    
    /**
     * Public API for forcing coverage data dump.
     * 
     * @param outFile
     * @param merge
     * @param stopDataCollection
     */
    public static synchronized void dumpCoverageData (File outFile, final boolean merge, final boolean stopDataCollection)
    {
        if (DEBUG) System.out.println ("RT::dumpCoverageData() DUMPING " + RT.class.getClassLoader ());
        outFile = outFile != null ? outFile : getCoverageOutFile ();
        
        ICoverageData cdata = s_cdata; // no need to use accessor
        if (stopDataCollection) s_cdata = null; // TODO: log this NOTE: this does not really stop data collection, merely prevents new class registration
        
        RTCoverageDataPersister.dumpCoverageData (cdata, ! stopDataCollection, outFile, merge);
    }
    
    public static synchronized void dumpCoverageData (File outFile, final boolean stopDataCollection)
    {
        outFile = outFile != null ? outFile : getCoverageOutFile ();
        
        ICoverageData cdata = s_cdata; // no need to use accessor
        if (stopDataCollection) s_cdata = null; // TODO: log this NOTE: this does not really stop data collection, merely prevents new class registration
        
        RTCoverageDataPersister.dumpCoverageData (cdata, ! stopDataCollection, outFile, getCoverageOutMerge ());
    }
    
    // protected: .............................................................

    // package: ...............................................................

    // private: ...............................................................
    
    
    private RT () {} // prevent subclassing
    
    
    private static File getCoverageOutFile ()
    {
        final IProperties appProperties = getAppProperties (); // sync accessor
        if (appProperties != null)
        {
            final String property = appProperties.getProperty (EMMAProperties.PROPERTY_COVERAGE_DATA_OUT_FILE,
                                                               EMMAProperties.DEFAULT_COVERAGE_DATA_OUT_FILE);
            return new File (property);
        }
        
        return new File (EMMAProperties.DEFAULT_COVERAGE_DATA_OUT_FILE); 
    }
    
    private static boolean getCoverageOutMerge ()
    {
        final IProperties appProperties = getAppProperties (); // sync accessor
        if (appProperties != null)
        {
            // [Boolean.toString (boolean) is J2SDK 1.4+]
            
            final String property = appProperties.getProperty (EMMAProperties.PROPERTY_COVERAGE_DATA_OUT_MERGE,
                                                               EMMAProperties.DEFAULT_COVERAGE_DATA_OUT_MERGE.toString ());
            return Property.toBoolean (property);
        }
        
        return EMMAProperties.DEFAULT_COVERAGE_DATA_OUT_MERGE.booleanValue ();
    }
    
        
    private static ICoverageData s_cdata;
    private static Runnable s_exitHook;
    private static IProperties s_appProperties; // TODO: this is better of as java.util.Properties

    private static final ExitHookManager EXIT_HOOK_MANAGER; // set in <clinit>
    
    private static final boolean DEBUG = false;
    
    static
    {
        if (DEBUG) System.out.println ("RT[" + System.identityHashCode (RT.class) + "]::<clinit>: loaded by " + RT.class.getClassLoader ());
        
        ExitHookManager temp = null;
        try
        {
            temp = ExitHookManager.getSingleton ();
        }
        catch (Throwable t)
        {
            // TODO: handle better
            t.printStackTrace (System.out);
        }
        EXIT_HOOK_MANAGER = temp;

         
        if (RTSettings.isStandaloneMode ())
        {
            if (DEBUG) System.out.println ("RT::<clinit>: STANDALONE MODE");
            
            // load app props, create coverage data, and register an exit hook for it:
            reset (true, true);
            
            // use method-scoped loggers in RT:
            final Logger log = Logger.getLogger ();
            if (log.atINFO ())
            {
                log.info ("collecting runtime coverage data ...");
            }
        }
        else
        {
            // load app props only:
            reset (false, false);
        }
    }

} // end of class
// ----------------------------------------------------------------------------