Subversion Repositories Programming Utils

Rev

Rev 113 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
113 rm5248 1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
 
18
#include <log4cxx/logstring.h>
19
#include <log4cxx/xml/domconfigurator.h>
20
#include <log4cxx/appender.h>
21
#include <log4cxx/layout.h>
22
#include <log4cxx/logger.h>
23
#include <log4cxx/logmanager.h>
24
#include <log4cxx/level.h>
25
#include <log4cxx/spi/filter.h>
26
#include <log4cxx/helpers/loglog.h>
27
#include <log4cxx/helpers/stringhelper.h>
28
#include <log4cxx/helpers/loader.h>
29
#include <log4cxx/helpers/optionconverter.h>
30
#include <log4cxx/config/propertysetter.h>
31
#include <log4cxx/spi/errorhandler.h>
32
#include <log4cxx/spi/loggerfactory.h>
33
#include <log4cxx/defaultloggerfactory.h>
34
#include <log4cxx/helpers/filewatchdog.h>
35
#include <log4cxx/helpers/synchronized.h>
36
#include <log4cxx/spi/loggerrepository.h>
37
#include <log4cxx/spi/loggingevent.h>
38
#include <log4cxx/helpers/pool.h>
39
#include <sstream>
40
#include <log4cxx/helpers/transcoder.h>
41
#include <log4cxx/rolling/rollingfileappender.h>
42
#include <log4cxx/rolling/filterbasedtriggeringpolicy.h>
43
#include <log4cxx/helpers/bytebuffer.h>
44
#include <log4cxx/helpers/charsetdecoder.h>
45
#include <log4cxx/net/smtpappender.h>
46
 
115 rm5248 47
#ifndef LOG4CXX_QT
48
#include <apr_xml.h>
49
#endif
50
 
113 rm5248 51
using namespace log4cxx;
52
using namespace log4cxx::xml;
53
using namespace log4cxx::helpers;
54
using namespace log4cxx::spi;
55
using namespace log4cxx::config;
56
using namespace log4cxx::rolling;
57
 
58
 
59
#if APR_HAS_THREADS
60
class XMLWatchdog  : public FileWatchdog
61
{
62
public:
63
        XMLWatchdog(const File& filename) : FileWatchdog(filename)
64
        {
65
        }
66
 
67
        /**
68
        Call DOMConfigurator#doConfigure with the
69
        <code>filename</code> to reconfigure log4cxx.
70
        */
71
        void doOnChange()
72
        {
73
                DOMConfigurator().doConfigure(file,
74
                        LogManager::getLoggerRepository());
75
        }
76
};
77
#endif
78
 
79
 
80
IMPLEMENT_LOG4CXX_OBJECT(DOMConfigurator)
81
 
82
#define CONFIGURATION_TAG "log4j:configuration"
83
#define OLD_CONFIGURATION_TAG "configuration"
84
#define APPENDER_TAG "appender"
85
#define APPENDER_REF_TAG "appender-ref"
86
#define PARAM_TAG "param"
87
#define LAYOUT_TAG "layout"
88
#define ROLLING_POLICY_TAG "rollingPolicy"
89
#define TRIGGERING_POLICY_TAG "triggeringPolicy"
90
#define CATEGORY "category"
91
#define LOGGER "logger"
92
#define LOGGER_REF "logger-ref"
93
#define CATEGORY_FACTORY_TAG "categoryFactory"
94
#define NAME_ATTR "name"
95
#define CLASS_ATTR "class"
96
#define VALUE_ATTR "value"
97
#define ROOT_TAG "root"
98
#define ROOT_REF "root-ref"
99
#define LEVEL_TAG "level"
100
#define PRIORITY_TAG "priority"
101
#define FILTER_TAG "filter"
102
#define ERROR_HANDLER_TAG "errorHandler"
103
#define REF_ATTR "ref"
104
#define ADDITIVITY_ATTR "additivity"
105
#define THRESHOLD_ATTR "threshold"
106
#define CONFIG_DEBUG_ATTR "configDebug"
107
#define INTERNAL_DEBUG_ATTR "debug"
108
 
109
DOMConfigurator::DOMConfigurator()
110
   : props(), repository() {
111
}
112
 
113
void DOMConfigurator::addRef() const {
114
   ObjectImpl::addRef();
115
}
116
 
117
void DOMConfigurator::releaseRef() const {
118
   ObjectImpl::releaseRef();
119
}
120
 
