/* * Part of the CCNx Java Library. * * Copyright (C) 2008-2011 Palo Alto Research Center, Inc. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. You should have received * a copy of the GNU Lesser General Public License along with this library; * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, * Fifth Floor, Boston, MA 02110-1301 USA. */ package org.ccnx.ccn.config; import java.io.File; import java.io.FileOutputStream; import java.lang.reflect.Method; import java.math.BigInteger; import java.util.HashMap; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.ccnx.ccn.impl.CCNNetworkManager.NetworkProtocol; import org.ccnx.ccn.impl.encoding.BinaryXMLCodec; import org.ccnx.ccn.impl.encoding.XMLEncodable; import org.ccnx.ccn.impl.security.crypto.CCNDigestHelper; import org.ccnx.ccn.impl.support.Log; import org.ccnx.ccn.io.content.ContentEncodingException; import org.ccnx.ccn.profiles.SegmentationProfile; import org.ccnx.ccn.protocol.ContentName; import org.ccnx.ccn.protocol.ContentObject; /** * A class encapsulating a number of system-level default parameters as well as helper * functionality for managing log output and printing debug data. Eventually will * be supported by an external configuration file for controlling key parameters. * * The current basic logging infrastructure uses standard Java logging, * controlled only by a system-wide Level value. * That value, as well as other logging-related parameters are currently managed by the * Log class, but should eventually migrate here. There is a facility for selective logging * control, by turning on and off logging for individual named "modules"; though that has * not yet been widely utilized. Eventually we should support separate log Level settings * for each module when necessary. */ public class SystemConfiguration { /** * String constants, to define these in one place. */ public static final String STRING_FALSE = "false"; public static final String STRING_TRUE = "true"; /** * System operation timeout. Very long timeout used to wait for system events * such as stopping Daemons. */ public final static int SYSTEM_STOP_TIMEOUT = 30000; /** * Very long timeout for network operations, in msec.. */ public final static int MAX_TIMEOUT = 10000; /** * Extra-long timeout, e.g. to get around reexpression timing issues. */ public final static int EXTRA_LONG_TIMEOUT = 6000; /** * Longer timeout, for e.g. waiting for a latest version and being sure you * have anything available locally in msec. */ public final static int LONG_TIMEOUT = 3000; /** * Medium timeout, used as system default. */ public static final int MEDIUM_TIMEOUT = 1000; /** * Short timeout; for things you expect to exist or not exist locally. */ public static final int SHORT_TIMEOUT = 300; protected static final String CCN_PROTOCOL_PROPERTY = "org.ccnx.protocol"; public static final String DEFAULT_PROTOCOL = "TCP"; // UDP or TCP allowed public static NetworkProtocol AGENT_PROTOCOL = null; // Set up below public static final String AGENT_PROTOCOL_PROPERTY = "org.ccnx.agent.protocol"; public static final String AGENT_PROTOCOL_ENVIRONMENT_VARIABLE = "CCN_AGENT_PROTOCOL"; /** * Controls whether we should exit on severe errors in the network manager. This should only be * set true in automated tests. In live running code, we hope to be able to recover instead. */ public static final boolean DEFAULT_EXIT_ON_NETWORK_ERROR = false; public static boolean EXIT_ON_NETWORK_ERROR = DEFAULT_EXIT_ON_NETWORK_ERROR; public static final String CCN_EXIT_ON_NETWORK_ERROR_PROPERTY = "org.ccnx.ExitOnNetworkError"; public static final String CCN_EXIT_ON_NETWORK_ERROR_ENVIRONMENT_VARIABLE = "CCN_EXIT_ON_NETERROR"; /** * Interest reexpression period * TODO - This is (currently) an architectural constant. Not all code has been changed to use it. */ public static final int INTEREST_REEXPRESSION_DEFAULT = 4000; public enum DEBUGGING_FLAGS {DEBUG_SIGN, DEBUG_VERIFY, DUMP_DAEMONCMD, REPO_EXITDUMP}; protected static HashMap<DEBUGGING_FLAGS,Boolean> DEBUG_FLAG_VALUES = new HashMap<DEBUGGING_FLAGS,Boolean>(); /** * Property to set debug flags. */ public static final String DEBUG_FLAG_PROPERTY = "com.parc.ccn.DebugFlags"; /** * Property to set directory to dump debug data. */ public static final String DEBUG_DATA_DIRECTORY_PROPERTY = "com.parc.ccn.DebugDataDirectory"; protected static final String DEFAULT_DEBUG_DATA_DIRECTORY = "./CCN_DEBUG_DATA"; public static String DEBUG_DATA_DIRECTORY = null; /** * Tunable timeouts as well as timeout defaults. */ /** * Enumerated Name List looping timeout in ms. * Default is 300ms */ protected static final String CHILD_WAIT_INTERVAL_PROPERTY = "org.ccnx.EnumList.WaitInterval"; public final static int CHILD_WAIT_INTERVAL_DEFAULT = 300; public static int CHILD_WAIT_INTERVAL = CHILD_WAIT_INTERVAL_DEFAULT; /** * Default timeout for the flow controller */ protected static final String FC_TIMEOUT_PROPERTY = "org.ccnx.fc.timeout"; public final static int FC_TIMEOUT_DEFAULT = MAX_TIMEOUT; public static int FC_TIMEOUT = FC_TIMEOUT_DEFAULT; /** * Allow override to only save to a local repository */ protected static final String FC_LOCALREPOSITORY_PROPERTY = "org.ccnx.fc.localrepository"; protected final static String FC_LOCALREPOSITORY_ENV_VAR = "FC_LOCALREPOSITORY"; public final static boolean FC_LOCALREPOSITORY_DEFAULT = false; public static boolean FC_LOCALREPOSITORY = FC_LOCALREPOSITORY_DEFAULT; /** * How long to wait for a service discovery timeout in CCNNetworkManager, in ms * * This should be longer than the interest timeout to permit at least one re-expression. */ protected static final String CCNDID_DISCOVERY_TIMEOUT_PROPERTY = "org.ccnx.ccndid.timeout"; public final static int CCNDID_DISCOVERY_TIMEOUT_DEFAULT = 4200; public static int CCNDID_DISCOVERY_TIMEOUT = CCNDID_DISCOVERY_TIMEOUT_DEFAULT; /** * Pipeline size for pipeline in CCNAbstractInputStream * Default is 4 */ protected static final String PIPELINE_SIZE_PROPERTY = "org.ccnx.PipelineSize"; protected static final String PIPELINE_SIZE_ENV_VAR = "JAVA_PIPELINE_SIZE"; public static int PIPELINE_SIZE = 4; /** * Pipeline segment attempts for pipeline in CCNAbstractInputStream * Default is 5 */ protected static final String PIPELINE_ATTEMPTS_PROPERTY = "org.ccnx.PipelineAttempts"; protected static final String PIPELINE_ATTEMPTS_ENV_VAR = "JAVA_PIPELINE_ATTEMPTS"; public static int PIPELINE_SEGMENTATTEMPTS = 5; /** * Pipeline round trip time factor for pipeline in CCNAbstractInputStream * Default is 2 */ protected static final String PIPELINE_RTT_PROPERTY = "org.ccnx.PipelineRTTFactor"; protected static final String PIPELINE_RTT_ENV_VAR = "JAVA_PIPELINE_RTTFACTOR"; public static int PIPELINE_RTTFACTOR = 2; /** * Pipeline stat printouts in CCNAbstractInputStream * Default is off */ protected static final String PIPELINE_STATS_PROPERTY = "org.ccnx.PipelineStats"; protected static final String PIPELINE_STATS_ENV_VAR = "JAVA_PIPELINE_STATS"; public static boolean PIPELINE_STATS = false; /** * Default block size for IO */ protected static final String BLOCK_SIZE_PROPERTY = "ccn.lib.blocksize"; protected static final String BLOCK_SIZE_ENV_VAR = "CCNX_BLOCKSIZE"; public static int BLOCK_SIZE = SegmentationProfile.DEFAULT_BLOCKSIZE; /** * Backwards-compatible handling of old header names. * Current default is true; eventually will be false. */ protected static final String OLD_HEADER_NAMES_PROPERTY = "org.ccnx.OldHeaderNames"; protected static final String OLD_HEADER_NAMES_ENV_VAR = "CCNX_OLD_HEADER_NAMES"; public static boolean OLD_HEADER_NAMES = true; /** * Timeout used for communication with local 'ccnd' for control operations. * * An example is Face Creation and Prefix Registration. * Should be longer than the interest timeout to permit at least one re-expression. * TODO - ccnop would properly be spelled ccndop */ protected static final String CCND_OP_TIMEOUT_PROPERTY = "org.ccnx.ccnop.timeout"; protected final static String CCND_OP_TIMEOUT_ENV_VAR = "CCND_OP_TIMEOUT"; public final static int CCND_OP_TIMEOUT_DEFAULT = 4200; public static int CCND_OP_TIMEOUT = CCND_OP_TIMEOUT_DEFAULT; /** * System default timeout */ protected static final String CCNX_TIMEOUT_PROPERTY = "org.ccnx.default.timeout"; protected final static String CCNX_TIMEOUT_ENV_VAR = "CCNX_TIMEOUT"; public final static int CCNX_TIMEOUT_DEFAULT = EXTRA_LONG_TIMEOUT; /** * GetLatestVersion attempt timeout. * TODO This timeout is set to MEDIUM_TIMEOUT to work around the problem * in ccnd where some interests take >300ms (and sometimes longer, have seen periodic delays >800ms) * when that bug is found and fixed, this can be reduced back to the SHORT_TIMEOUT. * long attemptTimeout = SystemConfiguration.SHORT_TIMEOUT; */ protected static final String GLV_ATTEMPT_TIMEOUT_PROPERTY = "org.ccnx.glv.attempt.timeout"; protected final static String GLV_ATTEMPT_TIMEOUT_ENV_VAR = "GLV_ATTEMPT_TIMEOUT"; public final static int GLV_ATTEMPT_TIMEOUT_DEFAULT = SHORT_TIMEOUT; public static int GLV_ATTEMPT_TIMEOUT = GLV_ATTEMPT_TIMEOUT_DEFAULT; /** * "Short timeout" that can be set */ protected static final String SETTABLE_SHORT_TIMEOUT_PROPERTY = "org.ccnx.short.timeout"; protected final static String SETTABLE_SHORT_TIMEOUT_ENV_VAR = "SETTABLE_SHORT_TIMEOUT"; public static int SETTABLE_SHORT_TIMEOUT = SHORT_TIMEOUT; /** * Should we dump netmanager statistics on shutdown */ protected static final String DUMP_NETMANAGER_STATS_PROPERTY = "org.ccnx.dump.netmanager.stats"; protected final static String DUMP_NETMANAGER_STATS_ENV_VAR = "CCNX_DUMP_NETMANAGER_STATS"; public static boolean DUMP_NETMANAGER_STATS = false; /** * Settable system default timeout. */ protected static int _defaultTimeout = CCNX_TIMEOUT_DEFAULT; /** * Get system default timeout. * @return the default timeout. */ public static int getDefaultTimeout() { return _defaultTimeout; } /** * Set system default timeout. */ public static void setDefaultTimeout(int newTimeout) { _defaultTimeout = newTimeout; } /** * No timeout. Should be single value used in all places in the code where you * want to block forever. */ public final static int NO_TIMEOUT = -1; /** * Set the maximum number of attempts that VersioningProfile.getLatestVersion will * try to get a later version of an object. */ public static final int GET_LATEST_VERSION_ATTEMPTS = 10; /** * Can set compile-time default encoding here. Choices are * currently "Text" and "Binary", or better yet * BinaryXMLCodec.codecName() or TextXMLCodec.codecName(). */ protected static final String SYSTEM_DEFAULT_ENCODING = BinaryXMLCodec.codecName(); /** * Run-time default. Set to command line property if given, if not, * the system default above. */ protected static String DEFAULT_ENCODING = null; /** * Command-line property to set default encoding * @return */ protected static final String DEFAULT_ENCODING_PROPERTY = "com.parc.ccn.data.DefaultEncoding"; public static final int DEBUG_RADIX = 34; public static final int SYSTEM_THREAD_LIFE = 10; public static ThreadPoolExecutor _systemThreadpool = (ThreadPoolExecutor)Executors.newCachedThreadPool(); /** * Obtain the management bean for this runtime if it is available. * The class of the management bean is discovered at runtime and there * should be no static dependency on any particular bean class. * @return the bean or null if none available */ public synchronized static Object getManagementBean() { // Check if we already have a management bean; retrieve only // once per VM if (null == runtimeMXBean) { ClassLoader cl = SystemConfiguration.class.getClassLoader(); try { Class<?> mgmtclass = cl.loadClass("java.lang.management.ManagementFactory"); Method getRuntimeMXBean = mgmtclass.getDeclaredMethod("getRuntimeMXBean", (Class[])null); runtimeMXBean = getRuntimeMXBean.invoke(mgmtclass, (Object[])null); } catch (Exception ex) { Log.log(Level.WARNING, "Management bean unavailable: {0}", ex.getMessage()); } } return runtimeMXBean; } static { // Allow override of default debug information. String debugFlags = System.getProperty(DEBUG_FLAG_PROPERTY); if (null != debugFlags) { String [] flags = debugFlags.split(":"); for (int i=0; i < flags.length; ++i) { setDebugFlag(flags[i]); } } DEBUG_DATA_DIRECTORY = System.getProperty(DEBUG_DATA_DIRECTORY_PROPERTY, DEFAULT_DEBUG_DATA_DIRECTORY); } static { // NOTE: do not call Log.* methods from the initializer as log depends on SystemConfiguration. // Allow override of basic protocol String proto = SystemConfiguration.retrievePropertyOrEnvironmentVariable(AGENT_PROTOCOL_PROPERTY, AGENT_PROTOCOL_ENVIRONMENT_VARIABLE, DEFAULT_PROTOCOL); boolean found = false; for (NetworkProtocol p : NetworkProtocol.values()) { String pAsString = p.toString(); if (proto.equalsIgnoreCase(pAsString)) { // if (!pAsString.equalsIgnoreCase(DEFAULT_PROTOCOL)) System.err.println("CCN agent protocol changed to " + pAsString + " per property"); AGENT_PROTOCOL = p; found = true; break; } } if (!found) { System.err.println("The protocol must be UDP(17) or TCP (6)"); throw new IllegalArgumentException("Invalid protocol '" + proto + "' specified in " + AGENT_PROTOCOL_PROPERTY); } // Allow override of exit on network error try { EXIT_ON_NETWORK_ERROR = Boolean.parseBoolean(retrievePropertyOrEnvironmentVariable(CCN_EXIT_ON_NETWORK_ERROR_PROPERTY, CCN_EXIT_ON_NETWORK_ERROR_ENVIRONMENT_VARIABLE, Boolean.toString(DEFAULT_EXIT_ON_NETWORK_ERROR))); // System.err.println("CCND_OP_TIMEOUT = " + CCND_OP_TIMEOUT); } catch (NumberFormatException e) { System.err.println("The exit on network error must be an boolean."); throw e; } // Allow override of default enumerated name list child wait timeout. try { CHILD_WAIT_INTERVAL = Integer.parseInt(System.getProperty(CHILD_WAIT_INTERVAL_PROPERTY, Integer.toString(CHILD_WAIT_INTERVAL_DEFAULT))); // System.err.println("CHILD_WAIT_INTERVAL = " + CHILD_WAIT_INTERVAL); } catch (NumberFormatException e) { System.err.println("The ChildWaitInterval must be an integer."); throw e; } // Allow override of default pipeline size for CCNAbstractInputStream try { PIPELINE_SIZE = Integer.parseInt(retrievePropertyOrEnvironmentVariable(PIPELINE_SIZE_PROPERTY, PIPELINE_SIZE_ENV_VAR, "4")); //PIPELINE_SIZE = Integer.parseInt(System.getProperty(PIPELINE_SIZE_PROPERTY, "4")); } catch (NumberFormatException e) { System.err.println("The PipelineSize must be an integer."); throw e; } // Allow override of default pipeline size for CCNAbstractInputStream try { PIPELINE_SEGMENTATTEMPTS = Integer.parseInt(retrievePropertyOrEnvironmentVariable(PIPELINE_ATTEMPTS_PROPERTY, PIPELINE_ATTEMPTS_ENV_VAR, "5")); //PIPELINE_SIZE = Integer.parseInt(System.getProperty(PIPELINE_SIZE_PROPERTY, "4")); } catch (NumberFormatException e) { System.err.println("The PipelineAttempts must be an integer."); } // Allow override of default pipeline rtt multiplication factor for CCNAbstractInputStream try { PIPELINE_RTTFACTOR = Integer.parseInt(retrievePropertyOrEnvironmentVariable(PIPELINE_RTT_PROPERTY, PIPELINE_RTT_ENV_VAR, "2")); } catch (NumberFormatException e) { System.err.println("The PipelineRTTFactor must be an integer."); } // Allow printing of pipeline stats in CCNAbstractInputStream PIPELINE_STATS = Boolean.parseBoolean(retrievePropertyOrEnvironmentVariable(PIPELINE_STATS_PROPERTY, PIPELINE_STATS_ENV_VAR, STRING_FALSE)); // Allow override of default ccndID discovery timeout. try { CCNDID_DISCOVERY_TIMEOUT = Integer.parseInt(System.getProperty(CCNDID_DISCOVERY_TIMEOUT_PROPERTY, Integer.toString(CCNDID_DISCOVERY_TIMEOUT_DEFAULT))); // System.err.println("CCNDID_DISCOVERY_TIMEOUT = " + CCNDID_DISCOVERY_TIMEOUT); } catch (NumberFormatException e) { System.err.println("The ccndID discovery timeout must be an integer."); throw e; } // Allow override of default flow controller timeout. try { FC_TIMEOUT = Integer.parseInt(System.getProperty(FC_TIMEOUT_PROPERTY, Integer.toString(FC_TIMEOUT_DEFAULT))); // System.err.println("FC_TIMEOUT = " + FC_TIMEOUT); } catch (NumberFormatException e) { System.err.println("The default flow controller timeout must be an integer."); throw e; } // Allow override for local repository override try { FC_LOCALREPOSITORY = Boolean.parseBoolean(retrievePropertyOrEnvironmentVariable(FC_LOCALREPOSITORY_PROPERTY, FC_LOCALREPOSITORY_ENV_VAR, Boolean.toString(FC_LOCALREPOSITORY_DEFAULT))); } catch (NumberFormatException e) { System.err.println("The local repository flow controller override must be a boolean."); throw e; } // Allow override of ccn default timeout. try { _defaultTimeout = Integer.parseInt(retrievePropertyOrEnvironmentVariable(CCNX_TIMEOUT_PROPERTY, CCNX_TIMEOUT_ENV_VAR, Integer.toString(CCNX_TIMEOUT_DEFAULT))); // System.err.println("CCNX_TIMEOUT = " + CCNX_TIMEOUT); } catch (NumberFormatException e) { System.err.println("The ccnd default timeout must be an integer."); throw e; } // Allow override of ccnd op timeout. try { CCND_OP_TIMEOUT = Integer.parseInt(System.getProperty(CCND_OP_TIMEOUT_PROPERTY, Integer.toString(CCND_OP_TIMEOUT_DEFAULT))); // System.err.println("CCND_OP_TIMEOUT = " + CCND_OP_TIMEOUT); } catch (NumberFormatException e) { System.err.println("The ccnd op timeout must be an integer."); throw e; } // Allow override of getLatestVersion attempt timeout. try { GLV_ATTEMPT_TIMEOUT = Integer.parseInt(retrievePropertyOrEnvironmentVariable(GLV_ATTEMPT_TIMEOUT_PROPERTY, GLV_ATTEMPT_TIMEOUT_ENV_VAR, Integer.toString(GLV_ATTEMPT_TIMEOUT_DEFAULT))); // System.err.println("GLV_ATTEMPT_TIMEOUT = " + GLV_ATTEMPT_TIMEOUT); } catch (NumberFormatException e) { System.err.println("The getlatestversion attempt timeout must be an integer."); throw e; } // Allow override of settable short timeout. try { SETTABLE_SHORT_TIMEOUT = Integer.parseInt(retrievePropertyOrEnvironmentVariable(SETTABLE_SHORT_TIMEOUT_PROPERTY, SETTABLE_SHORT_TIMEOUT_ENV_VAR, Integer.toString(SHORT_TIMEOUT))); // System.err.println("SETTABLE_SHORT_TIMEOUT = " + SETTABLE_SHORT_TIMEOUT); } catch (NumberFormatException e) { System.err.println("The settable short timeout must be an integer."); throw e; } _systemThreadpool.setKeepAliveTime(SYSTEM_THREAD_LIFE, TimeUnit.SECONDS); // Dump netmanager statistics if requested DUMP_NETMANAGER_STATS = Boolean.parseBoolean(retrievePropertyOrEnvironmentVariable(DUMP_NETMANAGER_STATS_PROPERTY, DUMP_NETMANAGER_STATS_ENV_VAR, Boolean.toString(DUMP_NETMANAGER_STATS))); // Allow override of block size // TODO should we make sure its a reasonable number? try { BLOCK_SIZE = Integer.parseInt(retrievePropertyOrEnvironmentVariable(BLOCK_SIZE_PROPERTY, BLOCK_SIZE_ENV_VAR, Integer.toString(BLOCK_SIZE))); } catch (NumberFormatException e) { System.err.println("The settable block size must be an integer."); throw e; } // Handle old-style header names OLD_HEADER_NAMES = Boolean.parseBoolean( retrievePropertyOrEnvironmentVariable(OLD_HEADER_NAMES_PROPERTY, OLD_HEADER_NAMES_ENV_VAR, STRING_TRUE)); } public static String getLocalHost() { // InetAddress.getLocalHost().toString(), return "127.0.0.1"; // using InetAddress.getLocalHost gives bad results } /** * Order of precedence (highest to lowest): * * 1) dynamic setting on an individual encoder or decoder, * or in a single encode or decode call * * 2) command-line property * * 3) compiled-in default * * The latter two are handled here, the former in the encoder/decoder * machinery itself. * @return */ public static String getDefaultEncoding() { if (null == DEFAULT_ENCODING) { // First time, check for argument String commandLineProperty = System.getProperty(DEFAULT_ENCODING_PROPERTY); if (null == commandLineProperty) DEFAULT_ENCODING = SYSTEM_DEFAULT_ENCODING; else DEFAULT_ENCODING = commandLineProperty; } return DEFAULT_ENCODING; } public static void setDefaultEncoding(String encoding) { DEFAULT_ENCODING = encoding; } public static boolean checkDebugFlag(DEBUGGING_FLAGS debugFlag) { Boolean result = DEBUG_FLAG_VALUES.get(debugFlag); if (null == result) return false; return result.booleanValue(); } /** * Management bean for this runtime, if available. This is not dependent * upon availability of any particular class but discovered dynamically * from what is available at runtime. */ private static Object runtimeMXBean = null; public static void setDebugFlag(DEBUGGING_FLAGS debugFlag, boolean value) { Log.info("Debug Flag {0} set to {1}", debugFlag.toString(), value); DEBUG_FLAG_VALUES.put(debugFlag, Boolean.valueOf(value)); } public static void setDebugFlag(String debugFlag, boolean value) { try { DEBUGGING_FLAGS df = DEBUGGING_FLAGS.valueOf(debugFlag); setDebugFlag(df, value); } catch (IllegalArgumentException ax) { Log.info("Cannot set debugging flag, no known flag: " + debugFlag + ". Choices are: " + debugFlagList()); } } public static String debugFlagList() { DEBUGGING_FLAGS [] availableFlags = DEBUGGING_FLAGS.values(); StringBuffer flags = new StringBuffer(); for (int i=0; i < availableFlags.length; ++i) { if (i > 0) flags.append(":"); flags.append(availableFlags[i]); } return flags.toString(); } public static void setDebugFlag(String debugFlag) { setDebugFlag(debugFlag, true); } public static void setDebugDataDirectory(String dir) { DEBUG_DATA_DIRECTORY=dir; } public static void outputDebugData(ContentName name, XMLEncodable data) { try { byte [] encoded = data.encode(); outputDebugData(name, encoded); } catch (ContentEncodingException ex) { Log.warning("Cannot encode object : " + name + " to output for debug."); } } public static void outputDebugData(ContentName name, byte [] data) { // Output debug data under a given name. try { File dataDir = new File(DEBUG_DATA_DIRECTORY); if (!dataDir.exists()) { if (!dataDir.mkdirs()) { Log.warning("outputDebugData: Cannot create default debug data directory: " + dataDir.getAbsolutePath()); return; } } File outputParent = new File(dataDir, name.toString()); if (!outputParent.exists()) { if (!outputParent.mkdirs()) { Log.warning("outputDebugData: cannot create data parent directory: " + outputParent); } } byte [] contentDigest = CCNDigestHelper.digest(data); String contentName = new BigInteger(1, contentDigest).toString(DEBUG_RADIX); File outputFile = new File(outputParent, contentName); Log.finest("Attempting to output debug data for name " + name.toString() + " to file " + outputFile.getAbsolutePath()); FileOutputStream fos = new FileOutputStream(outputFile); try { fos.write(data); } finally { fos.close(); } } catch (Exception e) { Log.warning("Exception attempting to log debug data for name: " + name.toString() + " " + e.getClass().getName() + ": " + e.getMessage()); } } public static void outputDebugObject(File dataDir, String postfix, ContentObject object) { // Output debug data under a given name. try { if (!dataDir.exists()) { if (!dataDir.mkdirs()) { Log.warning("outputDebugData: Cannot create debug data directory: " + dataDir.getAbsolutePath()); return; } } /* File outputParent = new File(dataDir, object.name().toString()); if (!outputParent.exists()) { if (!outputParent.mkdirs()) { Log.warning("outputDebugData: cannot create data parent directory: " + outputParent); } } */ byte [] objectDigest = object.digest(); StringBuffer contentName = new StringBuffer(new BigInteger(1, objectDigest).toString(DEBUG_RADIX)); if (null != postfix) { contentName = contentName.append(postfix); } contentName.append(".ccnb"); File outputFile = new File(dataDir, contentName.toString()); Log.finest("Attempting to output debug data for name " + object.name().toString() + " to file " + outputFile.getAbsolutePath()); FileOutputStream fos = new FileOutputStream(outputFile); try { object.encode(fos); } finally { fos.close(); } } catch (Exception e) { Log.warning("Exception attempting to log debug data for name: " + object.name().toString() + " " + e.getClass().getName() + ": " + e.getMessage()); } } public static void outputDebugObject(ContentObject object) { outputDebugObject(new File(DEBUG_DATA_DIRECTORY), null, object); } /** * Log information about an object at level Level.INFO. See logObject(Level, String, ContentObject) for details. * @param message String to prefix output with * @param co ContentObject to print debugging information about. * @see logObject(Level, String, ContentObject) */ public static void logObject(String message, ContentObject co) { logObject(Level.INFO, message, co); } /** * Log the gory details of an object, including debugging information relevant to object signing. * @param level log Level to control printing of log messages * @param message message to prefix output with * @param co ContentObject to print debugging information for */ public static void logObject(Level level, String message, ContentObject co) { try { byte [] coDigest = CCNDigestHelper.digest(co.encode()); byte [] tbsDigest = CCNDigestHelper.digest(ContentObject.prepareContent(co.name(), co.signedInfo(), co.content())); Log.log(level, message + " name: {0} timestamp: {1} digest: {2} tbs: {3}.", co.name(), co.signedInfo().getTimestamp(), CCNDigestHelper.printBytes(coDigest, DEBUG_RADIX), CCNDigestHelper.printBytes(tbsDigest, DEBUG_RADIX)); } catch (ContentEncodingException xs) { Log.log(level, "Cannot encode object for logging: {0}.", co.name()); } } protected static String _loggingConfiguration; /** * TODO: Fix this incorrect comment * Property to turn off access control flags. Set it to any value and it will turn off * access control; used for testing. */ public static final String LOGGING_CONFIGURATION_PROPERTY = "com.parc.ccn.LoggingConfiguration"; /** * Strings of interest to be set in the logging configuration */ public static final String DETAILED_LOGGER = "DetailedLogger"; /** * Configure logging itself. This is a set of concatenated strings set as a * command line property; it can be used to set transparent properties read * at various points in the code. */ public static String getLoggingConfiguration() { if (null == _loggingConfiguration) { _loggingConfiguration = System.getProperty(LOGGING_CONFIGURATION_PROPERTY, ""); } return _loggingConfiguration; } public static boolean hasLoggingConfigurationProperty(String property) { if (null == property) return false; return getLoggingConfiguration().contains(property); } /** * Gets a process identifier (PID) for the running Java Virtual Machine (JVM) process, if possible. * Java does not provide a supported way to obtain the operating system (OS) PID in general. * This method uses technique(s) for getting the OS PID that are not necessarily portable * to all Java execution environments. * The PID is returned as a String value. Where possible, the result will be the string representation of an integer * that is probably identical to the OS PID of the JVM process that executed this method. In other cases, * the result will be an implementation-dependent string name that identifies the JVM instance but does not exactly * match the OS PID. The returned value will not contain spaces. * If no identifier can be obtained, the result will be null. * @return A Process Identifier (PID) of the JVM (not necessarily the OS PID) or null if not available * @see <a href="http://blog.igorminar.com/2007/03/how-java-application-can-discover-its.html">Techniques for Discovering PID</a> */ public static String getPID() { // We try the JVM mgmt bean if available, reported to work on variety // of operating systems on the Sun JVM. The bean is obtained once per VM, // the other work to get the ID is done here. Object bean = getManagementBean(); if (null == getManagementBean()) { return null; } try { String pid = null; String vmname = null; Method getName = bean.getClass().getDeclaredMethod("getName", (Class[]) null); if (null == getName) { return null; } getName.setAccessible(true); vmname = (String) getName.invoke(bean, (Object[]) null); if (null == vmname) { return null; } // Hopefully the string is in the form "60447@ice.local", where we can pull // out the integer hoping it is identical to the OS PID Pattern exp = Pattern.compile("^(\\d+)@\\S+$"); Matcher match = exp.matcher(vmname); if (match.matches()) { pid = match.group(1); } else { // We don't have a candidate to match the OS PID, but we have the JVM name // from the mgmt bean itself so that will have to do, cleaned of spaces pid = vmname.replaceAll("\\s+", "_"); } return pid; } catch (Exception e) { return null; } } protected static Boolean _accessControlDisabled; /** * Property to turn off access control flags. Set it to any value and it will turn off * access control; used for testing. */ public static final String ACCESS_CONTROL_DISABLED_PROPERTY = "com.parc.ccn.DisableAccessControl"; /** * Allow control of access control at the command line. */ public synchronized static boolean disableAccessControl() { if (null == _accessControlDisabled) { _accessControlDisabled = (null != System.getProperty(ACCESS_CONTROL_DISABLED_PROPERTY)); } return _accessControlDisabled; } public static void setAccessControlDisabled(boolean accessControlDisabled) { _accessControlDisabled = accessControlDisabled; } /** * Retrieve a string that might be stored as an environment variable, or * overridden on the command line. If the command line variable is set, return * its (String) value; if not, return the environment variable value if available; * Caller should synchronize as appropriate. * @return The value in force for this variable, or null if unset. */ public static String retrievePropertyOrEnvironmentVariable(String javaPropertyName, String environmentVariableName, String defaultValue) { // First try the command line property. String value = null; if (null != javaPropertyName) { value = System.getProperty(javaPropertyName); } if ((null == value) && (null != environmentVariableName)) { // Try for an environment variable. value = System.getenv(environmentVariableName); } if (null == value) value = defaultValue; return value; } }