All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springsource.loaded.GlobalConfiguration Maven / Gradle / Ivy

There is a newer version: 1.2.8.RELEASE
Show newest version
/*
 * Copyright 2010-2012 VMware and contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springsource.loaded;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.springsource.loaded.agent.SpringPlugin;

/**
 * Encapsulates configurable elements - these are set (to values other than the defaults) in TypeRegistry when the
 * system property springloaded configuration is processed. Some of the options are only used by testcases to make the
 * testcases easier to write and more straightforward.
 *
 * @author Andy Clement
 * @since 0.5.0
 */
public class GlobalConfiguration {

	private static Logger log = Logger.getLogger(GlobalConfiguration.class.getName());

	/**
	 * Are references to fields being modified - covering both the GETS/SETS and the reflective references.
	 */
	public final static boolean fieldRewriting = true;

	public static boolean catchersOn = true;

	/**
	 * If active, SpringLoaded will be trying to watch for types changing on the file system once they have been made
	 * reloadable.
	 */
	public static boolean fileSystemMonitoring = false;

	/**
	 * Global control for loadtime logging
	 */
	public static boolean logging = false;

	/**
	 * verbose mode can trigger extra messages. Enable with 'verbose=true'
	 */
	public static boolean verboseMode = false;

	/**
	 * asserts mode will trigger extra checking (performance impact but confirms correctness)
	 */
	public static boolean assertsMode = false;

	/**
	 * Can be turned on to enable users to determine the decision process around why something is not reloadable.
	 */
	public static boolean explainMode = false;

	/**
	 * Once a type is found to be reloadable or not (based on whether it is accessible as a .class file on the disk
	 * rather than packaged in a jar), that decision is remembered and all types from the same package are treated in
	 * the same way without repeating the costly lookup. This option enables that behaviour to be turned OFF and then
	 * you can have some files in a package that are in a jar and are not reloadable and some types that are in the same
	 * package but on disk that will be reloadable.
	 */
	public static boolean allowSplitPackages = false;

	/**
	 * Global control for runtime logging
	 */
	public static boolean isRuntimeLogging = false;

	public static boolean callsideRewritingOn = true;

	/**
	 * Allows a cache to be cleaned up as the agent starts (effectively starting with a new cache, if 'caching' is true)
	 */
	public static boolean cleanCache = false;

	/**
	 * Determine whether on disk caching will be used.
	 */
	public static boolean isCaching = false;

	public static boolean investigateSystemClassReflection = false;

	public static boolean rewriteAllSystemClasses = false;

	/**
	 * A well known profile (e.g. grails) can tweak a lot of the default options in a particular way.
	 */
	public static String profile = null;

	/**
	 * The base directory in which to create any cache (.slcache folder). If null then user.home will be used.
	 */
	public static String cacheDir = null;

	public final static boolean logNonInterceptedReflectiveCalls = false;

	/**
	 * Holds a list of fully qualified paths to jars that should be 'watched' for changes. Types within these jars will
	 * be made reloadable. Set via option 'watchJars' which takes a colon separated list of jars.
	 */
	public static String[] jarsToWatch = null;

	/**
	 * Global control for checking assertions
	 */
	public final static boolean isProfiling = false;

	public static boolean directlyDefineTypes = true;

	public final static boolean interceptReflection = true;

	// max number of values before we prevent them being reloaded (the clinit rewrite blows the codesize limit)
	public static int enumLimit = 1000;

	public static boolean reloadMessages = false;// can be forced on for testing

	/**
	 * When a reload is attempted, if this is true it will be checked to confirm it is allowed and does not violate the
	 * supported reloadable changes that can be made to a type.
	 */
	public static boolean verifyReloads = true;

	/**
	 * When classes are dumped by Utils.dump() this specifies where. A null value will cause us to dump into the default
	 * temp folder.
	 */
	public static String dumpFolder = null;

	/**
	 * Global configuration properties set based on the value of system property 'springloaded'. If null then not yet
	 * initialized (and a call to initializeFromSystemProperty()) is needed. If settings are truely once per VM, they
	 * are set directly in GlobalConfiguration whereas if they may be overridden on a per classloader level, they are
	 * set in this properties object and may be overridden by the springloaded.properties files accessible through each
	 * classloader.
	 */
	public static Properties globalConfigurationProperties;

	/**
	 * List of slashed classnames for types we should 'dump' during processing (for debugging purposes).
	 */
	public static List classesToDump;

	public static int maxClassDefinitions = 100;

	/**
	 * List of dotted classnames representing classnames of plugins that should be loaded.
	 */
	public static List pluginClassnameList;

	public final static boolean debugplugins;