121
/**
122
Used internally to parse appenders by IDREF name.
123
*/
124
AppenderPtr DOMConfigurator::findAppenderByName(log4cxx::helpers::Pool& p,
125
                                                log4cxx::helpers::CharsetDecoderPtr& utf8Decoder,
126
                                                apr_xml_elem* element,
127
                                                apr_xml_doc* doc,
128
                                                const LogString& appenderName,
129
                                                AppenderMap& appenders) {
130
    AppenderPtr appender;
131
    std::string tagName(element->name);
132
    if (tagName == APPENDER_TAG) {
133
        if (appenderName == getAttribute(utf8Decoder, element, NAME_ATTR)) {
134
              appender = parseAppender(p, utf8Decoder, element, doc, appenders);
135
        }
136
    }
137
    if (element->first_child && !appender) {
138
         appender = findAppenderByName(p, utf8Decoder, element->first_child, doc, appenderName, appenders);
139
    }
140
    if (element->next && !appender) {
141
        appender = findAppenderByName(p, utf8Decoder, element->next, doc, appenderName, appenders);
142
    }
143
    return appender;
144
}
145
 
146
/**
147
 Used internally to parse appenders by IDREF element.
148
*/
149
AppenderPtr DOMConfigurator::findAppenderByReference(
150
                                                     log4cxx::helpers::Pool& p,
151
                                                     log4cxx::helpers::CharsetDecoderPtr& utf8Decoder,
152
                                                     apr_xml_elem* appenderRef,
153
                                                     apr_xml_doc* doc,
154
                                                     AppenderMap& appenders)
155
{
156
        LogString appenderName(subst(getAttribute(utf8Decoder, appenderRef, REF_ATTR)));
157
        AppenderMap::const_iterator match = appenders.find(appenderName);
158
        AppenderPtr appender;
159
        if (match != appenders.end()) {
160
            appender = match->second;
161
        } else if (doc) {
162
            appender = findAppenderByName(p, utf8Decoder, doc->root, doc, appenderName, appenders);
163
            if (appender) {
164
                appenders.insert(AppenderMap::value_type(appenderName, appender));
165
            }
166
        }
167
        if (!appender) {
168
                 LogLog::error(LOG4CXX_STR("No appender named [")+
169
                                appenderName+LOG4CXX_STR("] could be found."));
170
        }
171
        return appender;
172
}
173
 
174
/**
175
Used internally to parse an appender element.
176
*/
177
AppenderPtr DOMConfigurator::parseAppender(Pool& p,
178
                                           log4cxx::helpers::CharsetDecoderPtr& utf8Decoder,
179
                                           apr_xml_elem* appenderElement,
180
                                           apr_xml_doc* doc,
181
                                           AppenderMap& appenders)
182
{
183
 
184
    LogString className(subst(getAttribute(utf8Decoder, appenderElement, CLASS_ATTR)));
185
    LogLog::debug(LOG4CXX_STR("Class name: [") + className+LOG4CXX_STR("]"));
186
    try
187
        {
188
                ObjectPtr instance = Loader::loadClass(className).newInstance();
189
                AppenderPtr appender = instance;
190
                PropertySetter propSetter(appender);
191
 
192
                appender->setName(subst(getAttribute(utf8Decoder, appenderElement, NAME_ATTR)));
193
 
194
                for(apr_xml_elem* currentElement = appenderElement->first_child;
195
                     currentElement;
196
                     currentElement = currentElement->next) {
197
 
198
                                std::string tagName(currentElement->name);
199
 
200
                                // Parse appender parameters
201
                                if (tagName == PARAM_TAG)
202
                                {
203
                                        setParameter(p, utf8Decoder, currentElement, propSetter);
204
                                }
205
                                // Set appender layout
206
                                else if (tagName == LAYOUT_TAG)
207
                                {
208
                                        appender->setLayout(parseLayout(p, utf8Decoder, currentElement));
209
                                }
210
                                // Add filters
211
                                else if (tagName == FILTER_TAG)
212
                                {
213
                                        std::vector<log4cxx::spi::FilterPtr> filters;
214
                                        parseFilters(p, utf8Decoder, currentElement, filters);
215
                                        for(std::vector<log4cxx::spi::FilterPtr>::iterator iter = filters.begin();
216
                                            iter != filters.end();
217
                                            iter++) {
218
                                            appender->addFilter(*iter);
219
                                        }
220
                                }
221
                                else if (tagName == ERROR_HANDLER_TAG)
222
                                {
223
                                        parseErrorHandler(p, utf8Decoder, currentElement, appender, doc, appenders);
224
                                }
225
                                else if (tagName == ROLLING_POLICY_TAG)
226
                                {
227
                                        RollingPolicyPtr rollPolicy(parseRollingPolicy(p, utf8Decoder, currentElement));
228
                                        RollingFileAppenderPtr rfa(appender);
229
                                        if (rfa != NULL) {
230
                                           rfa->setRollingPolicy(rollPolicy);
231
                                        }
232
                                }
233
                                else if (tagName == TRIGGERING_POLICY_TAG)
234
                                {
235
                                        ObjectPtr policy(parseTriggeringPolicy(p, utf8Decoder, currentElement));
236
                                        RollingFileAppenderPtr rfa(appender);
237
                                        if (rfa != NULL) {
238
                                           rfa->setTriggeringPolicy(policy);
239
                                        } else {
240
                                            log4cxx::net::SMTPAppenderPtr smtpa(appender);
241
                                            if (smtpa != NULL) {
242
                                                log4cxx::spi::TriggeringEventEvaluatorPtr evaluator(policy);
243
                                                smtpa->setEvaluator(evaluator);
244
                                            }
245
                                        }
246
                                }
247
                                else if (tagName == APPENDER_REF_TAG)
248
                                {
249
                                        LogString refName = subst(getAttribute(utf8Decoder, currentElement, REF_ATTR));
250
                                        if(appender->instanceof(AppenderAttachable::getStaticClass()))
251
                                        {
252
                                                AppenderAttachablePtr aa(appender);
253
                                                LogLog::debug(LOG4CXX_STR("Attaching appender named [")+
254
                                                        refName+LOG4CXX_STR("] to appender named [")+
255
                                                        appender->getName()+LOG4CXX_STR("]."));
256
                                                aa->addAppender(findAppenderByReference(p, utf8Decoder, currentElement, doc, appenders));
257
                                        }
258
                                        else
259
                                        {
260
                                                LogLog::error(LOG4CXX_STR("Requesting attachment of appender named [")+
261
                                                        refName+ LOG4CXX_STR("] to appender named [")+ appender->getName()+
262
                                                        LOG4CXX_STR("] which does not implement AppenderAttachable."));
263
                                        }
264
                                }
265
                }
266
                propSetter.activate(p);
267
                return appender;
268
    }
269
    /* Yes, it's ugly.  But all of these exceptions point to the same
270
        problem: we can't create an Appender */
271
    catch (Exception& oops)
272
        {
273
                LogLog::error(LOG4CXX_STR("Could not create an Appender. Reported error follows."),
274
                        oops);
275
                return 0;
276
    }
277
}
278
 
279
/**
280
Used internally to parse an {@link ErrorHandler} element.
281
*/
282
void DOMConfigurator::parseErrorHandler(Pool& p,
283
                                        log4cxx::helpers::CharsetDecoderPtr& utf8Decoder,
284
                                        apr_xml_elem* element,
285
                                        AppenderPtr& appender,
286
                                        apr_xml_doc* doc,
287
                                        AppenderMap& appenders)
288
{
289
    ErrorHandlerPtr eh = OptionConverter::instantiateByClassName(
290
                subst(getAttribute(utf8Decoder, element, CLASS_ATTR)),
291
                ErrorHandler::getStaticClass(),
292
                0);
293
 
294
    if(eh != 0)
295
        {
296
                eh->setAppender(appender);
297
 
298
                PropertySetter propSetter(eh);
299
 
300
                for (apr_xml_elem* currentElement = element->first_child;
301
                     currentElement;
302
                     currentElement = currentElement->next) {
303
                                std::string tagName(currentElement->name);
304
                                if(tagName == PARAM_TAG)
305
                                {
306
                                        setParameter(p, utf8Decoder, currentElement, propSetter);
307
                                }
308
                                else if(tagName == APPENDER_REF_TAG)
309
                                {
310
                                        eh->setBackupAppender(findAppenderByReference(p, utf8Decoder, currentElement, doc, appenders));
311
                                }
312
                                else if(tagName == LOGGER_REF)
313
                                {
314
                                        LogString loggerName(getAttribute(utf8Decoder, currentElement, REF_ATTR));
315
                                        LoggerPtr logger = repository->getLogger(loggerName, loggerFactory);
316
                                        eh->setLogger(logger);
317
                                }
318
                                else if(tagName == ROOT_REF)
319
                                {
320
                                        LoggerPtr root = repository->getRootLogger();
321
                                        eh->setLogger(root);
322
                                }
323
                }
324
                propSetter.activate(p);
325
//                appender->setErrorHandler(eh);
326
    }
327
}
328
 
329
/**
330
 Used internally to parse a filter element.
331
*/
332
void DOMConfigurator::parseFilters(Pool& p,                                
333
                                   log4cxx::helpers::CharsetDecoderPtr& utf8Decoder,
334
                                   apr_xml_elem* element,
335
                                   std::vector<log4cxx::spi::FilterPtr>& filters)
336
{
337
        LogString clazz = subst(getAttribute(utf8Decoder, element, CLASS_ATTR));
338
        FilterPtr filter = OptionConverter::instantiateByClassName(clazz,
339
                Filter::getStaticClass(), 0);
340
 
341
        if(filter != 0)
342
        {
343
                PropertySetter propSetter(filter);
344
 
345
                for (apr_xml_elem* currentElement = element->first_child;
346
                     currentElement;
347
                     currentElement = currentElement->next)
348
                {
349
                                std::string tagName(currentElement->name);
350
                                if(tagName == PARAM_TAG)
351
                                {
352
                                        setParameter(p, utf8Decoder, currentElement, propSetter);
353
                                }
354
                }
355
                propSetter.activate(p);
356
                filters.push_back(filter);
357
        }
358
}
359
 
