logging-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ihabu...@apache.org
Subject svn commit: r1184770 [1/2] - in /logging/log4php/trunk/src: changes/ main/php/ main/php/appenders/ main/php/configurators/ main/php/helpers/ main/php/layouts/ test/php/ test/php/appenders/ test/php/configurators/ test/php/filters/ test/php/renderers/
Date Sun, 16 Oct 2011 07:12:51 GMT
Author: ihabunek
Date: Sun Oct 16 07:12:49 2011
New Revision: 1184770

URL: http://svn.apache.org/viewvc?rev=1184770&view=rev
Log:
LOG4PHP-152: A rewrite of the configurator and improved tests.

Added:
    logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapter.php
    logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterINI.php
    logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterPHP.php
    logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterXML.php
    logging/log4php/trunk/src/test/php/LoggerConfiguratorTest.php
    logging/log4php/trunk/src/test/php/LoggerTestHelper.php
    logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterINITest.php
    logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterPHPTest.php
    logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterXMLTest.php
    logging/log4php/trunk/src/test/php/configurators/config1.ini
    logging/log4php/trunk/src/test/php/configurators/config1.php
    logging/log4php/trunk/src/test/php/configurators/config1.xml
    logging/log4php/trunk/src/test/php/configurators/config2.ini
    logging/log4php/trunk/src/test/php/configurators/config2.php
    logging/log4php/trunk/src/test/php/configurators/config2.xml
    logging/log4php/trunk/src/test/php/configurators/config3.ini
    logging/log4php/trunk/src/test/php/configurators/config3.php
    logging/log4php/trunk/src/test/php/configurators/config3.xml
    logging/log4php/trunk/src/test/php/configurators/config4.ini
    logging/log4php/trunk/src/test/php/configurators/config4.php
    logging/log4php/trunk/src/test/php/configurators/config4.xml
Removed:
    logging/log4php/trunk/src/main/php/configurators/LoggerConfiguratorBasic.php
    logging/log4php/trunk/src/main/php/configurators/LoggerConfiguratorIni.php
    logging/log4php/trunk/src/main/php/configurators/LoggerConfiguratorPhp.php
    logging/log4php/trunk/src/main/php/configurators/LoggerConfiguratorXml.php
    logging/log4php/trunk/src/test/php/configurators/LoggerConfiguratorBasicTest.php
    logging/log4php/trunk/src/test/php/configurators/LoggerConfiguratorIniTest.php
    logging/log4php/trunk/src/test/php/configurators/LoggerConfiguratorPhpTest.php
    logging/log4php/trunk/src/test/php/configurators/LoggerConfiguratorXmlTest.php
    logging/log4php/trunk/src/test/php/configurators/test1.php
    logging/log4php/trunk/src/test/php/configurators/test1.properties
    logging/log4php/trunk/src/test/php/configurators/test1.xml
    logging/log4php/trunk/src/test/php/configurators/test2.properties
    logging/log4php/trunk/src/test/php/configurators/test3.properties
    logging/log4php/trunk/src/test/php/configurators/test4.properties
    logging/log4php/trunk/src/test/php/configurators/test5.properties
    logging/log4php/trunk/src/test/php/configurators/test6.properties
Modified:
    logging/log4php/trunk/src/changes/changes.xml
    logging/log4php/trunk/src/main/php/Logger.php
    logging/log4php/trunk/src/main/php/LoggerAppenderPool.php
    logging/log4php/trunk/src/main/php/LoggerConfigurator.php
    logging/log4php/trunk/src/main/php/appenders/LoggerAppenderConsole.php
    logging/log4php/trunk/src/main/php/helpers/LoggerNamedPatternConverter.php
    logging/log4php/trunk/src/main/php/layouts/LoggerLayoutPattern.php
    logging/log4php/trunk/src/test/php/LoggerTest.php
    logging/log4php/trunk/src/test/php/LoggerThrowableInformationTest.php
    logging/log4php/trunk/src/test/php/appenders/LoggerAppenderConsoleTest.php
    logging/log4php/trunk/src/test/php/appenders/LoggerAppenderEchoTest.php
    logging/log4php/trunk/src/test/php/appenders/LoggerAppenderFileTest.php
    logging/log4php/trunk/src/test/php/appenders/LoggerAppenderPhpTest.php
    logging/log4php/trunk/src/test/php/bootstrap.php
    logging/log4php/trunk/src/test/php/filters/LoggerFilterDenyAllTest.php
    logging/log4php/trunk/src/test/php/filters/LoggerFilterLevelMatchTest.php
    logging/log4php/trunk/src/test/php/filters/LoggerFilterStringMatchTest.php
    logging/log4php/trunk/src/test/php/renderers/LoggerRendererMapTest.php
    logging/log4php/trunk/src/test/php/renderers/test4.properties

Modified: logging/log4php/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/changes/changes.xml?rev=1184770&r1=1184769&r2=1184770&view=diff
==============================================================================
--- logging/log4php/trunk/src/changes/changes.xml (original)
+++ logging/log4php/trunk/src/changes/changes.xml Sun Oct 16 07:12:49 2011
@@ -21,6 +21,7 @@
 	</properties>
 	<body>
 	    <release version="2.2.0" date="SVN">
+	    	<action date="2011-10-15" type="update" issue="LOG4PHP-152" dev="Ivan Habunek">A rewrite of the configurator.</action>
 	    	<action date="2011-09-03" type="fix" issue="LOG4PHP-145" dev="Ivan Habunek">The syslog appender does not correctly parse options</action>
 	    	<action date="2011-08-31" type="remove" issue="LOG4PHP-149" dev="Ivan Habunek">Remove deprecated appender LoggerAppenderAdodb</action>
 	    	<action date="2011-08-31" type="fix" issue="LOG4PHP-148" dev="Ivan Habunek">LoggerUserFieldPatternConverter class missing in log4php archive</action>

