library/log4php/configurators/LoggerConfigurationAdapterXML.php
changeset 46 f11c31f7fa3e
parent 45 a56e7f9a0463
child 47 03388ec805b4
equal deleted inserted replaced
45:a56e7f9a0463 46:f11c31f7fa3e
     1 <?php
       
     2 /**
       
     3  * Licensed to the Apache Software Foundation (ASF) under one or more
       
     4  * contributor license agreements. See the NOTICE file distributed with
       
     5  * this work for additional information regarding copyright ownership.
       
     6  * The ASF licenses this file to You under the Apache License, Version 2.0
       
     7  * (the "License"); you may not use this file except in compliance with
       
     8  * the License. You may obtain a copy of the License at
       
     9  *
       
    10  *     http://www.apache.org/licenses/LICENSE-2.0
       
    11  *
       
    12  * Unless required by applicable law or agreed to in writing, software
       
    13  * distributed under the License is distributed on an "AS IS" BASIS,
       
    14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    15  * See the License for the specific language governing permissions and
       
    16  * limitations under the License.
       
    17  *
       
    18  * @package log4php
       
    19  */
       
    20 
       
    21 /**
       
    22  * Converts XML configuration files to a PHP array.
       
    23  *
       
    24  * @package log4php
       
    25  * @subpackage configurators
       
    26  * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
       
    27  * @version $Revision: 1394956 $
       
    28  * @since 2.2
       
    29  */
       
    30 class LoggerConfigurationAdapterXML implements LoggerConfigurationAdapter {
       
    31     /** Path to the XML schema used for validation. */
       
    32     const SCHEMA_PATH = '/../xml/log4php.xsd';
       
    33 
       
    34     private $config = array(
       
    35         'appenders' => array(),
       
    36         'loggers' => array(),
       
    37         'renderers' => array(),
       
    38     );
       
    39 
       
    40     public function convert($url) {
       
    41         $xml = $this->loadXML($url);
       
    42 
       
    43         $this->parseConfiguration($xml);
       
    44 
       
    45         // Parse the <root> node
       
    46         if (isset($xml->root)) {
       
    47             $this->parseRootLogger($xml->root);
       
    48         }
       
    49 
       
    50         // Process <logger> nodes
       
    51         foreach ($xml->logger as $logger) {
       
    52             $this->parseLogger($logger);
       
    53         }
       
    54 
       
    55         // Process <appender> nodes
       
    56         foreach ($xml->appender as $appender) {
       
    57             $this->parseAppender($appender);
       
    58         }
       
    59 
       
    60         // Process <renderer> nodes
       
    61         foreach ($xml->renderer as $rendererNode) {
       
    62             $this->parseRenderer($rendererNode);
       
    63         }
       
    64 
       
    65         // Process <defaultRenderer> node
       
    66         foreach ($xml->defaultRenderer as $rendererNode) {
       
    67             $this->parseDefaultRenderer($rendererNode);
       
    68         }
       
    69 
       
    70         return $this->config;
       
    71     }
       
    72 
       
    73     /**
       
    74      * Loads and validates the XML.
       
    75      * @param string $url Input XML.
       
    76      */
       
    77     private function loadXML($url) {
       
    78         if (!file_exists($url)) {
       
    79             throw new LoggerException("File [$url] does not exist.");
       
    80         }
       
    81 
       
    82         libxml_clear_errors();
       
    83         $oldValue = libxml_use_internal_errors(true);
       
    84 
       
    85         // Load XML
       
    86         $xml = @simplexml_load_file($url);
       
    87         if ($xml === false) {
       
    88 
       
    89             $errorStr = "";
       
    90             foreach (libxml_get_errors() as $error) {
       
    91                 $errorStr .= $error->message;
       
    92             }
       
    93 
       
    94             throw new LoggerException("Error loading configuration file: " . trim($errorStr));
       
    95         }
       
    96 
       
    97         libxml_clear_errors();
       
    98         libxml_use_internal_errors($oldValue);
       
    99 
       
   100         return $xml;
       
   101     }
       
   102 
       
   103     /**
       
   104      * Parses the <configuration> node.
       
   105      */
       
   106     private function parseConfiguration(SimpleXMLElement $xml) {
       
   107         $attributes = $xml->attributes();
       
   108         if (isset($attributes['threshold'])) {
       
   109             $this->config['threshold'] = (string)$attributes['threshold'];
       
   110         }
       
   111     }
       
   112 
       
   113     /** Parses an <appender> node. */
       
   114     private function parseAppender(SimpleXMLElement $node) {
       
   115         $name = $this->getAttributeValue($node, 'name');
       
   116         if (empty($name)) {
       
   117             $this->warn("An <appender> node is missing the required 'name' attribute. Skipping appender definition.");
       
   118             return;
       
   119         }
       
   120 
       
   121         $appender = array();
       
   122         $appender['class'] = $this->getAttributeValue($node, 'class');
       
   123 
       
   124         if (isset($node['threshold'])) {
       
   125             $appender['threshold'] = $this->getAttributeValue($node, 'threshold');
       
   126         }
       
   127 
       
   128         if (isset($node->layout)) {
       
   129             $appender['layout'] = $this->parseLayout($node->layout, $name);
       
   130         }
       
   131 
       
   132         if (count($node->param) > 0) {
       
   133             $appender['params'] = $this->parseParameters($node);
       
   134         }
       
   135 
       
   136         foreach ($node->filter as $filterNode) {
       
   137             $appender['filters'][] = $this->parseFilter($filterNode);
       
   138         }
       
   139 
       
   140         $this->config['appenders'][$name] = $appender;
       
   141     }
       
   142 
       
   143     /** Parses a <layout> node. */
       
   144     private function parseLayout(SimpleXMLElement $node, $appenderName) {
       
   145         $layout = array();
       
   146         $layout['class'] = $this->getAttributeValue($node, 'class');
       
   147 
       
   148         if (count($node->param) > 0) {
       
   149             $layout['params'] = $this->parseParameters($node);
       
   150         }
       
   151 
       
   152         return $layout;
       
   153     }
       
   154 
       
   155     /** Parses any <param> child nodes returning them in an array. */
       
   156     private function parseParameters($paramsNode) {
       
   157         $params = array();
       
   158 
       
   159         foreach ($paramsNode->param as $paramNode) {
       
   160             if (empty($paramNode['name'])) {
       
   161                 $this->warn("A <param> node is missing the required 'name' attribute. Skipping parameter.");
       
   162                 continue;
       
   163             }
       
   164 
       
   165             $name = $this->getAttributeValue($paramNode, 'name');
       
   166             $value = $this->getAttributeValue($paramNode, 'value');
       
   167 
       
   168             $params[$name] = $value;
       
   169         }
       
   170 
       
   171         return $params;
       
   172     }
       
   173 
       
   174     /** Parses a <root> node. */
       
   175     private function parseRootLogger(SimpleXMLElement $node) {
       
   176         $logger = array();
       
   177 
       
   178         if (isset($node->level)) {
       
   179             $logger['level'] = $this->getAttributeValue($node->level, 'value');
       
   180         }
       
   181 
       
   182         $logger['appenders'] = $this->parseAppenderReferences($node);
       
   183 
       
   184         $this->config['rootLogger'] = $logger;
       
   185     }
       
   186 
       
   187     /** Parses a <logger> node. */
       
   188     private function parseLogger(SimpleXMLElement $node) {
       
   189         $logger = array();
       
   190 
       
   191         $name = $this->getAttributeValue($node, 'name');
       
   192         if (empty($name)) {
       
   193             $this->warn("A <logger> node is missing the required 'name' attribute. Skipping logger definition.");
       
   194             return;
       
   195         }
       
   196 
       
   197         if (isset($node->level)) {
       
   198             $logger['level'] = $this->getAttributeValue($node->level, 'value');
       
   199         }
       
   200 
       
   201         if (isset($node['additivity'])) {
       
   202             $logger['additivity'] = $this->getAttributeValue($node, 'additivity');
       
   203         }
       
   204 
       
   205         $logger['appenders'] = $this->parseAppenderReferences($node);
       
   206 
       
   207         // Check for duplicate loggers
       
   208         if (isset($this->config['loggers'][$name])) {
       
   209             $this->warn("Duplicate logger definition [$name]. Overwriting.");
       
   210         }
       
   211 
       
   212         $this->config['loggers'][$name] = $logger;
       
   213     }
       
   214 
       
   215     /**
       
   216      * Parses a <logger> node for appender references and returns them in an array.
       
   217      *
       
   218      * Previous versions supported appender-ref, as well as appender_ref so both
       
   219      * are parsed for backward compatibility.
       
   220      */
       
   221     private function parseAppenderReferences(SimpleXMLElement $node) {
       
   222         $refs = array();
       
   223         foreach ($node->appender_ref as $ref) {
       
   224             $refs[] = $this->getAttributeValue($ref, 'ref');
       
   225         }
       
   226 
       
   227         foreach ($node->{'appender-ref'} as $ref) {
       
   228             $refs[] = $this->getAttributeValue($ref, 'ref');
       
   229         }
       
   230 
       
   231         return $refs;
       
   232     }
       
   233 
       
   234     /** Parses a <filter> node. */
       
   235     private function parseFilter($filterNode) {
       
   236         $filter = array();
       
   237         $filter['class'] = $this->getAttributeValue($filterNode, 'class');
       
   238 
       
   239         if (count($filterNode->param) > 0) {
       
   240             $filter['params'] = $this->parseParameters($filterNode);
       
   241         }
       
   242 
       
   243         return $filter;
       
   244     }
       
   245 
       
   246     /** Parses a <renderer> node. */
       
   247     private function parseRenderer(SimpleXMLElement $node) {
       
   248         $renderedClass = $this->getAttributeValue($node, 'renderedClass');
       
   249         $renderingClass = $this->getAttributeValue($node, 'renderingClass');
       
   250 
       
   251         $this->config['renderers'][] = compact('renderedClass', 'renderingClass');
       
   252     }
       
   253 
       
   254     /** Parses a <defaultRenderer> node. */
       
   255     private function parseDefaultRenderer(SimpleXMLElement $node) {
       
   256         $renderingClass = $this->getAttributeValue($node, 'renderingClass');
       
   257 
       
   258         // Warn on duplicates
       
   259         if (isset($this->config['defaultRenderer'])) {
       
   260             $this->warn("Duplicate <defaultRenderer> node. Overwriting.");
       
   261         }
       
   262 
       
   263         $this->config['defaultRenderer'] = $renderingClass;
       
   264     }
       
   265 
       
   266     // ******************************************
       
   267     // ** Helper methods                       **
       
   268     // ******************************************
       
   269 
       
   270     private function getAttributeValue(SimpleXMLElement $node, $name) {
       
   271         return isset($node[$name]) ? (string)$node[$name] : null;
       
   272     }
       
   273 
       
   274     private function warn($message) {
       
   275         trigger_error("log4php: " . $message, E_USER_WARNING);
       
   276     }
       
   277 }
       
   278