360
/**
361
Used internally to parse an category or logger element.
362
*/
363
void DOMConfigurator::parseLogger(
364
                                  log4cxx::helpers::Pool& p,
365
                                  log4cxx::helpers::CharsetDecoderPtr& utf8Decoder,                                  
366
                                  apr_xml_elem* loggerElement,
367
                                  apr_xml_doc* doc,
368
                                  AppenderMap& appenders)
369
{
370
        // Create a new Logger object from the <category> element.
371
        LogString loggerName = subst(getAttribute(utf8Decoder, loggerElement, NAME_ATTR));
372
 
373
        LogLog::debug(LOG4CXX_STR("Retreiving an instance of Logger."));
374
        LoggerPtr logger = repository->getLogger(loggerName, loggerFactory);
375
 
376
        // Setting up a logger needs to be an atomic operation, in order
377
        // to protect potential log operations while logger
378
        // configuration is in progress.
379
        synchronized sync(logger->getMutex());
380
        bool additivity = OptionConverter::toBoolean(
381
                subst(getAttribute(utf8Decoder, loggerElement, ADDITIVITY_ATTR)),
382
                true);
383
 
384
        LogLog::debug(LOG4CXX_STR("Setting [")+logger->getName()+LOG4CXX_STR("] additivity to [")+
385
                (additivity ? LogString(LOG4CXX_STR("true")) : LogString(LOG4CXX_STR("false")))+LOG4CXX_STR("]."));
386
        logger->setAdditivity(additivity);
387
        parseChildrenOfLoggerElement(p, utf8Decoder, loggerElement, logger, false, doc, appenders);
388
}
389
 
390
/**
391
 Used internally to parse the logger factory element.
392
*/
393
void DOMConfigurator::parseLoggerFactory(
394
                                  log4cxx::helpers::Pool& p,
395
                                  log4cxx::helpers::CharsetDecoderPtr& utf8Decoder,                                  
396
                                   apr_xml_elem* factoryElement)
397
{
398
        LogString className(subst(getAttribute(utf8Decoder, factoryElement, CLASS_ATTR)));
399
 
400
        if(className.empty())
401
        {
402
                LogLog::error(LOG4CXX_STR("Logger Factory tag class attribute not found."));
403
                LogLog::debug(LOG4CXX_STR("No Logger Factory configured."));
404
        }
405
        else
406
        {
407
                LogLog::debug(LOG4CXX_STR("Desired logger factory: [")+className+LOG4CXX_STR("]"));
408
                loggerFactory = OptionConverter::instantiateByClassName(
409
                        className,
410
                        LoggerFactory::getStaticClass(),
411
                        0);
412
                PropertySetter propSetter(loggerFactory);
413
 
414
                for (apr_xml_elem* currentElement = factoryElement->first_child;
415
                     currentElement;
416
                     currentElement = currentElement->next) {
417
                     std::string tagName(currentElement->name);
418
                     if (tagName == PARAM_TAG) {
419
                            setParameter(p, utf8Decoder, currentElement, propSetter);
420
                    }
421
                }
422
        }
423
}
424
 
425
/**
426
 Used internally to parse the root logger element.
427
*/
428
void DOMConfigurator::parseRoot(
429
                                  log4cxx::helpers::Pool& p,
430
                                  log4cxx::helpers::CharsetDecoderPtr& utf8Decoder,                                  
431
                                  apr_xml_elem* rootElement,
432
                                  apr_xml_doc* doc,
433
                                  AppenderMap& appenders)
434
{
435
        LoggerPtr root = repository->getRootLogger();
436
        // logger configuration needs to be atomic
437
        synchronized sync(root->getMutex());
438
        parseChildrenOfLoggerElement(p, utf8Decoder, rootElement, root, true, doc, appenders);
439
}
440
 
441
/**
442
 Used internally to parse the children of a logger element.
443
*/
444
void DOMConfigurator::parseChildrenOfLoggerElement(
445
                                  log4cxx::helpers::Pool& p,
446
                                  log4cxx::helpers::CharsetDecoderPtr& utf8Decoder,                                  
447
                                  apr_xml_elem* loggerElement, LoggerPtr logger, bool isRoot,
448
                                  apr_xml_doc* doc,
449
                                  AppenderMap& appenders)
