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$
28 : * @since 2.2
29 : */
30 : class LoggerConfigurationAdapterXML implements LoggerConfigurationAdapter
31 : {
32 : /** Path to the XML schema used for validation. */
33 : const SCHEMA_PATH = '/../xml/log4php.xsd';
34 :
35 : private $config = array(
36 : 'appenders' => array(),
37 : 'loggers' => array(),
38 : 'renderers' => array(),
39 : );
40 :
41 : public function convert($url)
42 : {
43 21 : $xml = $this->loadXML($url);
44 :
45 19 : $this->parseConfiguration($xml);
46 :
47 : // Parse the <root> node
48 19 : if (isset($xml->root)) {
49 18 : $this->parseRootLogger($xml->root);
50 18 : }
51 :
52 : // Process <logger> nodes
53 19 : foreach($xml->logger as $logger) {
54 5 : $this->parseLogger($logger);
55 19 : }
56 :
57 : // Process <appender> nodes
58 18 : foreach($xml->appender as $appender) {
59 17 : $this->parseAppender($appender);
60 18 : }
61 :
62 : // Process <renderer> nodes
63 18 : foreach($xml->renderer as $rendererNode) {
64 6 : $this->parseRenderer($rendererNode);
65 18 : }
66 18 : return $this->config;
67 : }
68 :
69 : /**
70 : * Loads and validates the XML.
71 : * @param string $url Input XML.
72 : */
73 : private function loadXML($url) {
74 21 : if (!file_exists($url)) {
75 1 : throw new LoggerException("File [$url] does not exist.");
76 : }
77 :
78 20 : libxml_clear_errors();
79 20 : $oldValue = libxml_use_internal_errors(true);
80 :
81 : // Load XML
82 20 : $xml = @simplexml_load_file($url);
83 20 : if ($xml === false) {
84 :
85 1 : $errorStr = "";
86 1 : foreach(libxml_get_errors() as $error) {
87 1 : $errorStr .= $error->message;
88 1 : }
89 :
90 1 : throw new LoggerException("Error loading configuration file: " . trim($errorStr));
91 : }
92 :
93 19 : libxml_clear_errors();
94 19 : libxml_use_internal_errors($oldValue);
95 :
96 19 : return $xml;
97 : }
98 :
99 : /**
100 : * Parses the <configuration> node.
101 : */
102 : private function parseConfiguration(SimpleXMLElement $xml) {
103 19 : $attributes = $xml->attributes();
104 19 : if (isset($attributes['threshold'])) {
105 8 : $this->config['threshold'] = (string) $attributes['threshold'];
106 8 : }
107 19 : }
108 :
109 : /** Parses an <appender> node. */
110 : private function parseAppender(SimpleXMLElement $node) {
111 17 : $name = $this->getAttributeValue($node, 'name');
112 17 : if (empty($name)) {
113 0 : $this->warn("An <appender> node is missing the required 'name' attribute. Skipping appender definition.");
114 0 : return;
115 : }
116 :
117 17 : $appender = array();
118 17 : $appender['class'] = $this->getAttributeValue($node, 'class');
119 :
120 17 : if (isset($node['threshold'])) {
121 1 : $appender['threshold'] = $this->getAttributeValue($node, 'threshold');
122 1 : }
123 :
124 17 : if (isset($node->layout)) {
125 11 : $appender['layout']= $this->parseLayout($node->layout, $name);
126 11 : }
127 :
128 17 : if (count($node->param) > 0) {
129 1 : $appender['params'] = $this->parseParameters($node);
130 1 : }
131 :
132 17 : foreach($node->filter as $filterNode) {
133 4 : $appender['filters'][] = $this->parseFilter($filterNode);
134 17 : }
135 :
136 17 : $this->config['appenders'][$name] = $appender;
137 17 : }
138 :
139 : /** Parses a <layout> node. */
140 : private function parseLayout(SimpleXMLElement $node, $appenderName) {
141 11 : $layout = array();
142 11 : $layout['class'] = $this->getAttributeValue($node, 'class');
143 :
144 11 : if (count($node->param) > 0) {
145 1 : $layout['params'] = $this->parseParameters($node);
146 1 : }
147 :
148 11 : return $layout;
149 : }
150 : /** Parses any <param> child nodes returning them in an array. */
151 : private function parseParameters($paramsNode) {
152 : $params = array();
153 2 :
154 : foreach($paramsNode->param as $paramNode) {
155 2 : if (empty($paramNode['name'])) {
156 2 : $this->warn("A <param> node is missing the required 'name' attribute. Skipping parameter.");
157 0 : continue;
158 0 : }
159 :
160 : $name = $this->getAttributeValue($paramNode, 'name');
161 2 : $value = $this->getAttributeValue($paramNode, 'value');
162 2 :
163 : $params[$name] = $value;
164 2 : }
165 2 :
166 : return $params;
167 2 : }
168 :
169 : /** Parses a <root> node. */
170 : private function parseRootLogger(SimpleXMLElement $node) {
171 : $logger = array();
172 18 :
173 : if (isset($node->level)) {
174 18 : $logger['level'] = $this->getAttributeValue($node->level, 'value');
175 18 : }
176 18 :
177 : $logger['appenders'] = array();
178 18 : foreach($node->appender_ref as $appender) {
179 18 : $logger['appenders'][] = $this->getAttributeValue($appender, 'ref');
180 18 : }
181 18 :
182 : $this->config['rootLogger'] = $logger;
183 18 : }
184 18 :
185 : /** Parses a <logger> node. */
186 : private function parseLogger(SimpleXMLElement $node) {
187 : $logger = array();
188 5 :
189 : $name = $this->getAttributeValue($node, 'name');
190 5 : if (empty($name)) {
191 5 : $this->warn("A <logger> node is missing the required 'name' attribute. Skipping logger definition.");
192 0 : return;
193 0 : }
194 :
195 : if (isset($node->level)) {
196 5 : $logger['level'] = $this->getAttributeValue($node->level, 'value');
197 5 : }
198 5 :
199 : if (isset($node['additivity'])) {
200 5 : $logger['additivity'] = $this->getAttributeValue($node, 'additivity');
201 2 : }
202 2 :
203 : $logger['appenders'] = $this->parseAppenderReferences($node, $name);
204 5 :
205 : // Check for duplicate loggers
206 : if (isset($this->config['loggers'][$name])) {
207 5 : $this->warn("Duplicate logger definition [$name]. Overwriting.");
208 2 : }
209 1 :
210 : $this->config['loggers'][$name] = $logger;
211 5 : }
212 5 :
213 : /**
214 : * Parses a <logger> node for appender references and returns them in an array.
215 : */
216 : private function parseAppenderReferences(SimpleXMLElement $node, $name) {
217 : $refs = array();
218 5 : foreach($node->appender_ref as $ref) {
219 5 : $refs[] = $this->getAttributeValue($ref, 'ref');
220 5 : }
221 5 :
222 : return $refs;
223 5 : }
224 :
225 : /** Parses a <filter> node. */
226 : private function parseFilter($filterNode) {
227 : $filter = array();
228 4 : $filter['class'] = $this->getAttributeValue($filterNode, 'class');
229 4 :
230 : if (count($filterNode->param) > 0) {
231 4 : $filter['params'] = $this->parseParameters($filterNode);
232 2 : }
233 2 :
234 : return $filter;
235 4 : }
236 :
237 : /** Parses a <renderer> node. */
238 : private function parseRenderer(SimpleXMLElement $node) {
239 : $renderedClass = $this->getAttributeValue($node, 'renderedClass');
240 6 : $renderingClass = $this->getAttributeValue($node, 'renderingClass');
241 6 :
242 : $this->config['renderers'][] = compact('renderedClass', 'renderingClass');
243 6 : }
244 6 :
245 : // ******************************************
246 : // ** Helper methods **
247 : // ******************************************
248 :
249 : private function getAttributeValue(SimpleXMLElement $node, $name) {
250 : return isset($node[$name]) ? (string) $node[$name] : null;
251 19 : }
252 :
253 : private function warn($message) {
254 : trigger_error("log4php: " . $message, E_USER_WARNING);
255 2 : }
256 1 : }
257 :
|