	private static void printUsage() {
		System.out.println("SpringLoaded");
		System.out.println("============");
		System.out.println();
		System.out.println("Usage: java -noverify -javaagent:/springloaded.jar");
		System.out.println("Optionally specify configuration through -Dspringloaded=");
		System.out.println(" is a ';' separated list of directives or name=value options");
		System.out.println("Example: -Dspringloaded=verbose;cacheDir=/tmp");
		System.out.println();
		System.out.println("Directives:");
		System.out.println("  ? - print this usage text");
		System.out.println("  verbose - the reloader will log important lifecycle events");
		System.out.println("Options:");
		System.exit(0);
	}

	/**
	 * Look for a springloaded system property and initialize the 'default system wide' configuration based upon it.
	 * Support configuration options:
	 * 
    *
  • info - print usage information on the options *
  • verbose - this directive causes SpringLoaded to report on decisions it is making. *
*/ static { globalConfigurationProperties = new Properties(); boolean debugPlugins = false; try { boolean specifiedCaching = false; String value = System.getProperty("springloaded"); // value is a ';' separated list of configuration options which either may be name=value settings or directives (just a name) if (value != null) { StringTokenizer st = new StringTokenizer(value, ";"); while (st.hasMoreTokens()) { String kv = st.nextToken(); int equals = kv.indexOf('='); if (equals != -1) { // key=value String key = kv.substring(0, equals); // Supported settings: // dump=XX,YYY,ZZZ // - this option lists classes for which we should dump the bytecode, names are dotted if (key.equals("dump")) { String classList = kv.substring(equals + 1); StringTokenizer clSt = new StringTokenizer(classList, ","); classesToDump = new ArrayList(); while (clSt.hasMoreTokens()) { classesToDump.add(clSt.nextToken().replace('.', '/')); } if (isRuntimeLogging && log.isLoggable(Level.INFO)) { log.info("configuration: dumping: " + classesToDump); } // } else if (key.equals("interceptReflection")) { // global setting // interceptReflection = kv.substring(equals + 1).equalsIgnoreCase("true"); // if (isRuntimeLogging && log.isLoggable(Level.INFO)) { // log.info("configuration: interceptReflection = " + interceptReflection); // } } else if (key.equals("cleanCache")) { cleanCache = kv.substring(equals + 1).equalsIgnoreCase("true"); } else if (key.equals("caching")) { specifiedCaching = true; isCaching = kv.substring(equals + 1).equalsIgnoreCase("true"); } else if (key.equals("allowSplitPackages")) { allowSplitPackages = kv.substring(equals + 1).equalsIgnoreCase("true"); } else if (key.equals("debugplugins")) { debugPlugins = true; } else if (key.equals("enumlimit")) { enumLimit = toInt(kv.substring(equals + 1), enumLimit); } else if (key.equals("profile")) { profile = kv.substring(equals + 1); } else if (key.equals("cacheDir")) { cacheDir = kv.substring(equals + 1); } else if (key.equals("callsideRewritingOn")) { // global setting callsideRewritingOn = kv.substring(equals + 1).equalsIgnoreCase("true"); if (isRuntimeLogging && log.isLoggable(Level.INFO)) { log.info("configuration: callsideRewritingOn = " + callsideRewritingOn); } // } else if (key.equals("logNonInterceptedReflectiveCalls")) { // global setting // logNonInterceptedReflectiveCalls = kv.substring(equals + 1).equalsIgnoreCase("true"); // if (isRuntimeLogging && log.isLoggable(Level.INFO)) { // log.info("configuration: logNonInterceptedReflectiveCalls = " + logNonInterceptedReflectiveCalls); // } } else if (key.equals("verifyReloads")) { // global setting verifyReloads = kv.substring(equals + 1).equalsIgnoreCase("true"); if (isRuntimeLogging && log.isLoggable(Level.INFO)) { log.info("configuration: verifyReloads = " + verifyReloads); } } else if (key.equals("dumpFolder")) { // global setting dumpFolder = kv.substring(equals + 1); if (isRuntimeLogging && log.isLoggable(Level.INFO)) { log.info("configuration: dumpFolder = " + dumpFolder); } } else if (key.equals("watchJars")) { if (isRuntimeLogging && log.isLoggable(Level.INFO)) { log.info("Watching jars: " + kv.substring(equals + 1)); } jarsToWatch = kv.substring(equals + 1).split(":"); } else if (key.equals("maxClassDefinitions")) { try { maxClassDefinitions = Integer.parseInt(kv.substring(equals + 1)); if (isRuntimeLogging && log.isLoggable(Level.INFO)) { log.info("configuration: maxClassDefinitions = " + maxClassDefinitions); } } catch (NumberFormatException nfe) { System.err.println("ERROR: unable to parse " + kv.substring(equals + 1) + " as a integer"); } } else if (key.equals("logging")) { GlobalConfiguration.isRuntimeLogging = kv.substring(equals + 1).equalsIgnoreCase("true"); GlobalConfiguration.logging = kv.substring(equals + 1).equalsIgnoreCase("true"); System.out.println("Spring-Loaded logging = (" + GlobalConfiguration.isRuntimeLogging + "," + GlobalConfiguration.logging + ")"); } else if (key.equals("verbose")) { verboseMode = kv.substring(equals + 1).equalsIgnoreCase("true"); reloadMessages = verboseMode; } else if (key.equals("asserts")) { assertsMode = kv.substring(equals + 1).equalsIgnoreCase("true"); } else if (key.equals("rebasePaths")) { // value is a series of "a=b,c=d,e=f" indicating from and to globalConfigurationProperties.put("rebasePaths", kv.substring(equals + 1)); } else if (key.equals("inclusions")) { globalConfigurationProperties.put("inclusions", kv.substring(equals + 1)); } else if (key.equals("exclusions")) { globalConfigurationProperties.put("exclusions", kv.substring(equals + 1)); } else if (key.equals("plugins")) { // plugins=com.myplugin.Plugin,com.somethingelse.SomeOtherPlugin String pluginList = kv.substring(equals + 1); StringTokenizer pluginListTokenizer = new StringTokenizer(pluginList, ","); pluginClassnameList = new ArrayList(); while (pluginListTokenizer.hasMoreTokens()) { pluginClassnameList.add(pluginListTokenizer.nextToken()); } } } else { if (kv.equals("?")) { printUsage(); } else if (kv.equals("verbose")) { Log.log("[verbose mode on] Full configuration is:" + value); verboseMode = true; reloadMessages = true; } else if (kv.equals("investigateSystemClassReflection")) { investigateSystemClassReflection = true; } else if (kv.equals("rewriteAllSystemClasses")) { rewriteAllSystemClasses = true; } else if (kv.equals("asserts")) { Log.log("[asserts mode on] Will verify system coherence"); assertsMode = true; } else if (kv.equals("explain")) { Log.log("[explain mode on] Reporting on the decision making process within SpringLoaded"); explainMode = true; } } } } // Profile support. A profile is a shortcut for configuring a bunch of options if (profile != null) { if (profile.equals("grails")) { // Configure options based on a grails profile // turn on caching if we have a cacheDir set or can put one in the .grails folder under user.home if (cacheDir == null) { try { String userhome = System.getProperty("user.home"); if (userhome != null) { cacheDir = new StringBuilder(userhome).append(File.separator).append( ".grails").toString(); new File(cacheDir).mkdir(); } } catch (Throwable t) { System.err.println( "looks like user.home is not set, or cannot write to it: cannot create cache."); t.printStackTrace(System.err); } } if (!specifiedCaching) { if (cacheDir != null) { isCaching = true; } } if (pluginClassnameList == null) { pluginClassnameList = new ArrayList(); } pluginClassnameList.add("org.springsource.loaded.SystemPropertyConfiguredIsReloadableTypePlugin"); // turn off the 3.0 reloading, for now (just because it hasn't been tested) SpringPlugin.support305 = false; } } else { if (isCaching) { if (cacheDir == null) { try { String userhome = System.getProperty("user.home"); if (userhome != null) { cacheDir = userhome; } } catch (Throwable t) { System.err.println("looks like user.home is not set: cannot create cache."); t.printStackTrace(System.err); } } } } if (isCaching) { // Ensure cache folder exists try { File cacheDirFile = new File(cacheDir); if (!cacheDirFile.exists()) { boolean created = cacheDirFile.mkdirs(); if (!created) { System.err.println("Caching deactivated: failed to create cache directory: " + cacheDir); isCaching = false; } } else { if (!cacheDirFile.isDirectory()) { System.err.println( "Caching deactivated: unable to use specified cache area, it is not a directory: " + cacheDirFile); isCaching = false; } } } catch (Exception e) { System.err.println("Unexpected problem creating specified cachedir: " + cacheDir); e.printStackTrace(); } } // Alternative route for specifying values value = System.getProperty("springloaded.enumlimit"); if (value != null) { enumLimit = toInt(value, enumLimit); } } catch (Throwable t) { System.err.println("Unexpected problem reading global configuration setting:" + t.toString()); t.printStackTrace(); } debugplugins = debugPlugins; } private static int toInt(String value, int defaultValue) { try { return Integer.parseInt(value); } catch (NumberFormatException nfe) { return defaultValue; } } public final static boolean isJava18orHigher; public static boolean InTestMode = false; static { String version = System.getProperty("java.version"); if (version.startsWith("1.8")) { isJava18orHigher = true; } else { isJava18orHigher = false; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy