| /* 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: EMMAProperties.java,v 1.1.1.1.2.3 2004/07/16 23:32:03 vlad_r Exp $ |
| */ |
| package com.vladium.emma; |
| |
| import java.io.File; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.WeakHashMap; |
| |
| import com.vladium.util.ClassLoaderResolver; |
| import com.vladium.util.IProperties; |
| import com.vladium.util.Property; |
| import com.vladium.emma.report.IReportProperties; |
| import com.vladium.emma.report.ReportProperties; |
| |
| // ---------------------------------------------------------------------------- |
| /** |
| * A reflection of "${IAppConstants.APP_PROPERTY_RES_NAME}.properties" resource |
| * as viewed by a given classloader. |
| * |
| * @author Vlad Roubtsov, (C) 2003 |
| */ |
| public |
| abstract class EMMAProperties |
| { |
| // public: ................................................................ |
| |
| public static final String GENERIC_PROPERTY_OVERRIDE_PREFIX = "D"; |
| |
| // [the DEFAULT_xxx settings duplicate the defaults in APP_DEFAULT_PROPERTIES_RES_NAME |
| // resource to provide a safe fallback option if that resource cannot be loaded] |
| |
| public static final String DEFAULT_META_DATA_OUT_FILE = "coverage.em"; |
| public static final Boolean DEFAULT_META_DATA_OUT_MERGE = Boolean.TRUE; |
| public static final String PREFIX_META_DATA = "metadata."; |
| public static final String PROPERTY_META_DATA_OUT_FILE = PREFIX_META_DATA + "out.file"; |
| public static final String PROPERTY_META_DATA_OUT_MERGE = PREFIX_META_DATA + "out.merge"; |
| |
| public static final String DEFAULT_COVERAGE_DATA_OUT_FILE = "coverage.ec"; |
| public static final Boolean DEFAULT_COVERAGE_DATA_OUT_MERGE = Boolean.TRUE; |
| public static final String PREFIX_COVERAGE_DATA = "coverage."; |
| public static final String PROPERTY_COVERAGE_DATA_OUT_FILE = PREFIX_COVERAGE_DATA + "out.file"; |
| public static final String PROPERTY_COVERAGE_DATA_OUT_MERGE = PREFIX_COVERAGE_DATA + "out.merge"; |
| |
| public static final String DEFAULT_SESSION_DATA_OUT_FILE = "coverage.es"; |
| public static final Boolean DEFAULT_SESSION_DATA_OUT_MERGE = Boolean.TRUE; |
| public static final String PREFIX_SESSION_DATA = "session."; |
| public static final String PROPERTY_SESSION_DATA_OUT_FILE = PREFIX_SESSION_DATA + "out.file"; |
| public static final String PROPERTY_SESSION_DATA_OUT_MERGE = PREFIX_SESSION_DATA + "out.merge"; |
| |
| public static final String PROPERTY_TEMP_FILE_EXT = ".et"; |
| |
| public static final Map SYSTEM_PROPERTY_REDIRECTS; // set in <clinit> |
| |
| |
| /** |
| * Global method used to create an appearance that all app work has been |
| * done at the same point in time (useful for setting archive and report |
| * timestamps etc). |
| * |
| * @return the result of System.currentTimeMillis (), evaluated on the |
| * first call only |
| */ |
| public static synchronized long getTimeStamp () |
| { |
| long result = s_timestamp; |
| if (result == 0) |
| { |
| s_timestamp = result = System.currentTimeMillis (); |
| } |
| |
| return result; |
| } |
| |
| |
| public static String makeAppVersion (final int major, final int minor, final int build) |
| { |
| final StringBuffer buf = new StringBuffer (); |
| |
| buf.append (major); |
| buf.append ('.'); |
| buf.append (minor); |
| buf.append ('.'); |
| buf.append (build); |
| |
| return buf.toString (); |
| } |
| |
| |
| /** |
| * Wraps a Properties into a IProperties with the app's standard property |
| * mapping in place. |
| * |
| * @param properties [null results in null result] |
| */ |
| public static IProperties wrap (final Properties properties) |
| { |
| if (properties == null) return null; |
| |
| return IProperties.Factory.wrap (properties, ReportProperties.REPORT_PROPERTY_MAPPER); |
| } |
| |
| /** |
| * Retrieves application properties as classloader resource with a given name. |
| * [as seen from ClassLoaderResolver.getClassLoader ()]. The result is cached |
| * using this loader as a weak key. |
| * |
| * @return properties [can be null] |
| */ |
| public static synchronized IProperties getAppProperties () |
| { |
| final ClassLoader loader = ClassLoaderResolver.getClassLoader (); |
| |
| return getAppProperties (loader); |
| } |
| |
| public static synchronized IProperties getAppProperties (final ClassLoader loader) |
| { |
| IProperties properties = (IProperties) s_properties.get (loader); |
| |
| if (properties != null) |
| return properties; |
| else |
| { |
| final String appName = IAppConstants.APP_NAME_LC; |
| |
| // note: this does not use Property.getAppProperties() by design, |
| // because that mechanism is not property alias-capable |
| |
| final IProperties systemRedirects = wrap (Property.getSystemPropertyRedirects (EMMAProperties.SYSTEM_PROPERTY_REDIRECTS)); |
| final IProperties appDefaults = wrap (Property.getProperties (appName + "_default.properties", loader)); |
| final IProperties systemFile; |
| { |
| final String fileName = Property.getSystemProperty (appName + ".properties"); |
| final File file = fileName != null |
| ? new File (fileName) |
| : null; |
| |
| systemFile = wrap (Property.getLazyPropertiesFromFile (file)); |
| } |
| final IProperties system = wrap (Property.getSystemProperties (appName)); |
| final IProperties userOverrides = wrap (Property.getProperties (appName + ".properties", loader)); |
| |
| // "vertical" inheritance order: |
| // (1) user overrides ("emma.properties" classloader resource) |
| // (2) system properties (java.lang.System.getProperties(), |
| // filtered by the app prefix) |
| // (3) system file properties ("emma.properties" system property, |
| // interpreted as a property file) |
| // (4) app defaults ("emma_default.properties" classloader resource) |
| // (5) system property redirects (report.out.encoding->file.encoding, |
| // report.out.dir->user.dir, etc) |
| |
| properties = IProperties.Factory.combine (userOverrides, |
| IProperties.Factory.combine (system, |
| IProperties.Factory.combine (systemFile, |
| IProperties.Factory.combine (appDefaults, |
| systemRedirects)))); |
| |
| s_properties.put (loader, properties); |
| |
| return properties; |
| } |
| } |
| |
| // protected: ............................................................. |
| |
| // package: ............................................................... |
| |
| // private: ............................................................... |
| |
| |
| private EMMAProperties () {} // prevent subclassing |
| |
| |
| private static long s_timestamp; |
| |
| private static final Map /* ClassLoader->Properties */ s_properties; // set in <clinit> |
| |
| static |
| { |
| s_properties = new WeakHashMap (); |
| |
| final Map redirects = new HashMap (); |
| redirects.put (IReportProperties.PREFIX.concat (IReportProperties.OUT_ENCODING), |
| "file.encoding"); |
| redirects.put (IReportProperties.PREFIX.concat (IReportProperties.OUT_DIR), |
| "user.dir"); |
| |
| SYSTEM_PROPERTY_REDIRECTS = Collections.unmodifiableMap (redirects); |
| } |
| |
| } // end of class |
| // ---------------------------------------------------------------------------- |