450
{
451
 
452
    PropertySetter propSetter(logger);
453
 
454
    // Remove all existing appenders from logger. They will be
455
    // reconstructed if need be.
456
    logger->removeAllAppenders();
457
 
458
 
459
    for (apr_xml_elem* currentElement = loggerElement->first_child;
460
         currentElement;
461
         currentElement = currentElement->next) {
462
                        std::string tagName(currentElement->name);
463
 
464
                        if (tagName == APPENDER_REF_TAG)
465
                        {
466
                                AppenderPtr appender = findAppenderByReference(p, utf8Decoder, currentElement, doc, appenders);
467
                                LogString refName =  subst(getAttribute(utf8Decoder, currentElement, REF_ATTR));
468
                                if(appender != 0)
469
                                {
470
                                        LogLog::debug(LOG4CXX_STR("Adding appender named [")+ refName+
471
                                        LOG4CXX_STR("] to logger [")+logger->getName()+LOG4CXX_STR("]."));
472
                                }
473
                                else
474
                                {
475
                                        LogLog::debug(LOG4CXX_STR("Appender named [")+ refName +
476
                                                LOG4CXX_STR("] not found."));
477
                                }
478
 
479
                                logger->addAppender(appender);
480
 
481
                        }
482
                        else if(tagName == LEVEL_TAG)
483
                        {
484
                                parseLevel(p, utf8Decoder, currentElement, logger, isRoot);
485
                        }
486
                        else if(tagName == PRIORITY_TAG)
487
                        {
488
                                parseLevel(p, utf8Decoder, currentElement, logger, isRoot);
489
                        }
490
                        else if(tagName == PARAM_TAG)
491
                        {
492
                                setParameter(p, utf8Decoder, currentElement, propSetter);
493
                        }
494
    }
495
    propSetter.activate(p);
496
}
497
 
498
/**
499
 Used internally to parse a layout element.
500
*/
501
LayoutPtr DOMConfigurator::parseLayout (
502
                                  log4cxx::helpers::Pool& p,
503
                                  log4cxx::helpers::CharsetDecoderPtr& utf8Decoder,                                  
504
                                  apr_xml_elem* layout_element)
505
{
506
        LogString className(subst(getAttribute(utf8Decoder, layout_element, CLASS_ATTR)));
507
        LogLog::debug(LOG4CXX_STR("Parsing layout of class: \"")+className+LOG4CXX_STR("\""));
508
        try
509
        {
510
                ObjectPtr instance = Loader::loadClass(className).newInstance();
511
                LayoutPtr layout = instance;
512
                PropertySetter propSetter(layout);
513
 
514
                for(apr_xml_elem* currentElement = layout_element->first_child;
515
                    currentElement;
516
                    currentElement = currentElement->next) {
517
                                std::string tagName(currentElement->name);
518
                                if(tagName == PARAM_TAG)
519
                                {
520
                                        setParameter(p, utf8Decoder, currentElement, propSetter);
521
                                }
522
                }
523
 
524
                propSetter.activate(p);
525
                return layout;
526
        }
527
        catch (Exception& oops)
528
        {
529
                LogLog::error(LOG4CXX_STR("Could not create the Layout. Reported error follows."),
530
                        oops);
531
                return 0;
532
        }
533
}
534
 
535
/**
536
 Used internally to parse a triggering policy
537
*/
538
ObjectPtr DOMConfigurator::parseTriggeringPolicy (
539
                                  log4cxx::helpers::Pool& p,
540
                                  log4cxx::helpers::CharsetDecoderPtr& utf8Decoder,                                  
541
                                  apr_xml_elem* layout_element)
542
{
543
        LogString className = subst(getAttribute(utf8Decoder, layout_element, CLASS_ATTR));
544
        LogLog::debug(LOG4CXX_STR("Parsing triggering policy of class: \"")+className+LOG4CXX_STR("\""));
545
        try
546
        {
547
                ObjectPtr instance = Loader::loadClass(className).newInstance();
548
                PropertySetter propSetter(instance);
549
 
550
                for (apr_xml_elem* currentElement = layout_element->first_child;
551
                     currentElement;
552
                     currentElement = currentElement->next) {
553
                                std::string tagName(currentElement->name);
554
                                if(tagName == PARAM_TAG)
555
                                {
556
                                        setParameter(p, utf8Decoder, currentElement, propSetter);
557
                                }
558
                                else if (tagName == FILTER_TAG) {
559
                                  std::vector<log4cxx::spi::FilterPtr> filters;
560
                                  parseFilters(p, utf8Decoder, currentElement, filters);
561
                                  FilterBasedTriggeringPolicyPtr fbtp(instance);
562
                                  if (fbtp != NULL) {
563
                                    for(std::vector<log4cxx::spi::FilterPtr>::iterator iter = filters.begin();
564
                                        iter != filters.end();
565
                                        iter++) {
566
                                        fbtp->addFilter(*iter);
567
                                    }
568
                                  }
569
                                }
570
                }
571
 
572
                propSetter.activate(p);
573
                return instance;
574
        }
575
        catch (Exception& oops)
576
        {
577
                LogLog::error(LOG4CXX_STR("Could not create the TriggeringPolicy. Reported error follows."),
578
                        oops);
579
                return 0;
580
        }
581
}
582
 
583
/**
584
 Used internally to parse a triggering policy
585
*/
586
RollingPolicyPtr DOMConfigurator::parseRollingPolicy (
587
                                  log4cxx::helpers::Pool& p,
588
                                  log4cxx::helpers::CharsetDecoderPtr& utf8Decoder,                                  
589
                                  apr_xml_elem* layout_element)