Modified: logging/log4php/trunk/src/main/php/Logger.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/Logger.php?rev=1184770&r1=1184769&r2=1184770&view=diff
==============================================================================
--- logging/log4php/trunk/src/main/php/Logger.php (original)
+++ logging/log4php/trunk/src/main/php/Logger.php Sun Oct 16 07:12:49 2011
@@ -54,10 +54,10 @@ class Logger {
 		'LoggerNDC' => '/LoggerNDC.php',
 		'LoggerReflectionUtils' => '/LoggerReflectionUtils.php',
 		'LoggerConfigurator' => '/LoggerConfigurator.php',
-		'LoggerConfiguratorBasic' => '/configurators/LoggerConfiguratorBasic.php',
-		'LoggerConfiguratorIni' => '/configurators/LoggerConfiguratorIni.php',
-		'LoggerConfiguratorPhp' => '/configurators/LoggerConfiguratorPhp.php',
-		'LoggerConfiguratorXml' => '/configurators/LoggerConfiguratorXml.php',
+		'LoggerConfigurationAdapter' => '/configurators/LoggerConfigurationAdapter.php',
+		'LoggerConfigurationAdapterINI' => '/configurators/LoggerConfigurationAdapterINI.php',
+		'LoggerConfigurationAdapterXML' => '/configurators/LoggerConfigurationAdapterXML.php',
+		'LoggerConfigurationAdapterPHP' => '/configurators/LoggerConfigurationAdapterPHP.php',
 		'LoggerRoot' => '/LoggerRoot.php',
 		'LoggerAppender' => '/LoggerAppender.php',
 		'LoggerAppenderPool' => '/LoggerAppenderPool.php',
@@ -154,16 +154,10 @@ class Logger {
 	private static $hierarchy;
 	
 	/** 
-	 * Name of the configurator class used to configure log4php. 
-	 * Populated by {@link configure()} and used in {@link initialize()}.
+	 * Holds the configurator. 
+	 * @var LoggerConfigurator 
 	 */
-	private static $configurationClass = 'LoggerConfiguratorBasic';
-	
-	/** 
-	 * Path to the configuration file which may be used by the configurator.
-	 * Populated by {@link configure()} and used in {@link initialize()}. 
-	 */
-	private static $configurationFile;
+	private static $configurator;
 	
 	/** Inidicates if log4php has been initialized */
 	private static $initialized = false;
@@ -344,26 +338,27 @@ class Logger {
 	/* Factory methods */ 
 	
 	/**
-	 * Get a Logger by name (Delegate to {@link Logger})
+	 * Returns a Logger by name. 
+	 * 
+	 * If it does not exist, it will be created.
 	 * 
 	 * @param string $name logger name
-	 * @param LoggerFactory $factory a {@link LoggerFactory} instance or null
 	 * @return Logger
 	 */
 	public static function getLogger($name) {
 		if(!self::isInitialized()) {
-			self::initialize();
+			self::configure();
 		}
 		return self::getHierarchy()->getLogger($name);
 	}
 	
 	/**
-	 * Get the Root Logger (Delegate to {@link Logger})
+	 * Returns the Root Logger.
 	 * @return LoggerRoot
 	 */	   
 	public static function getRootLogger() {
 		if(!self::isInitialized()) {
-			self::initialize();
+			self::configure();
 		}
 		return self::getHierarchy()->getRootLogger();	  
 	}
@@ -485,14 +480,11 @@ class Logger {
 	
 	/**
 	 * Destroy configurations for logger definitions
-	 * @return boolean 
 	 */
 	public static function resetConfiguration() {
-		$result = self::getHierarchy()->resetConfiguration();
+		self::getHierarchy()->resetConfiguration();
+		self::getHierarchy()->clear(); // TODO: clear or not?
 		self::$initialized = false;
-		self::$configurationClass = 'LoggerConfiguratorBasic';
-		self::$configurationFile = null;
-		return $result;	 
 	}
 
 	/**
@@ -550,58 +542,20 @@ class Logger {
 	} 
 	
 	/**
-	 * Configures log4php by defining a configuration file and/or class.
+	 * Configures log4php.
 	 * 
 	 * This method needs to be called before the first logging event has 
-	 * occured. If this method is not called before then, the standard 
-	 * configuration takes place (@see LoggerConfiguratorBasic).
-	 * 
-	 * If only the configuration file is given, the configurator class will
-	 * be determined by the config file extension.  
-	 * 
-	 * If a custom configurator class is provided, the configuration file
-	 * should either be null or contain the path to file used by the custom 
-	 * configurator. Make sure the configurator class is already loaded, or
-	 * that it can be included by PHP when necessary.
-	 * 
-	 * @param string $configurationFile path to the configuration file
-	 * @param string $configurationClass name of the custom configurator class 
-	 */
-	public static function configure($configurationFile = null, $configurationClass = null ) {
-		if($configurationClass === null && $configurationFile === null) {
-			self::$configurationClass = 'LoggerConfiguratorBasic';
-			return;
-		}
-									 	
-		if($configurationClass !== null) {
-			self::$configurationFile = $configurationFile;
-			self::$configurationClass = $configurationClass;
-			return;
-		}
-		
-		if (strtolower(substr( $configurationFile, -4 )) == '.xml') {
-			self::$configurationFile = $configurationFile;
-			self::$configurationClass = 'LoggerConfiguratorXml';
-		} else {
-			self::$configurationFile = $configurationFile;
-			self::$configurationClass = 'LoggerConfiguratorIni';
-		}
-	}
-	
-	/**
-	 * Returns the current {@link Logger::$configurationClass configurator class}.
-	 * @return string the configurator class name
-	 */
-	public static function getConfigurationClass() {
-		return self::$configurationClass;
-	}
-	
-	/**
-	 * Returns the current {@link Logger::$configurationFile configuration file}.
-	 * @return string the configuration file
+	 * occured. If this method is not called before then the default
+	 * configuration will be used.
+	 *
+	 * @param string|array $configuration Either a path to the configuration
+	 *   file, or a configuration array.
 	 */
-	public static function getConfigurationFile() {
-		return self::$configurationFile;
+	public static function configure($configuration = null) {
+		self::resetConfiguration();
+		$configurator = new LoggerConfigurator();
+		$configurator->configure(self::getHierarchy(), $configuration);
+		self::$initialized = true;
 	}
 	
 	/**
@@ -612,16 +566,4 @@ class Logger {
 		return self::$initialized;
 	}
 	
-	/**
-	 * Initializes the log4php framework using the provided {@link 
-	 * Logger::$configurationClass configuration class}  and {@link 
-	 * Logger::$configurationFile configuration file}.
-	 * @return boolean
-	 */
-	public static function initialize() {
-		self::$initialized = true;
-		$instance = LoggerReflectionUtils::createObject(self::$configurationClass);
-		$result = $instance->configure(self::getHierarchy(), self::$configurationFile);
-		return $result;
-	}
 }

Modified: logging/log4php/trunk/src/main/php/LoggerAppenderPool.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/LoggerAppenderPool.php?rev=1184770&r1=1184769&r2=1184770&view=diff
==============================================================================
--- logging/log4php/trunk/src/main/php/LoggerAppenderPool.php (original)
+++ logging/log4php/trunk/src/main/php/LoggerAppenderPool.php Sun Oct 16 07:12:49 2011
@@ -19,42 +19,81 @@
  */
 
 /**
- * Pool implmentation for LoggerAppender instances
+ * Pool implmentation for LoggerAppender instances.
+ * 
+ * The pool is used when configuring log4php. First all appender instances 
+ * are created in the pool. Afterward, they are linked to loggers, each 
+ * appender can be linked to multiple loggers. This makes sure duplicate 
+ * appenders are not created.
  *
  * @version $Revision: 795727 $
  * @package log4php
  */
 class LoggerAppenderPool {
-	/* Appender Pool */
-	public static $appenderPool =  array();
 	
+	/** Holds appenders indexed by their name */
+	public static $appenders =  array();
+
 	/**
-	 * 
-	 *
-	 * @param string $name 
-	 * @param string $class 
-	 * @return LoggerAppender
+	 * Adds an appender to the pool. 
+	 * The appender must be named for this operation. 
+	 * @param LoggerAppender $appender
 	 */
-	public static function getAppenderFromPool($name, $class = '') {
-		if(isset(self::$appenderPool[$name])) {
-			return self::$appenderPool[$name];
-		}
+	public static function add(LoggerAppender $appender)
+	{
+		$name = $appender->getName();
 		
-		if(empty($class)) {
-			return null;
+		if(empty($name)) {
+			trigger_error('log4php: Cannot add unnamed appender to pool.', E_USER_WARNING);
+			return;
 		}
 		
-		$appender = LoggerReflectionUtils::createObject($class);
-		$appender->setName($name);
-		if($appender !== null) { 
-			self::$appenderPool[$name] = $appender;
-			return self::$appenderPool[$name];
+		if (isset(self::$appenders[$name])) {
+			trigger_error("log4php: Appender [$name] already exists in pool. Overwriting existing appender.", E_USER_WARNING);
 		}
-		return null;		
+		
+		self::$appenders[$name] = $appender;
 	}
 	
-	public static function clear()
-	{
-		 self::$appenderPool =  array();
+	/** 
+	 * Retrieves an appender from the pool by name. 
+	 * @param string $name Name of the appender to retrieve.
+	 * @return LoggerAppender The named appender or NULL if no such appender 
+	 *  exists in the pool.
+	 */
+	public static function get($name) {
+		return isset(self::$appenders[$name]) ? self::$appenders[$name] : null;
+	}
+	
+	/**
+	* Removes an appender from the pool by name.
+	* @param string $name Name of the appender to remove.
+	*/
+	public static function delete($name) {
+		unset(self::$appenders[$name]);
+	}
+	
+	/**
+	 * Returns all appenders from the pool.
+	 * @return array Array of LoggerAppender objects.
+	 */
+	public static function getAppenders() {
+		return self::$appenders;
+	}
+	
+	/**
+	 * Checks whether an appender exists in the pool.
+	 * @param string $name Name of the appender to look for.
+	 * @return boolean TRUE if the appender with the given name exists.
+	 */
+	public static function exists($name) {
+		return isset(self::$appenders[$name]);
+	}
+
+	/**
+	 * Clears all appenders from the pool.
+	 */
+	public static function clear() {
+		 self::$appenders =  array();
 	}
 }
\ No newline at end of file

Modified: logging/log4php/trunk/src/main/php/LoggerConfigurator.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/LoggerConfigurator.php?rev=1184770&r1=1184769&r2=1184770&view=diff
==============================================================================
--- logging/log4php/trunk/src/main/php/LoggerConfigurator.php (original)
+++ logging/log4php/trunk/src/main/php/LoggerConfigurator.php Sun Oct 16 07:12:49 2011
@@ -19,35 +19,426 @@
  */
 
 /**
- * Implemented by classes capable of configuring log4php using a URL.
- *	
- * @version $Revision$
+ * Configures log4php based on a provided configuration file or array.
+ * 
  * @package log4php
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
+ * @version $Revision$
+ * @since 2.2
  */
-interface LoggerConfigurator {
+class LoggerConfigurator
+{
+	/** XML configuration file format. */
+	const FORMAT_XML = 'xml';
+	
+	/** PHP configuration file format. */
+	const FORMAT_PHP = 'php';
+	
+	/** INI (properties) configuration file format. */
+	const FORMAT_INI = 'ini';
+
+	/** Defines which adapter should be used for parsing which format. */
+	private $adapters = array(
+		self::FORMAT_XML => 'LoggerConfigurationAdapterXML',
+		self::FORMAT_INI => 'LoggerConfigurationAdapterINI',
+		self::FORMAT_PHP => 'LoggerConfigurationAdapterPHP',
+	);
+	
+	/** Default configuration; used if no configuration file is provided. */
+	private static $defaultConfiguration = array(
+        'threshold' => 'ALL',
+        'rootLogger' => array(
+            'level' => 'DEBUG',
+            'appenders' => array('default'),
+        ),
+        'appenders' => array(
+            'default' => array(
+                'class' => 'LoggerAppenderEcho',
+                'layout' => array(
+                    'class' => 'LoggerLayoutTTCC',
+                ),
+            ),
+        ),
+	);
+	
+	/** Holds the appenders before they are linked to loggers. */
+	private $appenders = array();
 	
 	/**
-	 * Special level value signifying inherited behaviour. The current
-	 * value of this string constant is <b>inherited</b>. 
-	 * {@link CONFIGURATOR_NULL} is a synonym.  
+	 * Configures log4php based on the given configuration. The input can 
+	 * either be a path to the config file, or a PHP array holding the 
+	 * configuration. 
+	 * 
+	 * If no configuration is given, or if the given configuration cannot be
+	 * parsed for whatever reason, a warning will be issued, and log4php
+	 * will use the default configuration contained in 
+	 * {@link $defaultConfiguration}.
+	 * 
+	 * @param LoggerHierarchy $hierarchy The hierarchy on which to perform 
+	 * 		the configuration. 
+	 * @param string|array $input Either path to the config file or the 
+	 * 		configuration as an array. If not set, default configuration 
+	 * 		will be used.
 	 */
-	const CONFIGURATOR_INHERITED = 'inherited';
+	public function configure(LoggerHierarchy $hierarchy, $input = null) {
+		$config = $this->parse($input);
+		$this->doConfigure($hierarchy, $config);
+	}
 	
 	/**
-	 * Special level signifying inherited behaviour, same as 
-	 * {@link CONFIGURATOR_INHERITED}. 
-	 * The current value of this string constant is <b>null</b>. 
+	 * Parses the given configuration and returns the parsed configuration
+	 * as a PHP array. Does not perform any configuration. 
+	 * 
+	 * If no configuration is given, or if the given configuration cannot be
+	 * parsed for whatever reason, a warning will be issued, and the default 
+	 * configuration will be returned ({@link $defaultConfiguration}).
+	 * 
+	 * @param string|array $input Either path to the config file or the 
+	 * 		configuration as an array. If not set, default configuration 
+	 * 		will be used.
+	 * @return array The parsed configuration.
 	 */
-	const CONFIGURATOR_NULL = 'null';
+	public function parse($input)
+	{
+		// No input - use default configuration
+		if (!isset($input)) {
+			$config = self::$defaultConfiguration;
+		}
+		
+		// Array input - contains configuration within the array
+		else if (is_array($input)) {
+			$config = $input;
+		}
 		
+		// String input - contains path to configuration file
+		else if (is_string($input)) {
+			try {
+				$config = $this->parseFile($input);
+			} catch (LoggerException $e) {
+				$this->warn("Configuration failed. " . $e->getMessage() . " Using default configuration.");
+				$config = self::$defaultConfiguration;
+			}
+		}
+		
+		// Anything else is an error
+		else {
+			$this->warn("Invalid configuration param given. Reverting to default configuration.");
+			$config = self::$defaultConfiguration;
+		}
+		
+		return $config;
+	}
+
+	/** 
+	 * Returns the default log4php configuration.
+	 * @return array
+	 */
+	public static function getDefaultConfiguration() {
+		return self::$defaultConfiguration;
+	} 
+	
 	/**
-	 * Interpret a resource pointed by a <var>url</var> and configure accordingly.
-	 *
-	 * The configuration is done relative to the <var>repository</var>
-	 * parameter.
+	 * Loads the configuration file from the given URL, determines which
+	 * adapter to use, converts the configuration to a PHP array and
+	 * returns it.
 	 *
-	 * @param string $url The URL to parse
+	 * @param string $url Path to the config file.
+	 * @return The configuration from the config file, as a PHP array.
+	 * @throws LoggerException If the configuration file cannot be loaded, or
+	 * 		if the parsing fails.
+	 */
+	private function parseFile($url) {
+		
+		if (!file_exists($url)) {
+			throw new LoggerException("File not found at [$url].");
+		}
+		
+		$type = $this->getConfigType($url);
+		$adapterClass = $this->adapters[$type];
+
+		$adapter = new $adapterClass();
+		return $adapter->convert($url);
+	}
+	
+	/** Determines configuration file type based on the file extension. */
+	private function getConfigType($url) {
+		$info = pathinfo($url);
+		$ext = strtolower($info['extension']);
+		
+		switch($ext) {
+			case 'xml':
+				return self::FORMAT_XML;
+			
+			case 'ini':
+			case 'properties':
+				return self::FORMAT_INI;
+			
+			case 'php':
+				return self::FORMAT_PHP;
+				
+			default:
+				throw new LoggerException("Unsupported configuration file extension: $ext");
+		}
+	}
+	
+	/**
+	 * Constructs the logger hierarchy based on configuration.
+	 * 
+	 * @param LoggerHierarchy $hierarchy
+	 * @param array $config
+	 */
+	private function doConfigure(LoggerHierarchy $hierarchy, $config) {
+		if (isset($config['threshold'])) {
+			$threshold = LoggerLevel::toLevel($config['threshold']);
+			if (isset($threshold)) {
+				$hierarchy->setThreshold($threshold);
+			} else {
+				$this->warn("Invalid threshold {$config['threshold']} specified.");
+			}
+		}
+		
+		// Configure appenders and add them to the appender pool
+		if (isset($config['appenders']) && is_array($config['appenders'])) {
+			foreach($config['appenders'] as $name => $appenderConfig) {
+				$this->configureAppender($name, $appenderConfig);
+			}
+		}
+		
+		// Configure root logger 
+		if (isset($config['rootLogger'])) {
+			$this->configureRootLogger($hierarchy, $config['rootLogger']);
+		}
+		
+		// Configure loggers
+		if (isset($config['loggers']) && is_array($config['loggers'])) {
+			foreach($config['loggers'] as $loggerName => $loggerConfig) {
+				$this->configureOtherLogger($hierarchy, $loggerName, $loggerConfig);
+			}
+		}
+
+		// Configure renderers
+		if (isset($config['renderers']) && is_array($config['renderers'])) {
+			foreach($config['renderers'] as $renderer) {
+				$hierarchy->getRendererMap()->addRenderer($renderer['renderedClass'], $renderer['renderingClass']);
+			}
+		}
+	}
+	
+	/** 
+	 * Configures an appender based on given config and saves it to 
+	 * {@link $appenders} array so it can be later linked to loggers. 
+	 * @param string $name Appender name. 
+	 * @param array $config Appender configuration options.
+	 */
+	private function configureAppender($name, $config) {
+
+		// TODO: add this check to other places where it might be useful
+		if (!is_array($config)) {
+			$type = gettype($config);
+			$this->warn("Invalid configuration provided for [$name] appender. Expected an array, found <$type>. Skipping appender definition.");
+			return;
+		}
+		
+		// Parse appender class
+		$class = $config['class'];
+		if (!class_exists($class)) {
+			$this->warn("Class [$class] does not exist. Skipping appender [$name].");
+			return;
+		}
+		
+		// Instantiate the appender
+		$appender = new $class($name);
+		if (!($appender instanceof LoggerAppender)) {
+			$this->warn("[$class] is not a valid appender class. Skipping appender [$name].");
+			return;
+		}
+		
+		// Parse the appender threshold
+		if (isset($config['threshold'])) {
+			$threshold = LoggerLevel::toLevel($config['threshold']);
+			if ($threshold instanceof LoggerLevel) {
+				$appender->setThreshold($threshold);
+			} else {
+				$default = $appender->getThreshold();
+				$this->warn("Invalid threshold value [{$config['threshold']}] specified for appender [$name]. Reverting to default value [$default].");
+			}
+		}
+		
+		// Parse the appender layout
+		if ($appender->requiresLayout() && isset($config['layout'])) {
+			$this->createAppenderLayout($appender, $config['layout']);
+		}
+		
+		// Parse filters
+		if (isset($config['filters']) && is_array($config['filters'])) {
+			foreach($config['filters'] as $filterConfig) {
+				$this->createAppenderFilter($appender, $filterConfig);
+			}
+		}
+		
+		// Set options if any
+		if (isset($config['params'])) {
+			$this->setOptions($appender, $config['params']);
+		}
+
+		// Activate and save for later linking to loggers
+		$appender->activateOptions();
+		$this->appenders[$name] = $appender;
+	}
+	
+	/**
+	 * Parses layout config, creates the layout and links it to the appender.
+	 * @param LoggerAppender $appender
+	 * @param array $config Layout configuration.
+	 */
+	private function createAppenderLayout(LoggerAppender $appender, $config) {
+		$name = $appender->getName();
+		$class = $config['class'];
+		if (!class_exists($class)) {
+			$this->warn("Nonexistant layout class [$class] specified for appender [$name]. Reverting to default layout.");
+			return;
+		}
+		
+		$layout = new $class();
+		if (!($layout instanceof LoggerLayout)) {
+			$this->warn("Invalid layout class [$class] sepcified for appender [$name]. Reverting to default layout.");
+			return;
+		}
+		
+		if (isset($config['params'])) {
+			$this->setOptions($layout, $config['params']);
+		}
+		
+		$layout->activateOptions();
+		$appender->setLayout($layout);
+	}
+	
+	/**
+	 * Parses filter config, creates the filter and adds it to the appender's 
+	 * filter chain.
+	 * @param LoggerAppender $appender
+	 * @param array $config Filter configuration.
+	 */
+	private function createAppenderFilter(LoggerAppender $appender, $config) {
+		$name = $appender->getName();
+		$class = $config['class'];
+		if (!class_exists($class)) {
+			$this->warn("Nonexistant filter class [$class] specified on appender [$name]. Skipping filter definition.");
+			return;
+		}
+	
+		$filter = new $class();
+		if (!($filter instanceof LoggerFilter)) {
+			$this->warn("Invalid filter class [$class] sepcified on appender [$name]. Skipping filter definition.");
+			return;
+		}
+	
+		if (isset($config['params'])) {
+			$this->setOptions($filter, $config['params']);
+		}
+	
+		$filter->activateOptions();
+		$appender->addFilter($filter);
+	}
+	
+	/** 
+	 * Configures the root logger
+	 * @see configureLogger() 
+	 */
+	private function configureRootLogger(LoggerHierarchy $hierarchy, $config) {
+		$logger = $hierarchy->getRootLogger();
+		$this->configureLogger($logger, $config);
+	}
+
+	/**
+	 * Configures a logger which is not root.
+	 * @see configureLogger()
+	 */
+	private function configureOtherLogger(LoggerHierarchy $hierarchy, $name, $config) {
+		// Get logger from hierarchy (this creates it if it doesn't already exist)
+		$logger = $hierarchy->getLogger($name);
+		$this->configureLogger($logger, $config);
+	}
+	
+	/**
+	 * Configures a logger. 
+	 * 
+	 * @param Logger $logger The logger to configure
+	 * @param array $config Logger configuration options.
+	 */
+	private function configureLogger(Logger $logger, $config) {
+		$loggerName = $logger->getName();
+		
+		// Set logger level
+		if (isset($config['level'])) {
+			$level = LoggerLevel::toLevel($config['level']);
+			if (isset($level)) {
+				$logger->setLevel($level);
+			} else {
+				$default = $logger->getLevel();
+				$this->warn("Invalid logger level [{$config['level']}] specified for logger [$loggerName].");
+			}
+		}
+		
+		// Link appenders to logger
+		if (isset($config['appenders'])) {
+			foreach($config['appenders'] as $appenderName) {
+				if (isset($this->appenders[$appenderName])) {
+					$logger->addAppender($this->appenders[$appenderName]);
+				} else {
+					$this->warn("Nonexistnant appender [$appenderName] linked to logger [$loggerName].");
+				}
+			}
+		}
+		
+		// Set logger additivity
+		if (isset($config['additivity'])) {
+			$additivity = LoggerOptionConverter::toBoolean($config['additivity'], null);
+			if (is_bool($additivity)) {
+				$logger->setAdditivity($additivity);
+			} else {
+				$this->warn("Invalid additivity value [{$config['additivity']}] specified for logger [$loggerName].");
+			}
+		}
+	}
+
+	/**
+	 * Helper method which applies given options to an object which has setters
+	 * for these options (such as appenders, layouts, etc.).
+	 * 
+	 * For example, if options are:
+	 * <code>
+	 * array(
+	 * 	'file' => '/tmp/myfile.log',
+	 * 	'append' => true
+	 * )
+	 * </code>
+	 * 
+	 * This method will call:
+	 * <code>
+	 * $object->setFile('/tmp/myfile.log')
+	 * $object->setAppend(true)
+	 * </code>
+	 * 
+	 * If required setters do not exist, it will produce a warning. 
+	 * 
+	 * @param mixed $object The object to configure.
+	 * @param unknown_type $options
 	 */
-	public function configure(LoggerHierarchy $hierarchy, $url = null);
+	private function setOptions($object, $options) {
+		foreach($options as $name => $value) {
+			$setter = "set$name";
+			if (method_exists($object, $setter)) {
+				$object->$setter($value);
+			} else {
+				$class = get_class($object);
+				$this->warn("Nonexistant option [$name] specified on [$class]. Skipping.");
+			}
+		}
+	}
 	
-}
+	/** Helper method to simplify error reporting. */
+	private function warn($message) {
+		trigger_error("log4php: $message", E_USER_WARNING);
+	}
+}
\ No newline at end of file

Modified: logging/log4php/trunk/src/main/php/appenders/LoggerAppenderConsole.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/appenders/LoggerAppenderConsole.php?rev=1184770&r1=1184769&r2=1184770&view=diff
==============================================================================
--- logging/log4php/trunk/src/main/php/appenders/LoggerAppenderConsole.php (original)
+++ logging/log4php/trunk/src/main/php/appenders/LoggerAppenderConsole.php Sun Oct 16 07:12:49 2011
@@ -71,6 +71,10 @@ class LoggerAppenderConsole extends Logg
 		}
 	}
 
+	public function getTarget() {
+		return $this->target;
+	}
+
 	public function activateOptions() {
 		$this->fp = fopen($this->target, 'w');
 		if(is_resource($this->fp) && $this->layout !== null) {

Added: logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapter.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapter.php?rev=1184770&view=auto
==============================================================================
--- logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapter.php (added)
+++ logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapter.php Sun Oct 16 07:12:49 2011
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 log4php
+ */
+
+/**
+ * The interface for configurator adapters.
+ * 
+ * Adapters convert configuration in several formats such as XML, ini and PHP 
+ * file to a PHP array. 
+ * 
+ * @package log4php
+ * @subpackage configurators
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
+ * @version $Revision$
+ * @since 2.2
+ */
+interface LoggerConfigurationAdapter
+{
+	/** Converts the configuration file to PHP format usable by the configurator. */
+	public function convert($input); 
+
+}
+
+?>
\ No newline at end of file

Added: logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterINI.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterINI.php?rev=1184770&view=auto
==============================================================================
--- logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterINI.php (added)
+++ logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterINI.php Sun Oct 16 07:12:49 2011
@@ -0,0 +1,306 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 log4php
+ */
+
+/**
+ * Converts ini configuration files to a PHP array.
+ * 
+ * These used to be called "properties" files (inherited from log4j), and that 
+ * file extension is still supported. 
+ *
+ * @package log4php
+ * @subpackage configurators
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
+ * @version $Revision$
+ * @since 2.2
+ */
+class LoggerConfigurationAdapterINI implements LoggerConfigurationAdapter {
+	
+	/** Name to assign to the root logger. */
+	const ROOT_LOGGER_NAME = "root";
+
+	/** Prefix used for defining logger additivity. */
+	const ADDITIVITY_PREFIX = "log4php.additivity.";
+	
+	/** Prefix used for defining logger threshold. */
+	const THRESHOLD_PREFIX = "log4php.threshold";
+	
+	/** Prefix used for defining the root logger. */
+	const ROOT_LOGGER_PREFIX = "log4php.rootLogger";
+	
+	/** Prefix used for defining a logger. */
+	const LOGGER_PREFIX = "log4php.logger.";
+	
+	/** Prefix used for defining an appender. */
+	const APPENDER_PREFIX = "log4php.appender.";
+	
+	/** Prefix used for defining a renderer. */
+	const RENDERER_PREFIX = "log4php.renderer.";
+	
+	/** Holds the configuration. */
+	private $config = array();
+	
+	/**
+	 * Loads and parses the INI configuration file.
+	 * 
+	 * INI_SCANNER_RAW is used here because otherwise parse_ini_file() will 
+	 * try to parse all values, with some strange results. For example, "true"
+	 * will become "1", while "false" and "null" will become "" (empty string). 
+	 * 
+	 * @see http://php.net/manual/en/function.parse-ini-file.php
+	 * 
+	 * @param string $url Path to the config file.
+	 * @throws LoggerException
+	 */
+	private function load($url) {
+		if (!file_exists($url)) {
+			throw new LoggerException("File [$url] does not exist.");
+		}
+		
+		$properties = @parse_ini_file($url, true, INI_SCANNER_RAW);
+		if ($properties === false) {
+			$error = error_get_last();
+			throw new LoggerException("Error parsing configuration file: {$error['message']}");
+		}
+		
+		return $properties;
+	}
+	
+	/**
+	* Converts the provided INI configuration file to a PHP array config.
+	*
+	* @param string $path Path to the config file.
+	* @throws LoggerException If the file cannot be loaded or parsed.
+	*/
+	public function convert($path) {
+		// Load the configuration
+		$properties = $this->load($path);
+		
+		// Parse threshold
+		if (isset($properties[self::THRESHOLD_PREFIX])) {
+			$this->config['threshold'] = $properties[self::THRESHOLD_PREFIX]; 
+		}
+		
+		// Parse root logger
+		if (isset($properties[self::ROOT_LOGGER_PREFIX])) {
+			$this->parseLogger($properties[self::ROOT_LOGGER_PREFIX], self::ROOT_LOGGER_NAME);
+		}
+		
+		$appenders = array();
+		
+		foreach($properties as $key => $value) {
+			// Parse loggers
+			if ($this->beginsWith($key, self::LOGGER_PREFIX)) {
+				$name = substr($key, strlen(self::LOGGER_PREFIX));
+				$this->parseLogger($value, $name);
+			}
+			
+			// Parse additivity
+			if ($this->beginsWith($key, self::ADDITIVITY_PREFIX)) {
+				$name = substr($key, strlen(self::ADDITIVITY_PREFIX));
+				$this->config['loggers'][$name]['additivity'] = $value;
+			}
+			
+			// Parse appenders
+			else if ($this->beginsWith($key, self::APPENDER_PREFIX)) {
+				$this->parseAppender($key, $value);
+			}
+			
+			// Parse renderers
+			else if ($this->beginsWith($key, self::RENDERER_PREFIX)) {
+				$this->parseRenderer($key, $value);
+			}
+		}
+		
+		return $this->config;
+	}
+	
+	
+	/**
+	 * Parses a logger definition.
+	 * 
+	 * Loggers are defined in the following manner:
+	 * <pre>
+	 * log4php.logger.<name> = [<level>], [<appender-ref>, <appender-ref>, ...] 
+	 * </pre>
+	 * 
+	 * @param string $value The configuration value (level and appender-refs).
+	 * @param string $name Logger name. 
+	 */
+	private function parseLogger($value, $name) {
+		// Value is divided by commas
+		$parts = explode(',', $value);
+		if (empty($value) || empty($parts)) {
+			return;
+		}
+
+		// The first value is the logger level 
+		$level = array_shift($parts);
+		
+		// The remaining values are appender references 
+		$appenders = array();
+		while($appender = array_shift($parts)) {
+			$appender = trim($appender);
+			if (!empty($appender)) {
+				$appenders[] = trim($appender);
+			}
+		}
+
+		// Find the target configuration 
+		if ($name == self::ROOT_LOGGER_NAME) {
+			$this->config['rootLogger']['level'] = trim($level);
+			$this->config['rootLogger']['appenders'] = $appenders;
+		} else {
+			$this->config['loggers'][$name]['level'] = trim($level);
+			$this->config['loggers'][$name]['appenders'] = $appenders;
+		}
+	}
+	
+	/**
+	 * Parses an configuration line pertaining to an appender.
+	 * 
+	 * Parses the following patterns:
+	 * 
+	 * Appender class:
+	 * <pre>
+	 * log4php.appender.<name> = <class>
+	 * </pre>
+	 * 
+	 * Appender parameter:
+	 * <pre>
+	 * log4php.appender.<name>.<param> = <value>
+	 * </pre>
+	 * 
+ 	 * Appender threshold:
+	 * <pre>
+	 * log4php.appender.<name>.threshold = <level>
+	 * </pre>
+	 * 
+ 	 * Appender layout:
+	 * <pre>
+	 * log4php.appender.<name>.layout = <layoutClass>
+	 * </pre>
+	 * 
+	 * Layout parameter:
+	 * <pre>
+	 * log4php.appender.<name>.layout.<param> = <value>
+	 * </pre> 
+	 * 
+	 * For example, a full appender config might look like:
+	 * <pre>
+	 * log4php.appender.myAppender = LoggerAppenderConsole
+	 * log4php.appender.myAppender.threshold = info
+	 * log4php.appender.myAppender.target = stdout
+	 * log4php.appender.myAppender.layout = LoggerLayoutPattern
+	 * log4php.appender.myAppender.layout.conversionPattern = "%d %c: %m%n"
+	 * </pre>
+	 * 
+	 * After parsing all these options, the following configuration can be 
+	 * found under $this->config['appenders']['myAppender']:
+	 * <pre>
+	 * array(
+	 * 	'class' => LoggerAppenderConsole,
+	 * 	'threshold' => info,
+	 * 	'params' => array(
+	 * 		'target' => 'stdout'
+	 * 	),
+	 * 	'layout' => array(
+	 * 		'class' => 'LoggerAppenderConsole',
+	 * 		'params' => array(
+	 * 			'conversionPattern' => '%d %c: %m%n'
+	 * 		)
+	 * 	)
+	 * )
+	 * </pre>
+	 * 
+	 * @param string $key
+	 * @param string $value
+	 */
+	private function parseAppender($key, $value) {
+
+		// Remove the appender prefix from key
+		$subKey = substr($key, strlen(self::APPENDER_PREFIX));
+		
+		// Divide the string by dots
+		$parts = explode('.', $subKey);
+		$count = count($parts);
+		
+		// The first part is always the appender name
+		$name = trim($parts[0]);
+		
+		// Only one part - this line defines the appender class 
+		if ($count == 1) {
+			$this->config['appenders'][$name]['class'] = $value;
+			return;
+		}
+		
+		// Two parts - either a parameter, a threshold or layout class
+		else if ($count == 2) {
+			
+			if ($parts[1] == 'layout') {
+				$this->config['appenders'][$name]['layout']['class'] = $value;
+				return;
+			} else if ($parts[1] == 'threshold') {
+				$this->config['appenders'][$name]['threshold'] = $value;
+				return;
+			} else {
+				$this->config['appenders'][$name]['params'][$parts[1]] = $value;
+				return;
+			}
+		}
+		
+		// Three parts - this can only be a layout parameter
+		else if ($count == 3) {
+			if ($parts[1] == 'layout') {
+				$this->config['appenders'][$name]['layout']['params'][$parts[2]] = $value;
+				return;
+			}
+		}
+		
+		trigger_error("log4php: Don't know how to parse the following line: \"$key = $value\". Skipping.");
+	}
+
+	/**
+	 * Parses a renderer definition.
+	 * 
+	 * Renderers are defined as:
+	 * <pre>
+	 * log4php.renderer.<renderedClass> = <renderingClass> 
+	 * </pre>
+	 * 
+	 * @param string $key log4php.renderer.<renderedClass>
+	 * @param string $value <renderingClass>
+	 */
+	private function parseRenderer($key, $value) {
+		// Remove the appender prefix from key
+		$renderedClass = substr($key, strlen(self::APPENDER_PREFIX));
+		$renderingClass = $value;
+		
+		$this->config['renderers'][] = compact('renderedClass', 'renderingClass');
+	}
+	
+	/** Helper method. Returns true if $str begins with $sub. */
+	private function beginsWith($str, $sub) {
+		return (strncmp($str, $sub, strlen($sub)) == 0);
+	}
+	
+	
+}
+
+?>
\ No newline at end of file

Added: logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterPHP.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterPHP.php?rev=1184770&view=auto
==============================================================================
--- logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterPHP.php (added)
+++ logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterPHP.php Sun Oct 16 07:12:49 2011
@@ -0,0 +1,85 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 log4php
+ */
+
+/**
+ * Converts PHP configuration files to a PHP array.
+ * 
+ * The file should only hold the PHP config array preceded by "return".
+ * 
+ * Example PHP config file:
+ * <code>
+ * <?php
+ * return array(
+ *   'rootLogger' => array(
+ *     'level' => 'info',
+ *     'appenders' => array('default')
+ *   ),
+ *   'appenders' => array(
+ *     'default' => array(
+ *       'class' => 'LoggerAppenderEcho',
+ *       'layout' => array(
+ *       	'class' => 'LoggerLayoutSimple'
+ *        )
+ *     )
+ *   )
+ * )
+ * ?>
+ * </code>
+ * 
+ * @package log4php
+ * @subpackage configurators
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
+ * @version $Revision$
+ * @since 2.2
+ */
+class LoggerConfigurationAdapterPHP implements LoggerConfigurationAdapter
+{
+	public function convert($url) {
+		if (!file_exists($url)) {
+			throw new LoggerException("File [$url] does not exist.");
+		}
+		
+		// Load the config file
+		$data = @file_get_contents($url);
+		if ($data === false) {
+			$error = error_get_last();
+			throw new LoggerException("Error loading config file: {$error['message']}");
+		}
+		
+		$config = @eval('?>' . $data);
+		
+		if ($config === false) {
+			$error = error_get_last();
+			throw new LoggerException("Error parsing configuration: " . $error['message']);
+		}
+		
+		if (empty($config)) {
+			throw new LoggerException("Invalid configuration: empty configuration array.");
+		}
+		
+		if (!is_array($config)) {
+			throw new LoggerException("Invalid configuration: not an array.");
+		}
+		
+		return $config;
+	}
+}
+
+?>
\ No newline at end of file

Added: logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterXML.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterXML.php?rev=1184770&view=auto
==============================================================================
--- logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterXML.php (added)
+++ logging/log4php/trunk/src/main/php/configurators/LoggerConfigurationAdapterXML.php Sun Oct 16 07:12:49 2011
@@ -0,0 +1,244 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 log4php
+ */
+
+/**
+ * Converts XML configuration files to a PHP array.
+ * 
+ * @package log4php
+ * @subpackage configurators
+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
+ * @version $Revision$
+ * @since 2.2
+ */
+class LoggerConfigurationAdapterXML implements LoggerConfigurationAdapter
+{
+	/** Path to the XML schema used for validation. */
+	const SCHEMA_PATH = '/../xml/log4php.xsd';
+	
+	private $config = array(
+		'appenders' => array(),
+		'loggers' => array(),
+		'renderers' => array(),
+	);
+	
+	public function convert($url)
+	{
+		$xml = $this->loadXML($url);
+		
+		$this->parseConfiguration($xml);
+
+		// Parse the <root> node
+		if (isset($xml->root)) {		
+			$this->parseRootLogger($xml->root);
+		}
+		
+		// Process <logger> nodes
+		foreach($xml->logger as $logger) {
+			$this->parseLogger($logger);
+		} 
+		
+		// Process <appender> nodes
+		foreach($xml->appender as $appender) {
+			$this->parseAppender($appender);
+		}
+		
+		// Process <renderer> nodes
+		foreach($xml->renderer as $rendererNode) {
+			$this->parseRenderer($rendererNode);
+		}
+		return $this->config;
+	}
+	
+	/**
+	 * Loads and validates the XML.
+	 * @param string $url Input XML.
+	 */
+	private function loadXML($url) {
+		if (!file_exists($url)) {
+			throw new LoggerException("File [$url] does not exist.");
+		}
+		
+		// Load XML
+		$xml = simplexml_load_file($url);
+		if ($xml === false) {
+			throw new LoggerException("Error loading confuguration file.");
+		}
+		return $xml;
+	}
+	
+	/**
+	 * Parses the <configuration> node.
+	 */
+	private function parseConfiguration(SimpleXMLElement $xml) {
+		$attributes = $xml->attributes();
+		if (isset($attributes['threshold'])) {
+			$this->config['threshold'] = (string) $attributes['threshold'];
+		}
+	}
+	
+	/** Parses an <appender> node. */
+	private function parseAppender(SimpleXMLElement $node) {
+		$name = $this->getAttributeValue($node, 'name');
+
+		$appender = array();
+		$appender['class'] = $this->getAttributeValue($node, 'class');
+		
+		if (isset($node['threshold'])) {
+			$appender['threshold'] = $this->getAttributeValue($node, 'threshold');
+		}
+		
+		if (isset($node->layout)) {
+			$appender['layout']= $this->parseLayout($node->layout, $name);
+		}
+		
+		if (count($node->param) > 0) {
+			$appender['params'] = $this->parseParameters($node);
+		}
+		
+		foreach($node->filter as $filterNode) {
+			$appender['filters'][] = $this->parseFilter($filterNode);
+		}
+		
+		$this->config['appenders'][$name] = $appender;
+	}
+	
+	/** Parses a <layout> node. */
+	private function parseLayout(SimpleXMLElement $node, $appenderName) {
+		$layout = array();
+		$layout['class'] = $this->getAttributeValue($node, 'class');
+		
+		if (count($node->param) > 0) {
+			$layout['params'] = $this->parseParameters($node);
+		}
+		
+		return $layout;
+	}

+	/** Parses any <param> child nodes returning them in an array. */
+	private function parseParameters($paramsNode) {
+		$params = array();
+
+		foreach($paramsNode->param as $paramNode) {
+			if (empty($paramNode['name'])) {
+				$this->warn("Found parameter node without a name. Skipping parameter.");
+				continue;
+			}
+			
+			$name = $this->getAttributeValue($paramNode, 'name');
+			$value = $this->getAttributeValue($paramNode, 'value');
+			
+			$params[$name] = $value;
+		}
+
+		return $params;
+	}
+	
+	/** Parses a <root> node. */
+	private function parseRootLogger(SimpleXMLElement $node) {
+		$logger = array();
+		
+		if (isset($node->level)) {
+			$logger['level'] = $this->getAttributeValue($node->level, 'value');
+		}
+		
+		$logger['appenders'] = array();
+		foreach($node->appender_ref as $appender) {
+			$logger['appenders'][] = $this->getAttributeValue($appender, 'ref');
+		}
+		
+		$this->config['rootLogger'] = $logger;
+	}
+	
+	/** Parses a <logger> node. */
+	private function parseLogger(SimpleXMLElement $node) {
+		$logger = array();
+		
+		// Check logger name exists (mandatory because it is used as the array key)
+		if (empty($node['name'])) {
+			$this->warn("Found logger without a 'name' attribute. All loggers must be named. Skipping.");
+			return;
+		}
+		
+		$name = (string) $node['name'];
+		
+		if (isset($node->level)) {
+			$logger['level'] = $this->getAttributeValue($node->level, 'value');
+		}
+		
+		if (isset($node['additivity'])) {
+			$logger['additivity'] = $this->getAttributeValue($node, 'additivity');
+		}
+		
+		$logger['appenders'] = $this->parseAppenderReferences($node, $name);
+
+		// Check for duplicate loggers
+		if (isset($this->config['loggers'][$name])) {
+			$this->warn("Duplicate logger definition [$name]. Overwriting.");
+		}
+		
+		$this->config['loggers'][$name] = $logger;
+	}
+	
+	/** 
+	 * Parses a <logger> node for appender references and returns them in an array.
+	 */
+	private function parseAppenderReferences(SimpleXMLElement $node, $name) {
+		$refs = array();
+		foreach($node->appender_ref as $ref) {
+			$refs[] = $this->getAttributeValue($ref, 'ref');
+		}
+		
+		return $refs;
+	}
+	
+	/** Parses a <filter> node. */
+	private function parseFilter($filterNode) {
+		$filter = array();
+		$filter['class'] = $this->getAttributeValue($filterNode, 'class');
+		
+		if (count($filterNode->param) > 0) {
+			$filter['params'] = $this->parseParameters($filterNode);
+		}
+		
+		return $filter;
+	}
+	
+	/** Parses a <renderer> node. */
+	private function parseRenderer(SimpleXMLElement $node) {
+		$renderedClass = $this->getAttributeValue($node, 'renderedClass');
+		$renderingClass = $this->getAttributeValue($node, 'renderingClass');
+		
+		$this->config['renderers'][] = compact('renderedClass', 'renderingClass');
+	}
+	
+	// ******************************************
+	// ** Helper methods                       **
+	// ******************************************
+	
+	private function getAttributeValue(SimpleXMLElement $node, $name) {
+		$attrs = $node->attributes();
+		return isset($attrs[$name]) ? (string) $attrs[$name] : null;
+	}
+	
+	private function warn($message) {
+		trigger_error("log4php: " . $message, E_USER_WARNING);
+	}
+}
+
+?>
\ No newline at end of file

Modified: logging/log4php/trunk/src/main/php/helpers/LoggerNamedPatternConverter.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/helpers/LoggerNamedPatternConverter.php?rev=1184770&r1=1184769&r2=1184770&view=diff
==============================================================================
--- logging/log4php/trunk/src/main/php/helpers/LoggerNamedPatternConverter.php (original)
+++ logging/log4php/trunk/src/main/php/helpers/LoggerNamedPatternConverter.php Sun Oct 16 07:12:49 2011
@@ -57,6 +57,9 @@ class LoggerNamedPatternConverter extend
 		if($this->precision <= 0) {
 			return $n;
 		} else {
+			
+			// TODO: do this with explode()
+			
 			$len = strlen($n);
 			// We substract 1 from 'len' when assigning to 'end' to avoid out of
 			// bounds exception in return r.substring(end+1, len). This can happen if

Modified: logging/log4php/trunk/src/main/php/layouts/LoggerLayoutPattern.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/main/php/layouts/LoggerLayoutPattern.php?rev=1184770&r1=1184769&r2=1184770&view=diff
==============================================================================
--- logging/log4php/trunk/src/main/php/layouts/LoggerLayoutPattern.php (original)
+++ logging/log4php/trunk/src/main/php/layouts/LoggerLayoutPattern.php Sun Oct 16 07:12:49 2011
@@ -140,7 +140,7 @@ class LoggerLayoutPattern extends Logger
 	const DEFAULT_CONVERSION_PATTERN = '%m%n';
 
 	/** Default conversion TTCC Pattern */
-	const TTCC_CONVERSION_PATTERN = '%r [%t] %p %c %x - %m%n';
+	const TTCC_CONVERSION_PATTERN = '%d [%t] %p %c %x - %m%n';
 
 	/** The pattern. 
 	 * @var string */

Added: logging/log4php/trunk/src/test/php/LoggerConfiguratorTest.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/LoggerConfiguratorTest.php?rev=1184770&view=auto
==============================================================================
--- logging/log4php/trunk/src/test/php/LoggerConfiguratorTest.php (added)
+++ logging/log4php/trunk/src/test/php/LoggerConfiguratorTest.php Sun Oct 16 07:12:49 2011
@@ -0,0 +1,97 @@
+<?php
+ 
+
+/**
+ * 
+ * @group configurators
+ *
+ */
+ class LoggerConfiguratorTest extends PHPUnit_Framework_TestCase
+ {
+ 	/** Reset configuration after each test. */
+ 	public function setUp() {
+ 		Logger::resetConfiguration();
+ 	}
+ 	/** Reset configuration after each test. */
+ 	public function tearDown() {
+ 		Logger::resetConfiguration();
+ 	}
+ 	
+ 	/** Check default setup. */
+ 	public function testDefaultConfig() {
+ 		Logger::configure();
+ 		
+ 		$actual = Logger::getCurrentLoggers();
+ 		$expected = array();
+		$this->assertSame($expected, $actual);
+
+ 		$appenders = Logger::getRootLogger()->getAllAppenders();
+ 		$this->assertInternalType('array', $appenders);
+ 		$this->assertEquals(count($appenders), 1);
+ 		$this->assertSame('default', $appenders[0]->getName());
+ 		
+ 		$appender = $appenders[0];
+ 		$this->assertInstanceOf('LoggerAppenderEcho', $appender);
+ 		
+ 		$layout = $appender->getLayout();
+ 		$this->assertInstanceOf('LoggerLayoutTTCC', $layout);
+ 		
+ 		$root = Logger::getRootLogger();
+ 		$appenders = $root->getAllAppenders();
+ 		$this->assertInternalType('array', $appenders);
+ 		$this->assertEquals(count($appenders), 1);
+		
+ 		$actual = $root->getLevel();
+ 		$expected = LoggerLevel::getLevelDebug();
+ 		$this->assertEquals($expected, $actual);
+ 	}
+ 	
+ 	/**
+ 	 * Test that an error is reported when config file is not found. 
+ 	 * @expectedException PHPUnit_Framework_Error
+ 	 * @expectedExceptionMessage log4php: Configuration failed. File not found
+ 	 */
+ 	public function testNonexistantFile() {
+ 		Logger::configure('hopefully/this/path/doesnt/exist/config.xml');
+ 		
+ 	}
+ 	
+ 	/** Test correct fallback to the default configuration. */
+ 	public function testNonexistantFileFallback() {
+ 		@Logger::configure('hopefully/this/path/doesnt/exist/config.xml');
+ 		$this->testDefaultConfig();
+ 	}
+ 	
+ 	public function testAppendersWithLayout() {
+ 		Logger::configure(array(
+ 			'rootLogger' => array(
+ 				'appenders' => array('app1', 'app2')
+ 			),
+ 			'appenders' => array(
+ 				'app1' => array(
+ 					'class' => 'LoggerAppenderEcho',
+ 					'layout' => array(
+ 						'class' => 'LoggerLayoutSimple'
+ 					)
+ 				),
+		 		'app2' => array(
+		 		 	'class' => 'LoggerAppenderEcho',
+		 		 	'layout' => array(
+		 		 		'class' => 'LoggerLayoutPattern',
+		 		 		'params' => array(
+		 		 			'conversionPattern' => 'message: %m%n'
+		 		 		)
+		 			)
+		 		),
+ 			) 
+ 		));
+ 		
+ 		ob_start();
+ 		Logger::getRootLogger()->info('info');
+ 		$actual = ob_get_contents();
+ 		ob_end_clean();
+ 		
+ 		$expected = "INFO - info" . PHP_EOL . "message: info" . PHP_EOL;
+  		$this->assertSame($expected, $actual);
+ 	}
+ }
\ No newline at end of file

Modified: logging/log4php/trunk/src/test/php/LoggerTest.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/LoggerTest.php?rev=1184770&r1=1184769&r2=1184770&view=diff
==============================================================================
--- logging/log4php/trunk/src/test/php/LoggerTest.php (original)
+++ logging/log4php/trunk/src/test/php/LoggerTest.php Sun Oct 16 07:12:49 2011
@@ -40,7 +40,6 @@ class LoggerTest extends PHPUnit_Framewo
 	public function testLoggerExist() {
 		$l = Logger::getLogger('test');
 		self::assertEquals($l->getName(), 'test');
-		$l->debug('test');
 		self::assertTrue(Logger::exists('test'));
 	}
 	
@@ -55,7 +54,7 @@ class LoggerTest extends PHPUnit_Framewo
 	}
 	
 	public function testCanLogToAllLevels() {
-		Logger::configure('LoggerTest.properties');
+		Logger::configure(dirname(__FILE__) . '/LoggerTest.properties');
 		
 		$logger = Logger::getLogger('mylogger');
 		ob_start();
@@ -78,7 +77,7 @@ class LoggerTest extends PHPUnit_Framewo
 	}
 	
 	public function testIsEnabledFor() {
-		Logger::configure('LoggerTest.properties');
+		Logger::configure(dirname(__FILE__) . '/LoggerTest.properties');
 		
 		$logger = Logger::getLogger('mylogger');
 		
@@ -97,34 +96,10 @@ class LoggerTest extends PHPUnit_Framewo
 		
 		self::assertEquals(0, count(Logger::getCurrentLoggers()));
 		
-		Logger::configure('LoggerTest.properties');
-		Logger::initialize();
+		Logger::configure(dirname(__FILE__) . '/LoggerTest.properties');
 		self::assertEquals(1, count(Logger::getCurrentLoggers()));
 		$list = Logger::getCurrentLoggers();
 		self::assertEquals('mylogger', $list[0]->getName());
 	}
-	
-	public function testConfigure() {
-		Logger::resetConfiguration();
-		Logger::configure();
-		self::assertEquals('LoggerConfiguratorBasic', Logger::getConfigurationClass());
-		self::assertEquals(null, Logger::getConfigurationFile());
-		
-		Logger::configure(null, 'MyLoggerClass');
-		self::assertEquals('MyLoggerClass', Logger::getConfigurationClass());
-		self::assertEquals(null, Logger::getConfigurationFile());
-		
-		Logger::configure('log4php.xml');
-		self::assertEquals('LoggerConfiguratorXml', Logger::getConfigurationClass());
-		self::assertEquals('log4php.xml', Logger::getConfigurationFile());
-		
-		Logger::configure('log4php.xml');
-		self::assertEquals('LoggerConfiguratorXml', Logger::getConfigurationClass());
-		self::assertEquals('log4php.xml', Logger::getConfigurationFile());
-		
-		Logger::configure('log4php.properties');
-		self::assertEquals('LoggerConfiguratorIni', Logger::getConfigurationClass());
-		self::assertEquals('log4php.properties', Logger::getConfigurationFile());
-		
-	}
+
 }

Added: logging/log4php/trunk/src/test/php/LoggerTestHelper.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/LoggerTestHelper.php?rev=1184770&view=auto
==============================================================================
--- logging/log4php/trunk/src/test/php/LoggerTestHelper.php (added)
+++ logging/log4php/trunk/src/test/php/LoggerTestHelper.php Sun Oct 16 07:12:49 2011
@@ -0,0 +1,92 @@
+<?php
+
+/** A set of helper functions for running tests. */
+class LoggerTestHelper {
+	
+	/** Returns a test logging event with level set to TRACE. */
+	public static function getTraceEvent($message = 'test') {
+		return new LoggerLoggingEvent(__CLASS__, new Logger("test"), LoggerLevel::getLevelTrace(), $message);
+	}
+	
+	/** Returns a test logging event with level set to DEBUG. */
+	public static function getDebugEvent($message = 'test') {
+		return new LoggerLoggingEvent(__CLASS__, new Logger("test"), LoggerLevel::getLevelDebug(), $message);
+	}
+	
+	/** Returns a test logging event with level set to INFO. */
+	public static function getInfoEvent($message = 'test') {
+		return new LoggerLoggingEvent(__CLASS__, new Logger("test"), LoggerLevel::getLevelInfo(), $message);
+	}
+	
+	/** Returns a test logging event with level set to WARN. */
+	public static function getWarnEvent($message = 'test') {
+		return new LoggerLoggingEvent(__CLASS__, new Logger("test"), LoggerLevel::getLevelWarn(), $message);
+	}
+	
+	/** Returns a test logging event with level set to ERROR. */
+	public static function getErrorEvent($message = 'test') {
+		return new LoggerLoggingEvent(__CLASS__, new Logger("test"), LoggerLevel::getLevelError(), $message);
+	}
+	
+	/** Returns a test logging event with level set to FATAL. */
+	public static function getFatalEvent($message = 'test') {
+		return new LoggerLoggingEvent(__CLASS__, new Logger("test"), LoggerLevel::getLevelFatal(), $message);
+	}
+	
+	/** 
+	 * Returns an array of logging events, one for each level, sorted ascending
+	 * by severitiy. 
+	 */
+	public static function getAllEvents($message = 'test') {
+		return array(
+			self::getTraceEvent($message),
+			self::getDebugEvent($message),
+			self::getInfoEvent($message),
+			self::getWarnEvent($message),
+			self::getErrorEvent($message),
+			self::getFatalEvent($message),
+		);
+	}
+	
+	/** Returns an array of all existing levels, sorted ascending by severity. */
+	public static function getAllLevels() {
+		return array(
+			LoggerLevel::getLevelTrace(),
+			LoggerLevel::getLevelDebug(),
+			LoggerLevel::getLevelInfo(),
+			LoggerLevel::getLevelWarn(),
+			LoggerLevel::getLevelError(),
+			LoggerLevel::getLevelFatal(),
+		);
+	}
+	
+	/** Returns a string representation of a filter decision. */
+	public static function decisionToString($decision) {
+		switch($decision) {
+			case LoggerFilter::ACCEPT: return 'ACCEPT';
+			case LoggerFilter::NEUTRAL: return 'NEUTRAL';
+			case LoggerFilter::DENY: return 'DENY';
+		}
+	}
+	
+	/** Returns a simple configuration with one echo appender tied to root logger. */
+	public static function getEchoConfig() {
+		return array(
+	        'threshold' => 'ALL',
+	        'rootLogger' => array(
+	            'level' => 'trace',
+	            'appenders' => array('default'),
+			),
+	        'appenders' => array(
+	            'default' => array(
+	                'class' => 'LoggerAppenderEcho',
+	                'layout' => array(
+	                    'class' => 'LoggerLayoutSimple',
+					),
+				),
+			),
+		);
+	}
+}
+
+?>
\ No newline at end of file

Modified: logging/log4php/trunk/src/test/php/LoggerThrowableInformationTest.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/LoggerThrowableInformationTest.php?rev=1184770&r1=1184769&r2=1184770&view=diff
==============================================================================
--- logging/log4php/trunk/src/test/php/LoggerThrowableInformationTest.php (original)
+++ logging/log4php/trunk/src/test/php/LoggerThrowableInformationTest.php Sun Oct 16 07:12:49 2011
@@ -26,17 +26,7 @@
  * @group main
  */
 class LoggerThrowableInformationTest extends PHPUnit_Framework_TestCase {
-	
-	protected static $logger;
-	
-	public static function setUpBeforeClass() {
-		self::$logger = Logger::getLogger('test');
-	}
-	
-	public static function tearDownAfterClass() {
-		self::$logger = null;
-	}
-	
+
 	public function testConstructor() {
 		$ex = new Exception();
 		$tInfo = new LoggerThrowableInformation($ex);

Modified: logging/log4php/trunk/src/test/php/appenders/LoggerAppenderConsoleTest.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/appenders/LoggerAppenderConsoleTest.php?rev=1184770&r1=1184769&r2=1184770&view=diff
==============================================================================
--- logging/log4php/trunk/src/test/php/appenders/LoggerAppenderConsoleTest.php (original)
+++ logging/log4php/trunk/src/test/php/appenders/LoggerAppenderConsoleTest.php Sun Oct 16 07:12:49 2011
@@ -25,55 +25,66 @@
 
 /** 
  * @group appenders
- *        
- * FIXME: Currently clutters the phpunit output as output buffering seems not
- *        to work for fwrite(STDOUT, ...)
  */
 class LoggerAppenderConsoleTest extends PHPUnit_Framework_TestCase {
-    
-	private $event;
 	
-	public function setUp()
-	{
-		$logger = new Logger('mycategory');
-		$level = LoggerLevel::getLevelWarn();
-		$this->event = new LoggerLoggingEvent(__CLASS__, $logger, $level, "my message");
-	}
+	private $config = array(
+		'rootLogger' => array(
+			'appenders' => array('default'),
+		),
+		'appenders' => array(
+			'default' => array(
+				'class' => 'LoggerAppenderConsole',
+				'layout' => array(
+					'class' => 'LoggerLayoutPattern',
+					'params' => array(
+						// Intentionally blank so output doesn't clutter phpunit output
+						'conversionPattern' => '' 
+					)
+				),
+			)
+		)
+	);
 	
 	public function testRequiresLayout() {
 		$appender = new LoggerAppenderConsole(); 
 		self::assertTrue($appender->requiresLayout());
 	}
 	
-    public function testSimpleStdOutLogging() {
-    	$layout = new LoggerLayoutSimple();
+    public function testAppendDefault() {
+    	Logger::configure($this->config);
+    	$log = Logger::getRootLogger();
+    	
+    	$expected = LoggerAppenderConsole::STDOUT;
+    	$actual = $log->getAppender('default')->getTarget();
+    	$this->assertSame($expected, $actual);
     	
-    	$appender = new LoggerAppenderConsole("mylogger"); 
-    	$appender->setTarget('STDOUT');
-		$appender->setLayout($layout);
-		$appender->activateOptions();
-		$appender->append($this->event);
-		$appender->close();
+    	$log->info("hello");
     }
 
-    public function testSimpleStdErrLogging() {
-    	$layout = new LoggerLayoutSimple();
+    public function testAppendStdout() {
+    	$this->config['appenders']['default']['params']['target'] = 'stdout';
     	
-    	$appender = new LoggerAppenderConsole("mylogger"); 
-		$appender->setTarget('STDERR');
-		$appender->setLayout($layout);
-		$appender->activateOptions();
-		$appender->append($this->event);
-		$appender->close();
-    }    
-
-    public function testSimpleDefaultLogging() {
-    	$layout = new LoggerLayoutSimple();
+    	Logger::configure($this->config);
+    	$log = Logger::getRootLogger();
+    	 
+    	$expected = LoggerAppenderConsole::STDOUT;
+    	$actual = $log->getAppender('default')->getTarget();
+    	$this->assertSame($expected, $actual);
+    	 
+    	$log->info("hello");
+    }
+    
+    public function testAppendStderr() {
+    	$this->config['appenders']['default']['params']['target'] = 'stderr';
     	
-    	$appender = new LoggerAppenderConsole("mylogger"); 
-		$appender->setLayout($layout);
-		$appender->activateOptions();
-		$appender->append($this->event);
-		$appender->close();
+    	Logger::configure($this->config);
+    	$log = Logger::getRootLogger();
+    	$expected = LoggerAppenderConsole::STDERR;
+    	 
+    	$actual = $log->getAppender('default')->getTarget();
+    	$this->assertSame($expected, $actual);
+    	 
+    	$log->info("hello");
     }
 }

Modified: logging/log4php/trunk/src/test/php/appenders/LoggerAppenderEchoTest.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/appenders/LoggerAppenderEchoTest.php?rev=1184770&r1=1184769&r2=1184770&view=diff
==============================================================================
--- logging/log4php/trunk/src/test/php/appenders/LoggerAppenderEchoTest.php (original)
+++ logging/log4php/trunk/src/test/php/appenders/LoggerAppenderEchoTest.php Sun Oct 16 07:12:49 2011
@@ -28,6 +28,91 @@
  */
 class LoggerAppenderEchoTest extends PHPUnit_Framework_TestCase {
 
+	private $config1 = array(
+		'rootLogger' => array(
+			'appenders' => array('default'),
+		),
+		'appenders' => array(
+			'default' => array(
+				'class' => 'LoggerAppenderEcho',
+				'layout' => array(
+					'class' => 'LoggerLayoutSimple'
+				),
+			)
+		)
+	);
+	
+	private $config2 = array(
+		'rootLogger' => array(
+			'appenders' => array('default'),
+		),
+		'appenders' => array(
+			'default' => array(
+				'class' => 'LoggerAppenderEcho',
+				'layout' => array(
+					'class' => 'LoggerLayoutSimple'
+				),
+				'params' => array(
+					'htmlLineBreaks' => true
+				)
+			)
+		)
+	);
+	
+	private $config3 = array(
+		'rootLogger' => array(
+			'appenders' => array('default'),
+		),
+		'appenders' => array(
+			'default' => array(
+				'class' => 'LoggerAppenderEcho',
+				'layout' => array(
+					'class' => 'LoggerLayoutSimple'
+				),
+				'params' => array(
+					'htmlLineBreaks' => 'foo'
+				)
+			)
+		)
+	);
+	
+	public function testAppend() {
+		Logger::configure($this->config1);
+		$log = Logger::getRootLogger();
+
+		$hlb = $log->getAppender('default')->getHtmlLineBreaks();
+		$this->assertSame(false, $hlb);
+		
+		ob_start();
+		$log->info("This is a test");
+		$log->debug("And this too");
+		$actual = ob_get_clean();
+		$expected = "INFO - This is a test" . PHP_EOL . "DEBUG - And this too". PHP_EOL;
+		
+		$this->assertSame($expected, $actual);
+	}
+	
+	public function testHtmlLineBreaks() {
+		Logger::configure($this->config2);
+		$log = Logger::getRootLogger();
+		
+		$hlb = $log->getAppender('default')->getHtmlLineBreaks();
+		$this->assertSame(true, $hlb);
+		
+		ob_start();
+		$log->info("This is a test" . PHP_EOL . "With more than one line");
+		$log->debug("And this too");
+		$actual = ob_get_clean();
+		$expected = "INFO - This is a test<br />" . PHP_EOL . "With more than one line<br />" . PHP_EOL . "DEBUG - And this too<br />" . PHP_EOL;
+		
+		$this->assertSame($expected, $actual);
+	}
+	
+// 	public function testHtmlLineBreaksInvalidOption() {
+// 		Logger::configure($this->config3);
+// 	}
+	
+	
 	public function testEcho() {
 		$appender = new LoggerAppenderEcho("myname ");
 		

Modified: logging/log4php/trunk/src/test/php/appenders/LoggerAppenderFileTest.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/appenders/LoggerAppenderFileTest.php?rev=1184770&r1=1184769&r2=1184770&view=diff
==============================================================================
--- logging/log4php/trunk/src/test/php/appenders/LoggerAppenderFileTest.php (original)
+++ logging/log4php/trunk/src/test/php/appenders/LoggerAppenderFileTest.php Sun Oct 16 07:12:49 2011
@@ -7,7 +7,7 @@
  * (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
+ *	  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,
@@ -16,58 +16,105 @@
  * limitations under the License.
  * 
  * @category   tests   
- * @package    log4php
+ * @package	log4php
  * @subpackage appenders
- * @license    http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
- * @version    SVN: $Id$
- * @link       http://logging.apache.org/log4php
+ * @license	http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
+ * @version	SVN: $Id$
+ * @link	   http://logging.apache.org/log4php
  */
 
 /**
  * @group appenders
  */
 class LoggerAppenderFileTest extends PHPUnit_Framework_TestCase {
-    
+	
+	private $config1 = array(
+		'rootLogger' => array(
+			'appenders' => array('default'),
+		),
+		'appenders' => array(
+			'default' => array(
+				'class' => 'LoggerAppenderFile',
+				'layout' => array(
+					'class' => 'LoggerLayoutSimple'
+				),
+				'params' => array()
+			)
+		)
+	);
+	
 	private $testPath;
 	
 	public function __construct() {
-		$this->testPath = dirname(__FILE__) . '/../../../../target/temp/phpunit/TEST.txt';
+		$this->testPath = PHPUNIT_TEMP_DIR . '/TEST.txt';
+	}
+	
+	public function setUp() {
+		Logger::resetConfiguration();
+		if(file_exists($this->testPath)) {
+			unlink($this->testPath);
+		}
+	}
+	
+	public function tearDown() {
+		Logger::resetConfiguration();
+		if(file_exists($this->testPath)) {
+			unlink($this->testPath);
+		}
 	}
 	
-    protected function setUp() {
-        if(file_exists($this->testPath)) {
-	        unlink($this->testPath);
-        }
-    }
-    
 	public function testRequiresLayout() {
 		$appender = new LoggerAppenderFile();
 		self::assertTrue($appender->requiresLayout());
 	}
 	
-    public function testSimpleLogging() {
-    	$layout = new LoggerLayoutSimple();
-    	
-    	$event = new LoggerLoggingEvent('LoggerAppenderFileTest', 
-    									new Logger('mycategory'), 
-    									LoggerLevel::getLevelWarn(),
-    									"my message");
-    	
-    	$appender = new LoggerAppenderFile("mylogger"); 
-		$appender->setFile($this->testPath);
-		$appender->setLayout($layout);
-		$appender->activateOptions();
-		$appender->append($event);
-		$appender->close();
-
-		$v = file_get_contents($this->testPath);
-		$e = "WARN - my message".PHP_EOL;
-		self::assertEquals($e, $v);
-    }
-     
-    protected function tearDown() {
-        if(file_exists($this->testPath)) {
-	        unlink($this->testPath);
-        }
-    }
+	public function testSimpleLogging() {
+		$config = $this->config1;
+		$config['appenders']['default']['params']['file'] = $this->testPath;
+		
+		Logger::configure($config);
+		
+		$logger = Logger::getRootLogger();
+		$logger->info('This is a test');
+		
+		$expected = "INFO - This is a test" . PHP_EOL;
+		$actual = file_get_contents($this->testPath);
+		$this->assertSame($expected, $actual);
+	}
+	
+	public function testAppendFlagTrue() {
+		$config = $this->config1;
+		$config['appenders']['default']['params']['file'] = $this->testPath;
+		$config['appenders']['default']['params']['append'] = true;
+		
+		Logger::configure($config);
+		$logger = Logger::getRootLogger();
+		$logger->info('This is a test');
+		
+		Logger::configure($config);
+		$logger = Logger::getRootLogger();
+		$logger->info('This is a test');
+		
+		$expected = "INFO - This is a test" . PHP_EOL . "INFO - This is a test" . PHP_EOL;
+		$actual = file_get_contents($this->testPath);
+		$this->assertSame($expected, $actual);
+	}
+	
+	public function testAppendFlagFalse() {
+		$config = $this->config1;
+		$config['appenders']['default']['params']['file'] = $this->testPath;
+		$config['appenders']['default']['params']['append'] = false;
+	
+		Logger::configure($config);
+		$logger = Logger::getRootLogger();
+		$logger->info('This is a test');
+	
+		Logger::configure($config);
+		$logger = Logger::getRootLogger();
+		$logger->info('This is a test');
+	
+		$expected = "INFO - This is a test" . PHP_EOL;
+		$actual = file_get_contents($this->testPath);
+		$this->assertSame($expected, $actual);
+	}
 }

Modified: logging/log4php/trunk/src/test/php/appenders/LoggerAppenderPhpTest.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/appenders/LoggerAppenderPhpTest.php?rev=1184770&r1=1184769&r2=1184770&view=diff
==============================================================================
--- logging/log4php/trunk/src/test/php/appenders/LoggerAppenderPhpTest.php (original)
+++ logging/log4php/trunk/src/test/php/appenders/LoggerAppenderPhpTest.php Sun Oct 16 07:12:49 2011
@@ -24,49 +24,71 @@
  */
  
 function errorHandler($errno, $errstr, $errfile, $errline) {
-	switch ($errno) {
-    	case E_USER_ERROR: 
-    			PHPUnit_Framework_TestCase::assertEquals($errstr, "ERROR - testmessage".PHP_EOL); 
-    			break;
-    	case E_USER_WARNING:
-    			PHPUnit_Framework_TestCase::assertEquals($errstr, "WARN - testmessage".PHP_EOL); 
-        		break;
-	    case E_USER_NOTICE:
-    			PHPUnit_Framework_TestCase::assertEquals($errstr, "DEBUG - testmessage".PHP_EOL); 
-        		break;
-	    default: 
-	    		PHPUnit_Framework_TestCase::assertTrue(false);
-	}
+	PHPUnit_Framework_TestCase::assertEquals(LoggerAppenderPhpTest::$expectedError, $errno);
+	PHPUnit_Framework_TestCase::assertEquals(LoggerAppenderPhpTest::$expectedMessage, $errstr);
 }
 
-
 /**
  * @group appenders
  */
 class LoggerAppenderPhpTest extends PHPUnit_Framework_TestCase {
+	
+	public static $expectedMessage;
+	
+	public static $expectedError;
+	
+	private $config = array(
+		'rootLogger' => array(
+			'appenders' => array('default'),
+			'level' => 'trace'
+		),
+		'appenders' => array(
+			'default' => array(
+				'class' => 'LoggerAppenderPHP',
+				'layout' => array(
+					'class' => 'LoggerLayoutSimple'
+				),
+			)
+		)
+	);
+	
     protected function setUp() {
 		set_error_handler("errorHandler");
 	}
-	
+		
 	public function testRequiresLayout() {
 		$appender = new LoggerAppenderPhp();
-		self::assertTrue($appender->requiresLayout());
+		$this->assertTrue($appender->requiresLayout());
 	}
     
 	public function testPhp() {
-		$appender = new LoggerAppenderPhp("TEST");
+		Logger::configure($this->config);
+		$logger = Logger::getRootLogger();
+		
+		 
+		self::$expectedError = E_USER_ERROR;
+		self::$expectedMessage = "FATAL - This is a test" . PHP_EOL;
+		$logger->fatal("This is a test");
+		
+		self::$expectedError = E_USER_ERROR;
+		self::$expectedMessage = "ERROR - This is a test" . PHP_EOL;
+		$logger->error("This is a test");
+		
+		self::$expectedError = E_USER_WARNING;
+		self::$expectedMessage = "WARN - This is a test" . PHP_EOL;
+		$logger->warn("This is a test");
 		
-		$layout = new LoggerLayoutSimple();
-		$appender->setLayout($layout);
-		$appender->activateOptions();
-		$event = new LoggerLoggingEvent("LoggerAppenderPhpTest", new Logger("TEST"), LoggerLevel::getLevelError(), "testmessage");
-		$appender->append($event);
+		self::$expectedError = E_USER_NOTICE;
+		self::$expectedMessage = "INFO - This is a test" . PHP_EOL;
+		$logger->info("This is a test");
 		
-		$event = new LoggerLoggingEvent("LoggerAppenderPhpTest", new Logger("TEST"), LoggerLevel::getLevelWarn(), "testmessage");
-		$appender->append($event);
+		self::$expectedError = E_USER_NOTICE;
+		self::$expectedMessage = "DEBUG - This is a test" . PHP_EOL;
+		$logger->debug("This is a test");
 		
-		$event = new LoggerLoggingEvent("LoggerAppenderPhpTest", new Logger("TEST"), LoggerLevel::getLevelDebug(), "testmessage");
-		$appender->append($event);
+		self::$expectedError = E_USER_NOTICE;
+		self::$expectedMessage = "TRACE - This is a test" . PHP_EOL;
+		$logger->trace("This is a test");
     }
     
     protected function tearDown() {

Modified: logging/log4php/trunk/src/test/php/bootstrap.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/bootstrap.php?rev=1184770&r1=1184769&r2=1184770&view=diff
==============================================================================
--- logging/log4php/trunk/src/test/php/bootstrap.php (original)
+++ logging/log4php/trunk/src/test/php/bootstrap.php Sun Oct 16 07:12:49 2011
@@ -26,4 +26,12 @@ error_reporting(E_ALL | E_STRICT); 
 
 date_default_timezone_set('Europe/London');
 
+// Define a temp dir where tests may write to
+$tmpDir = dirname(__FILE__) . '/../../../target/temp/phpunit';
+if (!is_dir($tmpDir)) {
+	mkdir($tmpDir, 0777, true);
+}
+define('PHPUNIT_TEMP_DIR', realpath($tmpDir));
+
 require dirname(__FILE__) . '/../../main/php/Logger.php';
+

Added: logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterINITest.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterINITest.php?rev=1184770&view=auto
==============================================================================
--- logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterINITest.php (added)
+++ logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterINITest.php Sun Oct 16 07:12:49 2011
@@ -0,0 +1,135 @@
+<?php
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 log4php
+ */
+
+/**
+ * @group configurators
+ */
+class LoggerConfigurationAdapterINITest extends PHPUnit_Framework_TestCase {
+	
+	/** Expected output of parsing config1.ini. */
+	private $expected1 = array(
+		'threshold' => 'debug',
+		'rootLogger' => array(
+			'level' => 'DEBUG',
+			'appenders' => array('default'),
+		),
+		'appenders' => array(
+			'default' => array(
+				'class' => 'LoggerAppenderEcho',
+				'layout' => array(
+					'class' => 'LoggerLayoutTTCC',
+				),
+			),
+			'file' => array(
+				'class' => 'LoggerAppenderDailyFile',
+				'layout' => array(
+					'class' => 'LoggerLayoutPattern',
+					'params' => array(
+						'conversionPattern' => '%d{ISO8601} [%p] %c: %m (at %F line %L)%n',
+					),
+				),
+				'params' => array(
+					'datePattern' => 'Ymd',
+					'file' => 'target/examples/daily_%s.log',
+				),
+				'threshold' => 'warn'
+			),
+		),
+		'loggers' => array(
+			'foo' => array(
+				'level' => 'warn',
+				'appenders' => array('default'),
+			),
+			'foo.bar' => array(
+				'level' => 'debug',
+				'appenders' => array('file'),
+				'additivity' => 'true',
+			),
+			'foo.bar.baz' => array(
+				'level' => 'trace',
+				'appenders' => array('default', 'file'),
+				'additivity' => 'false',
+			),
+		),
+		'renderers' => array(
+			array(
+				'renderedClass' => 'Fruit',
+				'renderingClass' => 'FruitRenderer',
+			),
+			array(
+				'renderedClass' => 'Beer',
+				'renderingClass' => 'BeerRenderer',
+			),
+		),
+	);	
+	
+	public function testConfig() {
+		$url = dirname(__FILE__) . '/config1.ini';
+		$adapter = new LoggerConfigurationAdapterINI();
+		$actual = $adapter->convert($url);
+	
+		$this->assertSame($this->expected1, $actual);
+	}
+	
+	/**
+	 * Test exception is thrown when file cannot be found.
+ 	 * @expectedException LoggerException
+ 	 * @expectedExceptionMessage File [you/will/never/find/me.ini] does not exist.
+	 */
+	public function testNonExistantFileException() {
+		$adapter = new LoggerConfigurationAdapterINI();
+		$adapter->convert('you/will/never/find/me.ini');
+	}
+	
+	/**
+	 * Test exception is thrown when file is not a valid ini file.
+	 * @expectedException LoggerException
+	 * @expectedExceptionMessage Error parsing configuration file: syntax error
+	 */
+	public function testInvalidFileException() {
+		$url =  dirname(__FILE__) . '/config2.ini';
+		$adapter = new LoggerConfigurationAdapterINI();
+		$adapter->convert($url);
+	}
+
+	/**
+	 * Test a warning is triggered when configurator doesn't understand a line.
+	 * @expectedException PHPUnit_Framework_Error
+	 * @expectedExceptionMessage log4php: Don't know how to parse the following line: "log4php.appender.default.layout.param.bla = LoggerLayoutTTCC". Skipping.
+	 */
+	public function testInvalidLineWarning1() {
+		$url =  dirname(__FILE__) . '/config3.ini';
+		$adapter = new LoggerConfigurationAdapterINI();
+		$adapter->convert($url);
+	}
+	
+	/**
+	 * Test a warning is triggered when configurator doesn't understand a line.
+	 * @expectedException PHPUnit_Framework_Error
+	 * @expectedExceptionMessage log4php: Don't know how to parse the following line: "log4php.appender.default.not-layout.param = LoggerLayoutTTCC". Skipping.
+	 */
+	public function testInvalidLineWarning2() {
+		$url =  dirname(__FILE__) . '/config4.ini';
+		$adapter = new LoggerConfigurationAdapterINI();
+		$adapter->convert($url);
+	}
+}
+
+?>
\ No newline at end of file

Added: logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterPHPTest.php
URL: http://svn.apache.org/viewvc/logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterPHPTest.php?rev=1184770&view=auto
==============================================================================
--- logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterPHPTest.php (added)
+++ logging/log4php/trunk/src/test/php/configurators/LoggerConfigurationAdapterPHPTest.php Sun Oct 16 07:12:49 2011
@@ -0,0 +1,96 @@
+<?php
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 log4php
+ */
+
+/**
+ * @group configurators
+ */
+class LoggerConfigurationAdapterPHPTest extends PHPUnit_Framework_TestCase {
+	
+	private $expected1 = array(
+		'rootLogger' => array(
+			'level' => 'info',
+			'appenders' => array('default')
+		),
+		'appenders' => array(
+			'default' => array(
+				'class' => 'LoggerAppenderEcho',
+				'layout' => array(
+					'class' => 'LoggerLayoutSimple'
+				 )
+			)
+		)
+	);
+	
+	public function testConfig() {
+		$url = dirname(__FILE__) . '/config1.php';
+		$adapter = new LoggerConfigurationAdapterPHP();
+		$actual = $adapter->convert($url);
+		
+		$this->assertSame($this->expected1, $actual);
+	}
+	
+	/**
+	 * Test exception is thrown when file cannot be found.
+ 	 * @expectedException LoggerException
+ 	 * @expectedExceptionMessage File [you/will/never/find/me.conf] does not exist.
+	 */
+	public function testNonExistantFileWarning() {
+		$adapter = new LoggerConfigurationAdapterPHP();
+		$adapter->convert('you/will/never/find/me.conf');
+	}
+	
+	/**
+	 * Test exception is thrown when file is not valid.
+	 * @expectedException LoggerException
+	 * @expectedExceptionMessage Error parsing configuration: syntax error
+	 */
+	public function testInvalidFileWarning() {
+		$url = dirname(__FILE__) . '/config2.php';
+		$adapter = new LoggerConfigurationAdapterPHP();
+		$adapter->convert($url);
+	}
+	
+	/**
+	 * Test exception is thrown when the configuration is empty.
+	 * @expectedException LoggerException
+	 * @expectedExceptionMessage Invalid configuration: empty configuration array.
+	 */
+	public function testEmptyConfigWarning() {
+		$url = dirname(__FILE__) . '/config3.php';
+		$adapter = new LoggerConfigurationAdapterPHP();
+		$adapter->convert($url);
+	}
+	
+	/**
+	 * Test exception is thrown when the configuration does not contain an array.
+	 * @expectedException LoggerException
+	 * @expectedExceptionMessage Invalid configuration: not an array.
+	 */
+	public function testInvalidConfigWarning() {
+		$url = dirname(__FILE__) . '/config4.php';
+		$adapter = new LoggerConfigurationAdapterPHP();
+		$adapter->convert($url);
+	}
+
+
+}
+
+?>
\ No newline at end of file



Mime
View raw message