1 /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved. 2 * 3 * This program and the accompanying materials are made available under 4 * the terms of the Common Public License v1.0 which accompanies this distribution, 5 * and is available at http://www.eclipse.org/legal/cpl-v10.html 6 * 7 * $Id: EMMAProperties.java,v 1.1.1.1.2.3 2004/07/16 23:32:03 vlad_r Exp $ 8 */ 9 package com.vladium.emma; 10 11 import java.io.File; 12 import java.util.Collections; 13 import java.util.HashMap; 14 import java.util.Map; 15 import java.util.Properties; 16 import java.util.WeakHashMap; 17 18 import com.vladium.util.ClassLoaderResolver; 19 import com.vladium.util.IProperties; 20 import com.vladium.util.Property; 21 import com.vladium.emma.report.IReportProperties; 22 import com.vladium.emma.report.ReportProperties; 23 24 // ---------------------------------------------------------------------------- 25 /** 26 * A reflection of "${IAppConstants.APP_PROPERTY_RES_NAME}.properties" resource 27 * as viewed by a given classloader. 28 * 29 * @author Vlad Roubtsov, (C) 2003 30 */ 31 public 32 abstract class EMMAProperties 33 { 34 // public: ................................................................ 35 36 public static final String GENERIC_PROPERTY_OVERRIDE_PREFIX = "D"; 37 38 // [the DEFAULT_xxx settings duplicate the defaults in APP_DEFAULT_PROPERTIES_RES_NAME 39 // resource to provide a safe fallback option if that resource cannot be loaded] 40 41 public static final String DEFAULT_META_DATA_OUT_FILE = "coverage.em"; 42 public static final Boolean DEFAULT_META_DATA_OUT_MERGE = Boolean.TRUE; 43 public static final String PREFIX_META_DATA = "metadata."; 44 public static final String PROPERTY_META_DATA_OUT_FILE = PREFIX_META_DATA + "out.file"; 45 public static final String PROPERTY_META_DATA_OUT_MERGE = PREFIX_META_DATA + "out.merge"; 46 47 public static final String DEFAULT_COVERAGE_DATA_OUT_FILE = "coverage.ec"; 48 public static final Boolean DEFAULT_COVERAGE_DATA_OUT_MERGE = Boolean.TRUE; 49 public static final String PREFIX_COVERAGE_DATA = "coverage."; 50 public static final String PROPERTY_COVERAGE_DATA_OUT_FILE = PREFIX_COVERAGE_DATA + "out.file"; 51 public static final String PROPERTY_COVERAGE_DATA_OUT_MERGE = PREFIX_COVERAGE_DATA + "out.merge"; 52 53 public static final String DEFAULT_SESSION_DATA_OUT_FILE = "coverage.es"; 54 public static final Boolean DEFAULT_SESSION_DATA_OUT_MERGE = Boolean.TRUE; 55 public static final String PREFIX_SESSION_DATA = "session."; 56 public static final String PROPERTY_SESSION_DATA_OUT_FILE = PREFIX_SESSION_DATA + "out.file"; 57 public static final String PROPERTY_SESSION_DATA_OUT_MERGE = PREFIX_SESSION_DATA + "out.merge"; 58 59 public static final String PROPERTY_TEMP_FILE_EXT = ".et"; 60 61 public static final Map SYSTEM_PROPERTY_REDIRECTS; // set in <clinit> 62 63 64 /** 65 * Global method used to create an appearance that all app work has been 66 * done at the same point in time (useful for setting archive and report 67 * timestamps etc). 68 * 69 * @return the result of System.currentTimeMillis (), evaluated on the 70 * first call only 71 */ getTimeStamp()72 public static synchronized long getTimeStamp () 73 { 74 long result = s_timestamp; 75 if (result == 0) 76 { 77 s_timestamp = result = System.currentTimeMillis (); 78 } 79 80 return result; 81 } 82 83 makeAppVersion(final int major, final int minor, final int build)84 public static String makeAppVersion (final int major, final int minor, final int build) 85 { 86 final StringBuffer buf = new StringBuffer (); 87 88 buf.append (major); 89 buf.append ('.'); 90 buf.append (minor); 91 buf.append ('.'); 92 buf.append (build); 93 94 return buf.toString (); 95 } 96 97 98 /** 99 * Wraps a Properties into a IProperties with the app's standard property 100 * mapping in place. 101 * 102 * @param properties [null results in null result] 103 */ wrap(final Properties properties)104 public static IProperties wrap (final Properties properties) 105 { 106 if (properties == null) return null; 107 108 return IProperties.Factory.wrap (properties, ReportProperties.REPORT_PROPERTY_MAPPER); 109 } 110 111 /** 112 * Retrieves application properties as classloader resource with a given name. 113 * [as seen from ClassLoaderResolver.getClassLoader ()]. The result is cached 114 * using this loader as a weak key. 115 * 116 * @return properties [can be null] 117 */ getAppProperties()118 public static synchronized IProperties getAppProperties () 119 { 120 final ClassLoader loader = ClassLoaderResolver.getClassLoader (); 121 122 return getAppProperties (loader); 123 } 124 getAppProperties(final ClassLoader loader)125 public static synchronized IProperties getAppProperties (final ClassLoader loader) 126 { 127 IProperties properties = (IProperties) s_properties.get (loader); 128 129 if (properties != null) 130 return properties; 131 else 132 { 133 final String appName = IAppConstants.APP_NAME_LC; 134 135 // note: this does not use Property.getAppProperties() by design, 136 // because that mechanism is not property alias-capable 137 138 final IProperties systemRedirects = wrap (Property.getSystemPropertyRedirects (EMMAProperties.SYSTEM_PROPERTY_REDIRECTS)); 139 final IProperties appDefaults = wrap (Property.getProperties (appName + "_default.properties", loader)); 140 final IProperties systemFile; 141 { 142 final String fileName = Property.getSystemProperty (appName + ".properties"); 143 final File file = fileName != null 144 ? new File (fileName) 145 : null; 146 147 systemFile = wrap (Property.getLazyPropertiesFromFile (file)); 148 } 149 final IProperties system = wrap (Property.getSystemProperties (appName)); 150 final IProperties userOverrides = wrap (Property.getProperties (appName + ".properties", loader)); 151 152 // "vertical" inheritance order: 153 // (1) user overrides ("emma.properties" classloader resource) 154 // (2) system properties (java.lang.System.getProperties(), 155 // filtered by the app prefix) 156 // (3) system file properties ("emma.properties" system property, 157 // interpreted as a property file) 158 // (4) app defaults ("emma_default.properties" classloader resource) 159 // (5) system property redirects (report.out.encoding->file.encoding, 160 // report.out.dir->user.dir, etc) 161 162 properties = IProperties.Factory.combine (userOverrides, 163 IProperties.Factory.combine (system, 164 IProperties.Factory.combine (systemFile, 165 IProperties.Factory.combine (appDefaults, 166 systemRedirects)))); 167 168 s_properties.put (loader, properties); 169 170 return properties; 171 } 172 } 173 174 // protected: ............................................................. 175 176 // package: ............................................................... 177 178 // private: ............................................................... 179 180 EMMAProperties()181 private EMMAProperties () {} // prevent subclassing 182 183 184 private static long s_timestamp; 185 186 private static final Map /* ClassLoader->Properties */ s_properties; // set in <clinit> 187 188 static 189 { 190 s_properties = new WeakHashMap (); 191 192 final Map redirects = new HashMap (); IReportProperties.PREFIX.concat(IReportProperties.OUT_ENCODING)193 redirects.put (IReportProperties.PREFIX.concat (IReportProperties.OUT_ENCODING), 194 "file.encoding"); IReportProperties.PREFIX.concat(IReportProperties.OUT_DIR)195 redirects.put (IReportProperties.PREFIX.concat (IReportProperties.OUT_DIR), 196 "user.dir"); 197 198 SYSTEM_PROPERTY_REDIRECTS = Collections.unmodifiableMap (redirects); 199 } 200 201 } // end of class 202 // ---------------------------------------------------------------------------- 203