590
{
591
        LogString className = subst(getAttribute(utf8Decoder, layout_element, CLASS_ATTR));
592
        LogLog::debug(LOG4CXX_STR("Parsing rolling policy of class: \"")+className+LOG4CXX_STR("\""));
593
        try
594
        {
595
                ObjectPtr instance = Loader::loadClass(className).newInstance();
596
                RollingPolicyPtr layout = instance;
597
                PropertySetter propSetter(layout);
598
 
599
                for(apr_xml_elem* currentElement = layout_element->first_child;
600
                    currentElement;
601
                    currentElement = currentElement->next) {
602
                                std::string tagName(currentElement->name);
603
                                if(tagName == PARAM_TAG)
604
                                {
605
                                        setParameter(p, utf8Decoder, currentElement, propSetter);
606
                        }
607
                }
608
 
609
                propSetter.activate(p);
610
                return layout;
611
        }
612
        catch (Exception& oops)
613
        {
614
                LogLog::error(LOG4CXX_STR("Could not create the RollingPolicy. Reported error follows."),
615
                        oops);
616
                return 0;
617
        }
618
}
619
 
620
 
621
 
622
/**
623
 Used internally to parse a level  element.
624
*/
625
void DOMConfigurator::parseLevel(
626
                                  log4cxx::helpers::Pool& p,
627
                                  log4cxx::helpers::CharsetDecoderPtr& utf8Decoder,                                  
628
                                  apr_xml_elem* element, LoggerPtr logger, bool isRoot)
629
{
630
    LogString loggerName = logger->getName();
631
    if(isRoot)
632
        {
633
                loggerName = LOG4CXX_STR("root");
634
    }
635
 
636
    LogString levelStr(subst(getAttribute(utf8Decoder, element, VALUE_ATTR)));
637
        LogLog::debug(LOG4CXX_STR("Level value for ")+loggerName+LOG4CXX_STR(" is [")+levelStr+LOG4CXX_STR("]."));
638
 
639
    if (StringHelper::equalsIgnoreCase(levelStr,LOG4CXX_STR("INHERITED"), LOG4CXX_STR("inherited"))
640
        || StringHelper::equalsIgnoreCase(levelStr, LOG4CXX_STR("NULL"), LOG4CXX_STR("null")))
641
        {
642
                if(isRoot)
643
                {
644
                        LogLog::error(LOG4CXX_STR("Root level cannot be inherited. Ignoring directive."));
645
                }
646
                else
647
                {
648
                        logger->setLevel(0);
649
                }
650
    }
651
        else
652
        {
653
                LogString className(subst(getAttribute(utf8Decoder, element, CLASS_ATTR)));
654
 
655
                if (className.empty())
656
                {
657
                        logger->setLevel(OptionConverter::toLevel(levelStr, Level::getDebug()));
658
                }
659
                else
660
                {
661
                        LogLog::debug(LOG4CXX_STR("Desired Level sub-class: [") + className + LOG4CXX_STR("]"));
662
 
663
                        try
664
                        {
665
                                Level::LevelClass& levelClass =
666
                                        (Level::LevelClass&)Loader::loadClass(className);
667
                                LevelPtr level = levelClass.toLevel(levelStr);
668
                                logger->setLevel(level);
669
                        }
670
                        catch (Exception& oops)
671
                        {
672
                                LogLog::error(
673
                                        LOG4CXX_STR("Could not create level [") + levelStr +
674
                                        LOG4CXX_STR("]. Reported error follows."),
675
                                        oops);
676
 
677
                                return;
678
                        }
679
                        catch (...)
680
                        {
681
                                LogLog::error(
682
                                        LOG4CXX_STR("Could not create level [") + levelStr);
683
 
684
                                return;
685
                        }
686
                }
687
    }
688
 
689
        LogLog::debug(loggerName + LOG4CXX_STR(" level set to ") +
690
                logger->getEffectiveLevel()->toString());
691
}
692
 
693
void DOMConfigurator::setParameter(log4cxx::helpers::Pool& p,
694
                                log4cxx::helpers::CharsetDecoderPtr& utf8Decoder,
695
                                apr_xml_elem* elem,
696
                                PropertySetter& propSetter)
697
{
698
        LogString name(subst(getAttribute(utf8Decoder, elem, NAME_ATTR)));
699
        LogString value(subst(getAttribute(utf8Decoder, elem, VALUE_ATTR)));
700
        value = subst(value);
701
        propSetter.setProperty(name, value, p);
702
}
703
 
704
void DOMConfigurator::doConfigure(const File& filename, spi::LoggerRepositoryPtr& repository1)
705
{
706
       repository1->setConfigured(true);
707
        this->repository = repository1;
708
        LogString msg(LOG4CXX_STR("DOMConfigurator configuring file "));
709
        msg.append(filename.getPath());
710
        msg.append(LOG4CXX_STR("..."));
711
        LogLog::debug(msg);
712
 
713
        loggerFactory = new DefaultLoggerFactory();
714
 
715
        Pool p;
716
        apr_file_t *fd;
717
 
718
        log4cxx_status_t rv = filename.open(&fd, APR_READ, APR_OS_DEFAULT, p);
719
        if (rv != APR_SUCCESS) {
720
            LogString msg2(LOG4CXX_STR("Could not open file ["));
721
            msg2.append(filename.getPath());
722
            msg2.append(LOG4CXX_STR("]."));
723
            LogLog::error(msg2);
724
        } else {
725
            apr_xml_parser *parser;
726
            apr_xml_doc *doc;
727
            rv = apr_xml_parse_file(p.getAPRPool(), &parser, &doc, fd, 2000);
728
            if (rv != APR_SUCCESS) {
729
                char errbuf[2000];
730
                char errbufXML[2000];
731
                LogString msg2(LOG4CXX_STR("Error parsing file ["));
732
                msg2.append(filename.getPath());
733
                msg2.append(LOG4CXX_STR("], "));
734
                apr_strerror(rv, errbuf, sizeof(errbuf));
735
                LOG4CXX_DECODE_CHAR(lerrbuf, std::string(errbuf));
736
                apr_xml_parser_geterror(parser, errbufXML, sizeof(errbufXML));
737
                LOG4CXX_DECODE_CHAR(lerrbufXML, std::string(errbufXML));
738
                msg2.append(lerrbuf);
739
                msg2.append(lerrbufXML);
740
                LogLog::error(msg2);
741
            } else {
742
                AppenderMap appenders;
743
                CharsetDecoderPtr utf8Decoder(CharsetDecoder::getUTF8Decoder());
744
                parse(p, utf8Decoder, doc->root, doc, appenders);
745
            }
746
        }
747
}
748
 
749
void DOMConfigurator::configure(const std::string& filename)
750
{
751
    File file(filename);
752
    DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository());
753
}
754
 
755
#if LOG4CXX_WCHAR_T_API
756
void DOMConfigurator::configure(const std::wstring& filename)
757
{
758
    File file(filename);
759
    DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository());
760
}
761
#endif
762
 
763
#if LOG4CXX_UNICHAR_API
764
void DOMConfigurator::configure(const std::basic_string<UniChar>& filename)
765
{
766
    File file(filename);
767
    DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository());
768
}
769
#endif
770
 
771
#if LOG4CXX_CFSTRING_API
772
void DOMConfigurator::configure(const CFStringRef& filename)
773
{
774
    File file(filename);
775
    DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository());
776
}
777
#endif
778
 
779
 
780
void DOMConfigurator::configureAndWatch(const std::string& filename)
781
{
782
  configureAndWatch(filename, FileWatchdog::DEFAULT_DELAY);
783
}
784
 
785
#if LOG4CXX_WCHAR_T_API
786
void DOMConfigurator::configureAndWatch(const std::wstring& filename)
787
{
788
  configureAndWatch(filename, FileWatchdog::DEFAULT_DELAY);
789
}
790
#endif
791
 
792
#if LOG4CXX_UNICHAR_API
793
void DOMConfigurator::configureAndWatch(const std::basic_string<UniChar>& filename)
794
{
795
  configureAndWatch(filename, FileWatchdog::DEFAULT_DELAY);
796
}
797
#endif
798
 
799
#if LOG4CXX_CFSTRING_API
800
void DOMConfigurator::configureAndWatch(const CFStringRef& filename)
801
{
802
  configureAndWatch(filename, FileWatchdog::DEFAULT_DELAY);
803
}
804
#endif
805
 
806
void DOMConfigurator::configureAndWatch(const std::string& filename, long delay)
807
{
808
        File file(filename);
809
#if APR_HAS_THREADS
810
        XMLWatchdog * xdog = new XMLWatchdog(file);
811
        xdog->setDelay(delay);
812
        xdog->start();
813
#else
814
    DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository());
815
#endif        
816
}
817
 
818
#if LOG4CXX_WCHAR_T_API
819
void DOMConfigurator::configureAndWatch(const std::wstring& filename, long delay)
820
{
821
        File file(filename);
822
#if APR_HAS_THREADS
823
        XMLWatchdog * xdog = new XMLWatchdog(file);
824
        xdog->setDelay(delay);
825
        xdog->start();
826
#else
827
    DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository());
828
#endif        
829
}
830
#endif
831
 
832
#if LOG4CXX_UNICHAR_API
833
void DOMConfigurator::configureAndWatch(const std::basic_string<UniChar>& filename, long delay)
834
{
835
        File file(filename);
836
#if APR_HAS_THREADS
837
        XMLWatchdog * xdog = new XMLWatchdog(file);
838
        xdog->setDelay(delay);
839
        xdog->start();
840
#else
841
    DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository());
842
#endif        
843
}
844
#endif
845
 
846
#if LOG4CXX_CFSTRING_API
847
void DOMConfigurator::configureAndWatch(const CFStringRef& filename, long delay)
848
{
849
        File file(filename);
850
#if APR_HAS_THREADS
851
        XMLWatchdog * xdog = new XMLWatchdog(file);
852
        xdog->setDelay(delay);
853
        xdog->start();
854
#else
855
    DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository());
856
#endif        
857
}
858
#endif
859
 
860
void DOMConfigurator::parse(
861
                            Pool& p,
862
                            log4cxx::helpers::CharsetDecoderPtr& utf8Decoder,
863
                            apr_xml_elem* element,
864
                            apr_xml_doc* doc,
865
                            AppenderMap& appenders)
866
{
867
    std::string rootElementName(element->name);
868
 
869
    if (rootElementName != CONFIGURATION_TAG)
870
        {
871
                if(rootElementName == OLD_CONFIGURATION_TAG)
872
                {
873
                        //LogLog::warn(LOG4CXX_STR("The <")+String(OLD_CONFIGURATION_TAG)+
874
                        // LOG4CXX_STR("> element has been deprecated."));
875
                        //LogLog::warn(LOG4CXX_STR("Use the <")+String(CONFIGURATION_TAG)+
876
                        // LOG4CXX_STR("> element instead."));
877
                }
878
                else
879
                {
880
                        LogLog::error(LOG4CXX_STR("DOM element is - not a <configuration> element."));
881
                        return;
882
                }
883
    }
884
 
885
    LogString debugAttrib = subst(getAttribute(utf8Decoder, element, INTERNAL_DEBUG_ATTR));
886
 
887
    static const LogString NuLL(LOG4CXX_STR("NULL"));
888
    LogLog::debug(LOG4CXX_STR("debug attribute= \"") + debugAttrib +LOG4CXX_STR("\"."));
889
    // if the log4j.dtd is not specified in the XML file, then the
890
    // "debug" attribute is returned as the empty string.
891
    if(!debugAttrib.empty() && debugAttrib != NuLL)
892
        {
893
                LogLog::setInternalDebugging(OptionConverter::toBoolean(debugAttrib, true));
894
    }
895
        else
896
        {
897
                LogLog::debug(LOG4CXX_STR("Ignoring internalDebug attribute."));
898
    }
899
 
900
 
901
    LogString confDebug = subst(getAttribute(utf8Decoder, element, CONFIG_DEBUG_ATTR));
902
    if(!confDebug.empty() && confDebug != NuLL)
903
        {
904
                LogLog::warn(LOG4CXX_STR("The \"configDebug\" attribute is deprecated."));
905
                LogLog::warn(LOG4CXX_STR("Use the \"internalDebug\" attribute instead."));
906
                LogLog::setInternalDebugging(OptionConverter::toBoolean(confDebug, true));
907
    }
908
 
909
    LogString thresholdStr = subst(getAttribute(utf8Decoder, element, THRESHOLD_ATTR));
910
    LogLog::debug(LOG4CXX_STR("Threshold =\"") + thresholdStr +LOG4CXX_STR("\"."));
911
    if(!thresholdStr.empty() && thresholdStr != NuLL)
912
        {
913
                repository->setThreshold(thresholdStr);
914
    }
915
 
916
    apr_xml_elem* currentElement;
917
    for(currentElement = element->first_child;
918
        currentElement;
919
        currentElement = currentElement->next) {
920
                        std::string tagName(currentElement->name);
921
 
922
                        if (tagName == CATEGORY_FACTORY_TAG)
923
                        {
924
                                parseLoggerFactory(p, utf8Decoder, currentElement);
925
                        }
926
    }
927
 
928
    for(currentElement = element->first_child;
929
        currentElement;
930
        currentElement = currentElement->next) {
931
                        std::string tagName(currentElement->name);
932
 
933
                        if (tagName == CATEGORY || tagName == LOGGER)
934
                        {
935
                                parseLogger(p, utf8Decoder, currentElement, doc, appenders);
936
                        }
937
                        else if (tagName == ROOT_TAG)
938
                        {
939
                                parseRoot(p, utf8Decoder, currentElement, doc, appenders);
940
                        }
941
    }
942
}
943
 
944
LogString DOMConfigurator::subst(const LogString& value)
945
{
946
    try
947
        {
948
                return OptionConverter::substVars(value, props);
949
    }
950
        catch(IllegalArgumentException& e)
951
        {
952
                LogLog::warn(LOG4CXX_STR("Could not perform variable substitution."), e);
953
                return value;
954
    }
955
}
956
 
957
 
958
LogString DOMConfigurator::getAttribute(
959
                                        log4cxx::helpers::CharsetDecoderPtr& utf8Decoder,
960
                                        apr_xml_elem* element,
961
                                        const std::string& attrName) {
962
    LogString attrValue;
963
    for(apr_xml_attr* attr = element->attr;
964
        attr;
965
        attr = attr->next) {
966
        if (attrName == attr->name) {
967
            ByteBuffer buf((char*) attr->value, strlen(attr->value));
968
            utf8Decoder->decode(buf, attrValue);
969
        }
970
    }
971
    return attrValue;
972
}