Coverage Report

Created: 2026-05-30 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/logging-log4cxx/src/main/cpp/domconfigurator.cpp
Line
Count
Source
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
#include <log4cxx/xml/domconfigurator.h>
18
#include <log4cxx/appender.h>
19
#include <log4cxx/asyncappender.h>
20
#include <log4cxx/layout.h>
21
#include <log4cxx/logger.h>
22
#include <log4cxx/logmanager.h>
23
#include <log4cxx/level.h>
24
#include <log4cxx/spi/filter.h>
25
#include <log4cxx/helpers/loglog.h>
26
#include <log4cxx/helpers/stringhelper.h>
27
#include <log4cxx/helpers/loader.h>
28
#include <log4cxx/helpers/optionconverter.h>
29
#include <log4cxx/config/propertysetter.h>
30
#include <log4cxx/varia/fallbackerrorhandler.h>
31
#include <log4cxx/spi/loggerfactory.h>
32
#if LOG4CXX_ABI_VERSION <= 15
33
#include <log4cxx/defaultloggerfactory.h>
34
#else
35
#include <log4cxx/spi/loggerfactory.h>
36
#endif
37
#include <log4cxx/helpers/filewatchdog.h>
38
#include <log4cxx/spi/loggerrepository.h>
39
#include <log4cxx/spi/loggingevent.h>
40
#include <log4cxx/helpers/pool.h>
41
#include <sstream>
42
#include <log4cxx/helpers/transcoder.h>
43
#include <log4cxx/rolling/rollingfileappender.h>
44
#include <log4cxx/rolling/filterbasedtriggeringpolicy.h>
45
#include <apr_xml.h>
46
#include <log4cxx/helpers/bytebuffer.h>
47
#include <log4cxx/helpers/charsetdecoder.h>
48
#include <log4cxx/net/smtpappender.h>
49
#include <log4cxx/helpers/messagebuffer.h>
50
#include <log4cxx/helpers/threadutility.h>
51
#include <log4cxx/helpers/singletonholder.h>
52
53
#define LOG4CXX 1
54
#include <log4cxx/helpers/aprinitializer.h>
55
56
using namespace LOG4CXX_NS;
57
using namespace LOG4CXX_NS::xml;
58
using namespace LOG4CXX_NS::helpers;
59
using namespace LOG4CXX_NS::spi;
60
using namespace LOG4CXX_NS::config;
61
using namespace LOG4CXX_NS::rolling;
62
63
0
#define MAX_ATTRIBUTE_NAME_LEN 2000
64
65
using FilterStore = std::vector<FilterPtr>;
66
67
struct DOMConfigurator::DOMConfiguratorPrivate
68
{
69
public: // Types
70
  struct AppenderStatus
71
  {
72
    AppenderPtr pAppender;
73
    bool activated;
74
  };
75
  using AppenderMap = std::map<LogString, AppenderStatus>;
76
77
public: // Attributes
78
  Properties props = Configurator::properties();
79
  LoggerRepositoryPtr repository;
80
#if LOG4CXX_ABI_VERSION <= 15
81
  LoggerFactoryPtr loggerFactory{ std::make_shared<DefaultLoggerFactory>() };
82
#else
83
  LoggerFactoryPtr loggerFactory{ std::make_shared<LoggerFactory>() };
84
#endif
85
  bool appenderAdded{ false };
86
  AppenderMap appenders;
87
  Pool p;
88
  CharsetDecoderPtr utf8Decoder{ CharsetDecoder::getDecoder(LOG4CXX_STR("UTF-8")) };
89
  apr_xml_doc* doc{ nullptr };
90
91
public: // ...structor
92
  DOMConfiguratorPrivate()
93
    : repository(LogManager::getLoggerRepository())
94
0
  {}
95
  
96
  DOMConfiguratorPrivate(const LoggerRepositoryPtr& r)
97
0
    : repository(r)
98
0
  {}
99
100
public: // Methods
101
  AppenderPtr findAppenderByName(apr_xml_elem* elem, const LogString& appenderName);
102
103
  AppenderPtr findAppenderByReference(apr_xml_elem* appenderRef, const char* optionalAttributeName = nullptr);
104
105
  AppenderPtr parseAppender(apr_xml_elem* appenderElement);
106
107
  void parseFallbackAppender(apr_xml_elem* element, const LogString& holderName, const AppenderAttachablePtr& holder, const AppenderPtr& primary, const AppenderSkeletonPtr& aSkel);
108
109
  void parseFallbackAppender(apr_xml_elem* element, const LoggerPtr& l, const AppenderSkeletonPtr& primary);
110
111
  void parseErrorHandler(apr_xml_elem* element, const AppenderPtr& appender);
112
113
  FilterStore parseFilters(apr_xml_elem* element);
114
115
  void parseLogger(apr_xml_elem* loggerElement);
116
117
  void parseLoggerFactory(apr_xml_elem* factoryElement);
118
119
  ObjectPtr parseTriggeringPolicy(apr_xml_elem* factoryElement);
120
121
  RollingPolicyPtr parseRollingPolicy(apr_xml_elem* factoryElement);
122
123
  void parseRoot(apr_xml_elem* rootElement);
124
125
  void parseChildrenOfLoggerElement(apr_xml_elem* catElement, LoggerPtr logger, bool isRoot);
126
127
  LayoutPtr parseLayout(apr_xml_elem* layout_element);
128
129
  void parseLevel(apr_xml_elem* element, LoggerPtr logger, bool isRoot);
130
131
  void setParameter(apr_xml_elem* elem, config::PropertySetter& propSetter);
132
133
  void parse(apr_xml_elem* element);
134
135
  LogString getAttribute(apr_xml_elem*, const std::string& attrName);
136
137
  LogString subst(const LogString& value);
138
};
139
140
namespace LOG4CXX_NS
141
{
142
namespace xml
143
{
144
class XMLWatchdog  : public FileWatchdog
145
{
146
  public:
147
0
    XMLWatchdog(const File& filename) : FileWatchdog(filename)
148
0
    {
149
0
    }
150
151
    /**
152
    Call DOMConfigurator#doConfigure with the
153
    <code>filename</code> to reconfigure log4cxx.
154
    */
155
    void doOnChange()
156
0
    {
157
0
      DOMConfigurator().doConfigure(file(),
158
0
        LogManager::getLoggerRepository());
159
0
    }
160
161
    static void startWatching(const File& filename, long delay)
162
0
    {
163
0
      using WatchdogHolder = SingletonHolder<XMLWatchdog>;
164
0
      auto pHolder = APRInitializer::getOrAddUnique<WatchdogHolder>
165
0
        ( [&filename]() -> ObjectPtr
166
0
          { return std::make_shared<WatchdogHolder>(filename); }
167
0
        );
168
0
      auto& xdog = pHolder->value();
169
0
      xdog.setFile(filename);
170
0
      xdog.setDelay(0 < delay ? delay : FileWatchdog::DEFAULT_DELAY);
171
0
      xdog.start();
172
0
    }
173
};
174
}
175
}
176
177
IMPLEMENT_LOG4CXX_OBJECT(DOMConfigurator)
178
179
0
#define CONFIGURATION_TAG "log4j:configuration"
180
0
#define OLD_CONFIGURATION_TAG "configuration"
181
0
#define APPENDER_TAG "appender"
182
0
#define APPENDER_REF_TAG "appender-ref"
183
0
#define PARAM_TAG "param"
184
0
#define LAYOUT_TAG "layout"
185
0
#define ROLLING_POLICY_TAG "rollingPolicy"
186
0
#define TRIGGERING_POLICY_TAG "triggeringPolicy"
187
0
#define CATEGORY "category"
188
0
#define LOGGER "logger"
189
0
#define LOGGER_REF "logger-ref"
190
0
#define CATEGORY_FACTORY_TAG "categoryFactory"
191
0
#define NAME_ATTR "name"
192
0
#define CLASS_ATTR "class"
193
0
#define VALUE_ATTR "value"
194
0
#define ROOT_TAG "root"
195
0
#define ROOT_REF "root-ref"
196
0
#define LEVEL_TAG "level"
197
0
#define PRIORITY_TAG "priority"
198
0
#define FILTER_TAG "filter"
199
0
#define ERROR_HANDLER_TAG "errorHandler"
200
0
#define REF_ATTR "ref"
201
#define FALLBACK_REF_ATTR "fallback-ref"
202
0
#define ADDITIVITY_ATTR "additivity"
203
0
#define ASYNCHRONOUS_ATTR "asynchronous"
204
0
#define THRESHOLD_ATTR "threshold"
205
#define STRINGSTREAM_ATTR "stringstream"
206
#define CONFIG_DEBUG_ATTR "configDebug"
207
0
#define INTERNAL_DEBUG_ATTR "debug"
208
0
#define INTERNAL_COLOR_ATTR "color"
209
0
#define THREAD_CONFIG_ATTR "threadConfiguration"
210
211
0
DOMConfigurator::DOMConfigurator() {}
Unexecuted instantiation: log4cxx::xml::DOMConfigurator::DOMConfigurator()
Unexecuted instantiation: log4cxx::xml::DOMConfigurator::DOMConfigurator()
212
213
0
DOMConfigurator::~DOMConfigurator() {}
214
215
/**
216
Used internally to parse appenders by IDREF name.
217
*/
218
AppenderPtr DOMConfigurator::DOMConfiguratorPrivate::findAppenderByName(apr_xml_elem* element, const LogString& appenderName)
219
0
{
220
0
  AppenderPtr appender;
221
222
0
  while (element)
223
0
  {
224
0
    if (std::string(element->name) == APPENDER_TAG)
225
0
    {
226
0
      if (appenderName == getAttribute(element, NAME_ATTR))
227
0
      {
228
0
        if (appender = parseAppender(element))
229
0
          break;
230
0
      }
231
0
    }
232
233
0
    if (element->first_child)
234
0
    {
235
0
      if (appender = findAppenderByName(element->first_child, appenderName))
236
0
        break;
237
0
    }
238
0
    element = element->next;
239
0
  }
240
241
0
  return appender;
242
0
}
243
244
/**
245
 Used internally to parse appenders by IDREF element.
246
*/
247
AppenderPtr DOMConfigurator::DOMConfiguratorPrivate::findAppenderByReference(apr_xml_elem* appenderRef, const char* optionalAttributeName)
248
0
{
249
0
  AppenderPtr appender;
250
0
  LogString appenderName = subst(getAttribute(appenderRef, optionalAttributeName ? optionalAttributeName : REF_ATTR));
251
0
  if (optionalAttributeName && appenderName.empty())
252
0
    return appender;
253
0
  if (appenderName.empty())
254
0
  {
255
0
    LogString msg(LOG4CXX_STR("["));
256
0
    utf8Decoder->decode(appenderRef->name, MAX_ATTRIBUTE_NAME_LEN, msg);
257
0
    msg += LOG4CXX_STR("] attribute [");
258
0
    utf8Decoder->decode(REF_ATTR, MAX_ATTRIBUTE_NAME_LEN, msg);
259
0
    msg += LOG4CXX_STR("] not found");
260
0
    LogLog::warn(msg);
261
0
    return appender;
262
0
  }
263
0
  AppenderMap::const_iterator match = appenders.find(appenderName);
264
265
0
  if (match != appenders.end())
266
0
  {
267
0
    if (!match->second.activated)
268
0
    {
269
0
      LogString msg(LOG4CXX_STR("Ignoring recursive reference to [") + appenderName + LOG4CXX_STR("]"));
270
0
      LogLog::warn(msg);
271
0
    }
272
0
    else
273
0
      appender = match->second.pAppender;
274
0
  }
275
0
  else if (doc)
276
0
  {
277
0
    appender = findAppenderByName(doc->root, appenderName);
278
0
  }
279
280
0
  if (!appender)
281
0
  {
282
0
    LogLog::error(LOG4CXX_STR("No ") + Appender::getStaticClass().getName()
283
0
      + LOG4CXX_STR(" named [") + appenderName + LOG4CXX_STR("] could be found."));
284
0
  }
285
286
0
  return appender;
287
0
}
288
289
/**
290
Used internally to parse an appender element.
291
*/
292
AppenderPtr DOMConfigurator::DOMConfiguratorPrivate::parseAppender(apr_xml_elem* appenderElement)
293
0
{
294
295
0
  LogString className(subst(getAttribute(appenderElement, CLASS_ATTR)));
296
0
  if (LogLog::isDebugEnabled())
297
0
  {
298
0
    LogLog::debug(LOG4CXX_STR("Desired ") + Appender::getStaticClass().getName()
299
0
          + LOG4CXX_STR(" sub-class: [") + className + LOG4CXX_STR("]"));
300
0
  }
301
302
0
  try
303
0
  {
304
0
    ObjectPtr instance = ObjectPtr(Loader::loadClass(className).newInstance());
305
0
    AppenderPtr appender = LOG4CXX_NS::cast<Appender>(instance);
306
0
    if(!appender){
307
0
      LogLog::error(LOG4CXX_STR("Could not cast [") + className + LOG4CXX_STR("] to ") + Appender::getStaticClass().getName());
308
0
      return AppenderPtr();
309
0
    }
310
0
    PropertySetter propSetter(appender);
311
312
0
    appender->setName(subst(getAttribute(appenderElement, NAME_ATTR)));
313
0
    appenders.emplace(appender->getName(), AppenderStatus{appender, false});
314
315
0
    for (apr_xml_elem* currentElement = appenderElement->first_child;
316
0
      currentElement;
317
0
      currentElement = currentElement->next)
318
0
    {
319
320
0
      std::string tagName(currentElement->name);
321
322
      // Parse appender parameters
323
0
      if (tagName == PARAM_TAG)
324
0
      {
325
0
        setParameter(currentElement, propSetter);
326
0
      }
327
      // Set appender layout
328
0
      else if (tagName == LAYOUT_TAG)
329
0
      {
330
0
        appender->setLayout(parseLayout(currentElement));
331
0
      }
332
      // Add filters
333
0
      else if (tagName == FILTER_TAG)
334
0
      {
335
0
        auto filters = parseFilters(currentElement);
336
337
0
        for (auto& item : filters)
338
0
        {
339
0
          appender->addFilter(item);
340
0
        }
341
0
      }
342
0
      else if (tagName == ERROR_HANDLER_TAG)
343
0
      {
344
0
        parseErrorHandler(currentElement, appender);
345
0
      }
346
0
      else if (tagName == ROLLING_POLICY_TAG)
347
0
      {
348
0
        auto rollPolicy = parseRollingPolicy(currentElement);
349
0
        RollingFileAppenderPtr rfa = LOG4CXX_NS::cast<RollingFileAppender>(appender);
350
351
0
        if (rfa != NULL)
352
0
        {
353
0
          rfa->setRollingPolicy(rollPolicy);
354
0
        }
355
0
      }
356
0
      else if (tagName == TRIGGERING_POLICY_TAG)
357
0
      {
358
0
        auto policy = parseTriggeringPolicy(currentElement);
359
0
        RollingFileAppenderPtr rfa = LOG4CXX_NS::cast<RollingFileAppender>(appender);
360
0
        TriggeringPolicyPtr policyPtr = LOG4CXX_NS::cast<TriggeringPolicy>(policy);
361
362
0
        if (rfa != NULL)
363
0
        {
364
0
          rfa->setTriggeringPolicy(policyPtr);
365
0
        }
366
0
        else
367
0
        {
368
0
          auto smtpa = LOG4CXX_NS::cast<LOG4CXX_NS::net::SMTPAppender>(appender);
369
370
0
          if (smtpa != NULL)
371
0
          {
372
0
            auto evaluator = LOG4CXX_NS::cast<TriggeringEventEvaluator>(policy);
373
0
            smtpa->setEvaluator(evaluator);
374
0
          }
375
0
        }
376
0
      }
377
0
      else if (tagName == APPENDER_REF_TAG)
378
0
      {
379
0
        if (appender->instanceof(AppenderAttachable::getStaticClass()))
380
0
        {
381
0
          AppenderAttachablePtr aa = LOG4CXX_NS::cast<AppenderAttachable>(appender);
382
0
          if (auto delegateAppender = findAppenderByReference(currentElement))
383
0
          {
384
0
            if (LogLog::isDebugEnabled())
385
0
            {
386
0
              LogLog::debug(LOG4CXX_STR("Attaching ") + Appender::getStaticClass().getName()
387
0
                + LOG4CXX_STR(" named [") + delegateAppender->getName() + LOG4CXX_STR("] to ") + Appender::getStaticClass().getName()
388
0
                + LOG4CXX_STR(" named [") + appender->getName() + LOG4CXX_STR("]"));
389
0
            }
390
0
            aa->addAppender(delegateAppender);
391
0
            if (auto appSkeleton = LOG4CXX_NS::cast<AppenderSkeleton>(appender))
392
0
              parseFallbackAppender(currentElement, appender->getName(), aa, delegateAppender, appSkeleton);
393
0
          }
394
0
        }
395
0
        else
396
0
        {
397
0
          LogLog::error(LOG4CXX_STR("Cannot attach to ") + Appender::getStaticClass().getName()
398
0
            + LOG4CXX_STR(" named [") + appender->getName() + LOG4CXX_STR("]")
399
0
            + LOG4CXX_STR(" which does not implement ") + AppenderAttachable::getStaticClass().getName());
400
0
        }
401
0
      }
402
0
      else
403
0
      {
404
0
        LogString msg{ LOG4CXX_STR("Ignoring unknown [") };
405
0
        utf8Decoder->decode(currentElement->name, MAX_ATTRIBUTE_NAME_LEN, msg);
406
0
        msg += LOG4CXX_STR("] ");
407
0
        utf8Decoder->decode(appenderElement->name, MAX_ATTRIBUTE_NAME_LEN, msg);
408
0
        msg += LOG4CXX_STR(" element");
409
0
        LogLog::warn(msg);
410
0
      }
411
0
    }
412
413
0
    propSetter.activate();
414
0
    appenders[appender->getName()].activated = true;
415
0
    return appender;
416
0
  }
417
  /* Yes, it's ugly.  But all of these exceptions point to the same
418
      problem: we can't create an Appender */
419
0
  catch (Exception& oops)
420
0
  {
421
0
    LogLog::error(LOG4CXX_STR("Could not create ") + Appender::getStaticClass().getName() + LOG4CXX_STR(" sub-class"), oops);
422
0
    return 0;
423
0
  }
424
0
}
425
426
void DOMConfigurator::DOMConfiguratorPrivate::parseFallbackAppender(apr_xml_elem* element, const LogString& holderName, const AppenderAttachablePtr& holder, const AppenderPtr& primary, const AppenderSkeletonPtr& aSkel)
427
0
{
428
0
  if (auto fallbackAppender = findAppenderByReference(element, FALLBACK_REF_ATTR))
429
0
  {
430
0
    auto fb = std::make_shared<varia::FallbackErrorHandler>();
431
0
    fb->setAppender(primary);
432
0
    fb->setBackupAppender(fallbackAppender);
433
0
    fb->addAppenderHolder(holderName, holder);
434
0
    aSkel->setErrorHandler(fb);
435
0
  }
436
0
}
437
438
void DOMConfigurator::DOMConfiguratorPrivate::parseFallbackAppender(apr_xml_elem* element, const LoggerPtr& l, const AppenderSkeletonPtr& primary)
439
0
{
440
0
  if (auto fallbackAppender = findAppenderByReference(element, FALLBACK_REF_ATTR))
441
0
  {
442
0
    auto fb = std::make_shared<varia::FallbackErrorHandler>();
443
0
    fb->setAppender(primary);
444
0
    fb->setBackupAppender(fallbackAppender);
445
0
    fb->setLogger(l);
446
0
    primary->setErrorHandler(fb);
447
0
  }
448
0
}
449
450
/**
451
Used internally to parse an {@link ErrorHandler} element.
452
*/
453
void DOMConfigurator::DOMConfiguratorPrivate::parseErrorHandler(apr_xml_elem* element, const AppenderPtr& appender)
454
0
{
455
456
0
  ErrorHandlerPtr eh;
457
0
  std::shared_ptr<Object> obj = OptionConverter::instantiateByClassName(
458
0
      subst(getAttribute(element, CLASS_ATTR)),
459
0
      ErrorHandler::getStaticClass(),
460
0
      0);
461
0
  eh = LOG4CXX_NS::cast<ErrorHandler>(obj);
462
463
0
  if (eh != 0)
464
0
  {
465
0
    eh->setAppender(appender);
466
467
0
    PropertySetter propSetter(eh);
468
469
0
    for (apr_xml_elem* currentElement = element->first_child;
470
0
      currentElement;
471
0
      currentElement = currentElement->next)
472
0
    {
473
0
      std::string tagName(currentElement->name);
474
475
0
      if (tagName == PARAM_TAG)
476
0
      {
477
0
        setParameter(currentElement, propSetter);
478
0
      }
479
0
      else if (tagName == APPENDER_REF_TAG)
480
0
      {
481
0
        if (auto appender = findAppenderByReference(currentElement))
482
0
          eh->setBackupAppender(appender);
483
0
      }
484
0
      else if (tagName == LOGGER_REF)
485
0
      {
486
0
        LogString loggerName(getAttribute(currentElement, REF_ATTR));
487
0
        LoggerPtr logger = this->repository->getLogger(loggerName, this->loggerFactory);
488
0
        eh->setLogger(logger);
489
0
      }
490
0
      else if (tagName == ROOT_REF)
491
0
      {
492
0
        LoggerPtr root = this->repository->getRootLogger();
493
0
        eh->setLogger(root);
494
0
      }
495
0
      else
496
0
      {
497
0
        LogString msg{ LOG4CXX_STR("Ignoring unknown [") };
498
0
        utf8Decoder->decode(currentElement->name, MAX_ATTRIBUTE_NAME_LEN, msg);
499
0
        msg += LOG4CXX_STR("] ");
500
0
        utf8Decoder->decode(element->name, MAX_ATTRIBUTE_NAME_LEN, msg);
501
0
        msg += LOG4CXX_STR(" element");
502
0
        LogLog::warn(msg);
503
0
      }
504
0
    }
505
506
0
    propSetter.activate();
507
0
    if (auto appSkeleton = LOG4CXX_NS::cast<AppenderSkeleton>(appender))
508
0
      appSkeleton->setErrorHandler(eh);
509
0
  }
510
0
}
511
512
/**
513
 Used internally to parse a filter element.
514
*/
515
FilterStore DOMConfigurator::DOMConfiguratorPrivate::parseFilters(apr_xml_elem* element)
516
0
{
517
0
  FilterStore result;
518
0
  LogString clazz = subst(getAttribute(element, CLASS_ATTR));
519
0
  FilterPtr filter;
520
0
  std::shared_ptr<Object> obj = OptionConverter::instantiateByClassName(clazz,
521
0
      Filter::getStaticClass(), 0);
522
0
  filter = LOG4CXX_NS::cast<Filter>(obj);
523
524
0
  if (filter != 0)
525
0
  {
526
0
    PropertySetter propSetter(filter);
527
528
0
    for (apr_xml_elem* currentElement = element->first_child;
529
0
      currentElement;
530
0
      currentElement = currentElement->next)
531
0
    {
532
0
      std::string tagName(currentElement->name);
533
534
0
      if (tagName == PARAM_TAG)
535
0
      {
536
0
        setParameter(currentElement, propSetter);
537
0
      }
538
0
      else
539
0
      {
540
0
        LogString msg{ LOG4CXX_STR("Ignoring unknown [") };
541
0
        utf8Decoder->decode(currentElement->name, MAX_ATTRIBUTE_NAME_LEN, msg);
542
0
        msg += LOG4CXX_STR("] ");
543
0
        utf8Decoder->decode(element->name, MAX_ATTRIBUTE_NAME_LEN, msg);
544
0
        msg += LOG4CXX_STR(" element");
545
0
        LogLog::warn(msg);
546
0
      }
547
0
    }
548
549
0
    propSetter.activate();
550
0
    result.push_back(filter);
551
0
  }
552
0
  return result;
553
0
}
554
555
/**
556
Used internally to parse an category or logger element.
557
*/
558
void DOMConfigurator::DOMConfiguratorPrivate::parseLogger(apr_xml_elem* loggerElement)
559
0
{
560
  // Create a new Logger object from the <category> element.
561
0
  LogString loggerName = subst(getAttribute(loggerElement, NAME_ATTR));
562
563
0
  if (LogLog::isDebugEnabled())
564
0
  {
565
0
    LogLog::debug(LOG4CXX_STR("Getting [") + loggerName + LOG4CXX_STR("]"));
566
0
  }
567
0
  LoggerPtr logger = this->repository->getLogger(loggerName, this->loggerFactory);
568
569
  // Setting up a logger needs to be an atomic operation, in order
570
  // to protect potential log operations while logger
571
  // configuration is in progress.
572
0
  bool additivity = OptionConverter::toBoolean(
573
0
      subst(getAttribute(loggerElement, ADDITIVITY_ATTR)),
574
0
      true);
575
576
0
  if (LogLog::isDebugEnabled())
577
0
  {
578
0
    LogLog::debug(LOG4CXX_STR("Setting [") + logger->getName() + LOG4CXX_STR("] additivity to [") +
579
0
      (additivity ? LogString(LOG4CXX_STR("true")) : LogString(LOG4CXX_STR("false"))) + LOG4CXX_STR("]"));
580
0
  }
581
0
  logger->setAdditivity(additivity);
582
0
  parseChildrenOfLoggerElement(loggerElement, logger, false);
583
0
}
584
585
/**
586
 Used internally to parse the logger factory element.
587
*/
588
void DOMConfigurator::DOMConfiguratorPrivate::parseLoggerFactory(apr_xml_elem* factoryElement)
589
0
{
590
0
  LogString className(subst(getAttribute(factoryElement, CLASS_ATTR)));
591
592
0
  if (className.empty())
593
0
  {
594
0
    LogString msg(LOG4CXX_STR("["));
595
0
    utf8Decoder->decode(factoryElement->name, MAX_ATTRIBUTE_NAME_LEN, msg);
596
0
    msg += LOG4CXX_STR("] attribute [");
597
0
    utf8Decoder->decode(CLASS_ATTR, MAX_ATTRIBUTE_NAME_LEN, msg);
598
0
    msg += LOG4CXX_STR("] not found");
599
0
    LogLog::warn(msg);
600
0
  }
601
0
  else
602
0
  {
603
0
    auto obj = OptionConverter::instantiateByClassName
604
0
      ( StringHelper::trim(className)
605
0
      , LoggerFactory::getStaticClass()
606
0
#if LOG4CXX_ABI_VERSION <= 15
607
0
      , std::make_shared<DefaultLoggerFactory>()
608
#else
609
      , std::make_shared<LoggerFactory>()
610
#endif
611
0
      );
612
0
    this->loggerFactory = LOG4CXX_NS::cast<LoggerFactory>(obj);
613
0
    PropertySetter propSetter(this->loggerFactory);
614
615
0
    for (apr_xml_elem* currentElement = factoryElement->first_child;
616
0
      currentElement;
617
0
      currentElement = currentElement->next)
618
0
    {
619
0
      std::string tagName(currentElement->name);
620
621
0
      if (tagName == PARAM_TAG)
622
0
      {
623
0
        setParameter(currentElement, propSetter);
624
0
      }
625
0
    }
626
0
  }
627
0
}
628
629
/**
630
 Used internally to parse the root logger element.
631
*/
632
void DOMConfigurator::DOMConfiguratorPrivate::parseRoot(apr_xml_elem* rootElement)
633
0
{
634
0
  LoggerPtr root = this->repository->getRootLogger();
635
0
  parseChildrenOfLoggerElement(rootElement, root, true);
636
0
}
637
638
/**
639
 Used internally to parse the children of a logger element.
640
*/
641
void DOMConfigurator::DOMConfiguratorPrivate::parseChildrenOfLoggerElement(apr_xml_elem* loggerElement, LoggerPtr logger, bool isRoot)
642
0
{
643
0
  PropertySetter propSetter(logger);
644
0
  auto loggerName = this->repository->getRootLogger() == logger
645
0
          ? LogString(LOG4CXX_STR("root"))
646
0
          : logger->getName();
647
0
  AsyncAppenderPtr async;
648
0
  auto lsAsynchronous = subst(getAttribute(loggerElement, ASYNCHRONOUS_ATTR));
649
0
  if (!lsAsynchronous.empty() && OptionConverter::toBoolean(lsAsynchronous, true))
650
0
  {
651
0
    async = std::make_shared<AsyncAppender>();
652
0
    async->setName(loggerName);
653
0
  }
654
655
0
  std::vector<AppenderPtr> newappenders;
656
0
  for (apr_xml_elem* currentElement = loggerElement->first_child;
657
0
    currentElement;
658
0
    currentElement = currentElement->next)
659
0
  {
660
0
    std::string tagName(currentElement->name);
661
662
0
    if (tagName == APPENDER_REF_TAG)
663
0
    {
664
0
      if (auto appender = findAppenderByReference(currentElement))
665
0
      {
666
0
        if (log4cxx::cast<AsyncAppender>(appender)) // An explicitly configured AsyncAppender?
667
0
          async.reset(); // Not required
668
0
        if (LogLog::isDebugEnabled())
669
0
        {
670
0
          LogLog::debug(LOG4CXX_STR("Adding ") + Appender::getStaticClass().getName()
671
0
            + LOG4CXX_STR(" named [") + appender->getName() + LOG4CXX_STR("]")
672
0
            + LOG4CXX_STR(" to logger [") + logger->getName() + LOG4CXX_STR("]"));
673
0
        }
674
0
        newappenders.push_back(appender);
675
0
        if (async)
676
0
        {
677
0
          async->addAppender(appender);
678
0
          parseFallbackAppender(currentElement, async->getName(), async, appender, async);
679
0
        }
680
0
        else if (auto appSkeleton = LOG4CXX_NS::cast<AppenderSkeleton>(appender))
681
0
          parseFallbackAppender(currentElement, logger, appSkeleton);
682
0
      }
683
0
    }
684
0
    else if (tagName == LEVEL_TAG)
685
0
    {
686
0
      parseLevel(currentElement, logger, isRoot);
687
0
    }
688
0
    else if (tagName == PRIORITY_TAG)
689
0
    {
690
0
      parseLevel(currentElement, logger, isRoot);
691
0
    }
692
0
    else if (tagName == PARAM_TAG)
693
0
    {
694
0
      setParameter(currentElement, propSetter);
695
0
    }
696
0
    else
697
0
    {
698
0
      LogString msg{ LOG4CXX_STR("Ignoring unknown [") };
699
0
      utf8Decoder->decode(currentElement->name, MAX_ATTRIBUTE_NAME_LEN, msg);
700
0
      msg += LOG4CXX_STR("] ");
701
0
      utf8Decoder->decode(loggerElement->name, MAX_ATTRIBUTE_NAME_LEN, msg);
702
0
      msg += LOG4CXX_STR(" element");
703
0
      LogLog::warn(msg);
704
0
    }
705
0
  }
706
0
  if (async && !newappenders.empty())
707
0
  {
708
0
    if (LogLog::isDebugEnabled())
709
0
    {
710
0
      LogLog::debug(LOG4CXX_STR("Asynchronous logging for [")
711
0
          + logger->getName() + LOG4CXX_STR("] is on"));
712
0
    }
713
0
    logger->replaceAppenders({async});
714
0
    this->appenderAdded = true;
715
0
  }
716
0
  else if (newappenders.empty())
717
0
    logger->removeAllAppenders();
718
0
  else
719
0
  {
720
0
    logger->replaceAppenders(newappenders);
721
0
    this->appenderAdded = true;
722
0
  }
723
0
  propSetter.activate();
724
0
}
725
726
/**
727
 Used internally to parse a layout element.
728
*/
729
LayoutPtr DOMConfigurator::DOMConfiguratorPrivate::parseLayout(apr_xml_elem* layout_element)
730
0
{
731
0
  LogString className(subst(getAttribute(layout_element, CLASS_ATTR)));
732
0
  if (LogLog::isDebugEnabled())
733
0
  {
734
0
    LogLog::debug(LOG4CXX_STR("Desired ") + Layout::getStaticClass().getName()
735
0
          + LOG4CXX_STR(" sub-class: [") + className + LOG4CXX_STR("]"));
736
0
  }
737
738
0
  try
739
0
  {
740
0
    ObjectPtr instance = ObjectPtr(Loader::loadClass(className).newInstance());
741
0
    LayoutPtr layout = LOG4CXX_NS::cast<Layout>(instance);
742
0
    PropertySetter propSetter(layout);
743
744
0
    for (apr_xml_elem* currentElement = layout_element->first_child;
745
0
      currentElement;
746
0
      currentElement = currentElement->next)
747
0
    {
748
0
      std::string tagName(currentElement->name);
749
750
0
      if (tagName == PARAM_TAG)
751
0
      {
752
0
        setParameter(currentElement, propSetter);
753
0
      }
754
0
      else
755
0
      {
756
0
        LogString msg{ LOG4CXX_STR("Ignoring unknown [") };
757
0
        utf8Decoder->decode(currentElement->name, MAX_ATTRIBUTE_NAME_LEN, msg);
758
0
        msg += LOG4CXX_STR("] ");
759
0
        utf8Decoder->decode(layout_element->name, MAX_ATTRIBUTE_NAME_LEN, msg);
760
0
        msg += LOG4CXX_STR(" element");
761
0
        LogLog::warn(msg);
762
0
      }
763
0
    }
764
765
0
    propSetter.activate();
766
0
    return layout;
767
0
  }
768
0
  catch (Exception& oops)
769
0
  {
770
0
    LogLog::error(LOG4CXX_STR("Could not create ") + Layout::getStaticClass().getName() + LOG4CXX_STR(" sub-class"), oops);
771
0
    return 0;
772
0
  }
773
0
}
774
775
/**
776
 Used internally to parse a triggering policy
777
*/
778
ObjectPtr DOMConfigurator::DOMConfiguratorPrivate::parseTriggeringPolicy(apr_xml_elem* policy_element)
779
0
{
780
0
  LogString className = subst(getAttribute(policy_element, CLASS_ATTR));
781
0
  if (LogLog::isDebugEnabled())
782
0
  {
783
0
    LogLog::debug(LOG4CXX_STR("Desired ") + TriggeringPolicy::getStaticClass().getName()
784
0
          + LOG4CXX_STR(" sub-class: [") + className + LOG4CXX_STR("]"));
785
0
  }
786
787
0
  try
788
0
  {
789
0
    ObjectPtr instance = ObjectPtr(Loader::loadClass(className).newInstance());
790
0
    PropertySetter propSetter(instance);
791
792
0
    for (apr_xml_elem* currentElement = policy_element->first_child;
793
0
      currentElement;
794
0
      currentElement = currentElement->next)
795
0
    {
796
0
      std::string tagName(currentElement->name);
797
798
0
      if (tagName == PARAM_TAG)
799
0
      {
800
0
        setParameter(currentElement, propSetter);
801
0
      }
802
0
      else if (tagName == FILTER_TAG)
803
0
      {
804
0
        auto filters = parseFilters(currentElement);
805
0
        if (auto fbtp = LOG4CXX_NS::cast<FilterBasedTriggeringPolicy>(instance))
806
0
        {
807
0
          for (auto& item : filters)
808
0
          {
809
0
            fbtp->addFilter(item);
810
0
          }
811
0
        }
812
0
      }
813
0
      else
814
0
      {
815
0
        LogString msg{ LOG4CXX_STR("Ignoring unknown [") };
816
0
        utf8Decoder->decode(currentElement->name, MAX_ATTRIBUTE_NAME_LEN, msg);
817
0
        msg += LOG4CXX_STR("] ");
818
0
        utf8Decoder->decode(policy_element->name, MAX_ATTRIBUTE_NAME_LEN, msg);
819
0
        msg += LOG4CXX_STR(" element");
820
0
        LogLog::warn(msg);
821
0
      }
822
0
    }
823
824
0
    propSetter.activate();
825
0
    return instance;
826
0
  }
827
0
  catch (Exception& oops)
828
0
  {
829
0
    LogLog::error(LOG4CXX_STR("Could not create ") + TriggeringPolicy::getStaticClass().getName() + LOG4CXX_STR(" sub-class"), oops);
830
0
    return 0;
831
0
  }
832
0
}
833
834
/**
835
 Used internally to parse a triggering policy
836
*/
837
RollingPolicyPtr DOMConfigurator::DOMConfiguratorPrivate::parseRollingPolicy(apr_xml_elem* policy_element)
838
0
{
839
0
  LogString className = subst(getAttribute(policy_element, CLASS_ATTR));
840
0
  if (LogLog::isDebugEnabled())
841
0
  {
842
0
    LogLog::debug(LOG4CXX_STR("Desired ") + RollingPolicy::getStaticClass().getName()
843
0
          + LOG4CXX_STR(" sub-class: [") + className + LOG4CXX_STR("]"));
844
0
  }
845
846
0
  try
847
0
  {
848
0
    ObjectPtr instance = ObjectPtr(Loader::loadClass(className).newInstance());
849
0
    PropertySetter propSetter(instance);
850
851
0
    for (apr_xml_elem* currentElement = policy_element->first_child;
852
0
      currentElement;
853
0
      currentElement = currentElement->next)
854
0
    {
855
0
      std::string tagName(currentElement->name);
856
857
0
      if (tagName == PARAM_TAG)
858
0
      {
859
0
        setParameter(currentElement, propSetter);
860
0
      }
861
0
      else
862
0
      {
863
0
        LogString msg{ LOG4CXX_STR("Ignoring unknown [") };
864
0
        utf8Decoder->decode(currentElement->name, MAX_ATTRIBUTE_NAME_LEN, msg);
865
0
        msg += LOG4CXX_STR("] ");
866
0
        utf8Decoder->decode(policy_element->name, MAX_ATTRIBUTE_NAME_LEN, msg);
867
0
        msg += LOG4CXX_STR(" element");
868
0
        LogLog::warn(msg);
869
0
      }
870
0
    }
871
872
0
    propSetter.activate();
873
0
    return LOG4CXX_NS::cast<RollingPolicy>(instance);
874
0
  }
875
0
  catch (Exception& oops)
876
0
  {
877
0
    LogLog::error(LOG4CXX_STR("Could not create ") + RollingPolicy::getStaticClass().getName() + LOG4CXX_STR(" sub-class"), oops);
878
0
    return 0;
879
0
  }
880
0
}
881
882
883
884
/**
885
 Used internally to parse a level  element.
886
*/
887
void DOMConfigurator::DOMConfiguratorPrivate::parseLevel(apr_xml_elem* element, LoggerPtr logger, bool isRoot)
888
0
{
889
0
  LogString loggerName = logger->getName();
890
891
0
  if (isRoot)
892
0
  {
893
0
    loggerName = LOG4CXX_STR("root");
894
0
  }
895
896
0
  LogString levelStr(subst(getAttribute(element, VALUE_ATTR)));
897
0
  if (LogLog::isDebugEnabled())
898
0
  {
899
0
    LogLog::debug(LOG4CXX_STR("Setting [") + loggerName + LOG4CXX_STR("] level to [") + levelStr + LOG4CXX_STR("]"));
900
0
  }
901
902
0
  if (StringHelper::equalsIgnoreCase(levelStr, LOG4CXX_STR("INHERITED"), LOG4CXX_STR("inherited"))
903
0
    || StringHelper::equalsIgnoreCase(levelStr, LOG4CXX_STR("NULL"), LOG4CXX_STR("null")))
904
0
  {
905
0
    if (isRoot)
906
0
    {
907
0
      LogLog::error(LOG4CXX_STR("Root level cannot be ") + levelStr + LOG4CXX_STR(". Ignoring directive."));
908
0
    }
909
0
    else
910
0
    {
911
0
      logger->setLevel(0);
912
0
    }
913
0
  }
914
0
  else
915
0
  {
916
0
    LogString className(subst(getAttribute(element, CLASS_ATTR)));
917
918
0
    if (className.empty())
919
0
    {
920
0
      logger->setLevel(OptionConverter::toLevel(levelStr, Level::getDebug()));
921
0
    }
922
0
    else
923
0
    {
924
0
      if (LogLog::isDebugEnabled())
925
0
      {
926
0
        LogLog::debug(LOG4CXX_STR("Desired ") + Level::getStaticClass().getName()
927
0
          + LOG4CXX_STR(" sub-class: [") + className + LOG4CXX_STR("]"));
928
0
      }
929
930
0
      try
931
0
      {
932
0
        logger->setLevel(dynamic_cast<const Level::LevelClass&>(Loader::loadClass(className)).toLevel(levelStr));
933
0
      }
934
0
      catch (Exception& oops)
935
0
      {
936
0
        LogLog::error(LOG4CXX_STR("Could not create ") + Level::getStaticClass().getName() + LOG4CXX_STR(" sub-class"), oops);
937
0
        return;
938
0
      }
939
0
      catch (...)
940
0
      {
941
0
        LogLog::error(LOG4CXX_STR("Could not create ") + Level::getStaticClass().getName() + LOG4CXX_STR(" sub-class")
942
0
              + LOG4CXX_STR(" from [") + className
943
0
              + LOG4CXX_STR("]"));
944
0
        return;
945
0
      }
946
0
    }
947
0
  }
948
949
0
  if (LogLog::isDebugEnabled())
950
0
  {
951
0
    LogLog::debug(LOG4CXX_STR("[") + loggerName + LOG4CXX_STR("] level is ") +
952
0
      logger->getEffectiveLevel()->toString());
953
0
  }
954
0
}
955
956
void DOMConfigurator::DOMConfiguratorPrivate::setParameter(apr_xml_elem* elem, PropertySetter& propSetter)
957
0
{
958
0
  LogString name(subst(getAttribute(elem, NAME_ATTR)));
959
0
  LogString value(subst(getAttribute(elem, VALUE_ATTR)));
960
0
  value = subst(value);
961
0
  propSetter.setProperty(name, value);
962
0
}
963
964
spi::ConfigurationStatus DOMConfigurator::doConfigure
965
  ( const File&                     filename
966
#if LOG4CXX_ABI_VERSION <= 15
967
  , spi::LoggerRepositoryPtr        repository
968
#else
969
  , const spi::LoggerRepositoryPtr& repository
970
#endif
971
  )
972
0
{
973
0
  m_priv = std::make_unique<DOMConfiguratorPrivate>
974
0
    ( repository ? repository : LogManager::getLoggerRepository()
975
0
    );
976
977
0
  apr_file_t* fd;
978
0
  log4cxx_status_t rv = apr_file_open(&fd, filename.getAPRPath(), APR_READ, APR_OS_DEFAULT, m_priv->p.getAPRPool());
979
980
0
  if (rv != APR_SUCCESS)
981
0
  {
982
0
    LogLog::error(LOG4CXX_STR("Could not open configuration file [")
983
0
      + filename.getPath() + LOG4CXX_STR("]")
984
0
      , IOException(rv));
985
0
    return spi::ConfigurationStatus::NotConfigured;
986
0
  }
987
0
  else
988
0
  {
989
0
    if (LogLog::isDebugEnabled())
990
0
    {
991
0
      LogLog::debug(LOG4CXX_STR("Loading configuration file [")
992
0
          + filename.getPath() + LOG4CXX_STR("]"));
993
0
    }
994
995
0
    apr_xml_parser* parser = NULL;
996
0
    rv = apr_xml_parse_file(m_priv->p.getAPRPool(), &parser, &m_priv->doc, fd, 2000);
997
998
0
    if (rv != APR_SUCCESS)
999
0
    {
1000
0
      LogString reason;
1001
0
      if (parser)
1002
0
      {
1003
0
        char errbuf[2000];
1004
0
        apr_xml_parser_geterror(parser, errbuf, sizeof(errbuf));
1005
0
        LOG4CXX_DECODE_CHAR(lsErrbuf, std::string(errbuf));
1006
0
        reason.append(lsErrbuf);
1007
0
      }
1008
0
      else
1009
0
      {
1010
0
        char errbuf[2000];
1011
0
        apr_strerror(rv, errbuf, sizeof(errbuf));
1012
0
        LOG4CXX_DECODE_CHAR(lsErrbuf, std::string(errbuf));
1013
0
        reason.append(lsErrbuf);
1014
0
      }
1015
0
      LogLog::error(LOG4CXX_STR("Error parsing file [")
1016
0
        + filename.getPath() + LOG4CXX_STR("]")
1017
0
        , RuntimeException(reason));
1018
0
      return spi::ConfigurationStatus::NotConfigured;
1019
0
    }
1020
0
    else
1021
0
    {
1022
0
      m_priv->parse(m_priv->doc->root);
1023
0
    }
1024
0
  }
1025
1026
0
  if (!m_priv->appenderAdded)
1027
0
  {
1028
0
    LogLog::warn(LOG4CXX_STR("[") + filename.getPath()
1029
0
      + LOG4CXX_STR("] did not add an ") + Appender::getStaticClass().getName()
1030
0
      + LOG4CXX_STR(" to a logger"));
1031
0
    return spi::ConfigurationStatus::NotConfigured;
1032
0
  }
1033
1034
0
  m_priv->repository->setConfigured(true);
1035
0
  return spi::ConfigurationStatus::Configured;
1036
0
}
1037
1038
// Read configuration options from \c filename.
1039
spi::ConfigurationStatus DOMConfigurator::configure(const File& filename)
1040
0
{
1041
0
  return DOMConfigurator().doConfigure(filename, LogManager::getLoggerRepository());
1042
0
}
1043
1044
#if LOG4CXX_ABI_VERSION <= 15
1045
spi::ConfigurationStatus DOMConfigurator::configure(const std::string& filename)
1046
0
{
1047
0
  File file(filename);
1048
0
  return DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository());
1049
0
}
1050
1051
#if LOG4CXX_WCHAR_T_API
1052
spi::ConfigurationStatus DOMConfigurator::configure(const std::wstring& filename)
1053
0
{
1054
0
  File file(filename);
1055
0
  return DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository());
1056
0
}
1057
#endif
1058
1059
#if LOG4CXX_UNICHAR_API || LOG4CXX_LOGCHAR_IS_UNICHAR
1060
spi::ConfigurationStatus DOMConfigurator::configure(const std::basic_string<UniChar>& filename)
1061
{
1062
  File file(filename);
1063
  return DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository());
1064
}
1065
#endif
1066
1067
#if LOG4CXX_CFSTRING_API
1068
spi::ConfigurationStatus DOMConfigurator::configure(const CFStringRef& filename)
1069
{
1070
  File file(filename);
1071
  return DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository());
1072
}
1073
#endif
1074
1075
1076
spi::ConfigurationStatus DOMConfigurator::configureAndWatch(const std::string& filename)
1077
0
{
1078
0
  return configureAndWatch(filename, FileWatchdog::DEFAULT_DELAY);
1079
0
}
1080
1081
#if LOG4CXX_WCHAR_T_API
1082
spi::ConfigurationStatus DOMConfigurator::configureAndWatch(const std::wstring& filename)
1083
0
{
1084
0
  return configureAndWatch(filename, FileWatchdog::DEFAULT_DELAY);
1085
0
}
1086
#endif
1087
1088
#if LOG4CXX_UNICHAR_API || LOG4CXX_LOGCHAR_IS_UNICHAR
1089
spi::ConfigurationStatus DOMConfigurator::configureAndWatch(const std::basic_string<UniChar>& filename)
1090
{
1091
  return configureAndWatch(filename, FileWatchdog::DEFAULT_DELAY);
1092
}
1093
#endif
1094
1095
#if LOG4CXX_CFSTRING_API
1096
spi::ConfigurationStatus DOMConfigurator::configureAndWatch(const CFStringRef& filename)
1097
{
1098
  return configureAndWatch(filename, FileWatchdog::DEFAULT_DELAY);
1099
}
1100
#endif
1101
1102
spi::ConfigurationStatus DOMConfigurator::configureAndWatch(const std::string& filename, long delay)
1103
0
{
1104
0
  return configureAndWatch(File(filename), delay);
1105
0
}
1106
#endif // LOG4CXX_ABI_VERSION <= 15
1107
1108
spi::ConfigurationStatus DOMConfigurator::configureAndWatch(const File& file, long delay)
1109
0
{
1110
0
  spi::ConfigurationStatus status = DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository());
1111
0
  XMLWatchdog::startWatching(file, delay);
1112
0
  return status;
1113
0
}
1114
1115
#if LOG4CXX_ABI_VERSION <= 15
1116
#if LOG4CXX_WCHAR_T_API
1117
spi::ConfigurationStatus DOMConfigurator::configureAndWatch(const std::wstring& filename, long delay)
1118
0
{
1119
0
  File file(filename);
1120
0
  spi::ConfigurationStatus status = DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository());
1121
0
  XMLWatchdog::startWatching(file, delay);
1122
0
  return status;
1123
0
}
1124
#endif
1125
1126
#if LOG4CXX_UNICHAR_API || LOG4CXX_LOGCHAR_IS_UNICHAR
1127
spi::ConfigurationStatus DOMConfigurator::configureAndWatch(const std::basic_string<UniChar>& filename, long delay)
1128
{
1129
  File file(filename);
1130
  spi::ConfigurationStatus status = DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository());
1131
  XMLWatchdog::startWatching(file, delay);
1132
  return status;
1133
}
1134
#endif
1135
1136
#if LOG4CXX_CFSTRING_API
1137
spi::ConfigurationStatus DOMConfigurator::configureAndWatch(const CFStringRef& filename, long delay)
1138
{
1139
  File file(filename);
1140
  spi::ConfigurationStatus status = DOMConfigurator().doConfigure(file, LogManager::getLoggerRepository());
1141
  XMLWatchdog::startWatching(file, delay);
1142
  return status;
1143
}
1144
#endif
1145
#endif // LOG4CXX_ABI_VERSION <= 15
1146
1147
void DOMConfigurator::DOMConfiguratorPrivate::parse(apr_xml_elem* element)
1148
0
{
1149
0
  std::string rootElementName(element->name);
1150
1151
0
  if (rootElementName != CONFIGURATION_TAG)
1152
0
  {
1153
0
    if (rootElementName == OLD_CONFIGURATION_TAG)
1154
0
    {
1155
      //LogLog::warn(LOG4CXX_STR("The <")+String(OLD_CONFIGURATION_TAG)+
1156
      // LOG4CXX_STR("> element has been deprecated."));
1157
      //LogLog::warn(LOG4CXX_STR("Use the <")+String(CONFIGURATION_TAG)+
1158
      // LOG4CXX_STR("> element instead."));
1159
0
    }
1160
0
    else
1161
0
    {
1162
0
      LogString msg(LOG4CXX_STR("Root element ["));
1163
0
      utf8Decoder->decode(element->name, MAX_ATTRIBUTE_NAME_LEN, msg);
1164
0
      msg += LOG4CXX_STR("] is not [");
1165
0
      utf8Decoder->decode(CONFIGURATION_TAG, MAX_ATTRIBUTE_NAME_LEN, msg);
1166
0
      msg += LOG4CXX_STR("]");
1167
0
      LogLog::error(msg);
1168
0
      return;
1169
0
    }
1170
0
  }
1171
1172
0
  LogString debugAttrib = subst(getAttribute(element, INTERNAL_DEBUG_ATTR));
1173
1174
  // if the log4j.dtd is not specified in the XML file, then the
1175
  // "debug" attribute is returned as the empty string.
1176
0
  if (!debugAttrib.empty() && debugAttrib != LOG4CXX_STR("NULL"))
1177
0
  {
1178
0
    LogLog::setInternalDebugging(OptionConverter::toBoolean(debugAttrib, true));
1179
0
  }
1180
1181
0
  LogString colorAttrib = subst(getAttribute(element, INTERNAL_COLOR_ATTR));
1182
0
  if (!colorAttrib.empty())
1183
0
  {
1184
0
    LogLog::setColorEnabled(OptionConverter::toBoolean(colorAttrib, true));
1185
0
  }
1186
1187
0
  LogString thresholdStr = subst(getAttribute(element, THRESHOLD_ATTR));
1188
1189
0
  if (!thresholdStr.empty() && thresholdStr != LOG4CXX_STR("NULL"))
1190
0
  {
1191
0
    this->repository->setThreshold(OptionConverter::toLevel(thresholdStr, Level::getAll()));
1192
0
    if (LogLog::isDebugEnabled())
1193
0
    {
1194
0
      LogLog::debug(LOG4CXX_STR("Repository threshold =[")
1195
0
        + this->repository->getThreshold()->toString()
1196
0
        + LOG4CXX_STR("]"));
1197
0
    }
1198
0
  }
1199
1200
0
  LogString threadSignalValue = subst(getAttribute(element, THREAD_CONFIG_ATTR));
1201
1202
0
  if ( !threadSignalValue.empty() && threadSignalValue != LOG4CXX_STR("NULL") )
1203
0
  {
1204
0
    if (LogLog::isDebugEnabled())
1205
0
    {
1206
0
      LogLog::debug(LOG4CXX_STR("ThreadUtility configuration =[") + threadSignalValue + LOG4CXX_STR("]"));
1207
0
    }
1208
0
    if ( threadSignalValue == LOG4CXX_STR("NoConfiguration") )
1209
0
    {
1210
0
      helpers::ThreadUtility::configure( ThreadConfigurationType::NoConfiguration );
1211
0
    }
1212
0
    else if ( threadSignalValue == LOG4CXX_STR("BlockSignalsOnly") )
1213
0
    {
1214
0
      helpers::ThreadUtility::configure( ThreadConfigurationType::BlockSignalsOnly );
1215
0
    }
1216
0
    else if ( threadSignalValue == LOG4CXX_STR("NameThreadOnly") )
1217
0
    {
1218
0
      helpers::ThreadUtility::configure( ThreadConfigurationType::NameThreadOnly );
1219
0
    }
1220
0
    else if ( threadSignalValue == LOG4CXX_STR("BlockSignalsAndNameThread") )
1221
0
    {
1222
0
      helpers::ThreadUtility::configure( ThreadConfigurationType::BlockSignalsAndNameThread );
1223
0
    }
1224
0
    else
1225
0
    {
1226
0
      LogLog::warn(LOG4CXX_STR("threadConfiguration value [") + threadSignalValue + LOG4CXX_STR("]") + LOG4CXX_STR(" is not valid"));
1227
0
    }
1228
0
  }
1229
1230
0
  apr_xml_elem* currentElement;
1231
1232
0
  for (currentElement = element->first_child;
1233
0
    currentElement;
1234
0
    currentElement = currentElement->next)
1235
0
  {
1236
0
    std::string tagName(currentElement->name);
1237
1238
0
    if (tagName == CATEGORY_FACTORY_TAG)
1239
0
    {
1240
0
      parseLoggerFactory(currentElement);
1241
0
    }
1242
0
  }
1243
1244
0
  for (currentElement = element->first_child;
1245
0
    currentElement;
1246
0
    currentElement = currentElement->next)
1247
0
  {
1248
0
    std::string tagName(currentElement->name);
1249
1250
0
    if (tagName == CATEGORY || tagName == LOGGER)
1251
0
    {
1252
0
      parseLogger(currentElement);
1253
0
    }
1254
0
    else if (tagName == ROOT_TAG)
1255
0
    {
1256
0
      parseRoot(currentElement);
1257
0
    }
1258
0
  }
1259
0
}
1260
1261
LogString DOMConfigurator::DOMConfiguratorPrivate::subst(const LogString& value)
1262
0
{
1263
0
  try
1264
0
  {
1265
0
    return OptionConverter::substVars(value, this->props);
1266
0
  }
1267
0
  catch (IllegalArgumentException& e)
1268
0
  {
1269
0
    LogLog::warn(LOG4CXX_STR("Could not substitute variables using [") + value + LOG4CXX_STR("]"), e);
1270
0
    return value;
1271
0
  }
1272
0
}
1273
1274
1275
LogString DOMConfigurator::DOMConfiguratorPrivate::getAttribute(apr_xml_elem* element, const std::string& attrName)
1276
0
{
1277
0
  LogString attrValue;
1278
1279
0
  for (apr_xml_attr* attr = element->attr;
1280
0
    attr;
1281
0
    attr = attr->next)
1282
0
  {
1283
0
    if (attrName == attr->name)
1284
0
    {
1285
0
      utf8Decoder->decode(attr->value, MAX_ATTRIBUTE_NAME_LEN, attrValue);
1286
0
    }
1287
0
  }
1288
1289
0
  return attrValue;
1290
0
}
1291
1292
#if LOG4CXX_ABI_VERSION <= 15
1293
AppenderPtr DOMConfigurator::findAppenderByName(LOG4CXX_NS::helpers::Pool& p,
1294
  LOG4CXX_NS::helpers::CharsetDecoderPtr& utf8Decoder,
1295
  apr_xml_elem* element,
1296
  apr_xml_doc* doc,
1297
  const LogString& appenderName,
1298
  AppenderMap& appenders)
1299
0
{ return AppenderPtr{}; }
1300
AppenderPtr DOMConfigurator::findAppenderByReference(
1301
  LOG4CXX_NS::helpers::Pool& p,
1302
  LOG4CXX_NS::helpers::CharsetDecoderPtr& utf8Decoder,
1303
  apr_xml_elem* appenderRef,
1304
  apr_xml_doc* doc,
1305
  AppenderMap& appenders)
1306
0
{ return AppenderPtr{}; }
1307
AppenderPtr DOMConfigurator::parseAppender(Pool& p,
1308
  LOG4CXX_NS::helpers::CharsetDecoderPtr& utf8Decoder,
1309
  apr_xml_elem* appenderElement,
1310
  apr_xml_doc* doc,
1311
  AppenderMap& appenders)
1312
0
{ return AppenderPtr{}; }
1313
void DOMConfigurator::parseErrorHandler(Pool& p,
1314
  LOG4CXX_NS::helpers::CharsetDecoderPtr& utf8Decoder,
1315
  apr_xml_elem* element,
1316
  AppenderPtr& appender,
1317
  apr_xml_doc* doc,
1318
  AppenderMap& appenders)
1319
0
{}
1320
void DOMConfigurator::parseFilters(Pool& p,
1321
  LOG4CXX_NS::helpers::CharsetDecoderPtr& utf8Decoder,
1322
  apr_xml_elem* element,
1323
  std::vector<LOG4CXX_NS::spi::FilterPtr>& filters)
1324
0
{}
1325
void DOMConfigurator::parseLogger(
1326
  LOG4CXX_NS::helpers::Pool& p,
1327
  LOG4CXX_NS::helpers::CharsetDecoderPtr& utf8Decoder,
1328
  apr_xml_elem* loggerElement,
1329
  apr_xml_doc* doc,
1330
  AppenderMap& appenders)
1331
0
{}
1332
void DOMConfigurator::parseLoggerFactory(
1333
  LOG4CXX_NS::helpers::Pool& p,
1334
  LOG4CXX_NS::helpers::CharsetDecoderPtr& utf8Decoder,
1335
  apr_xml_elem* factoryElement)
1336
0
{}
1337
void DOMConfigurator::parseRoot(
1338
  LOG4CXX_NS::helpers::Pool& p,
1339
  LOG4CXX_NS::helpers::CharsetDecoderPtr& utf8Decoder,
1340
  apr_xml_elem* rootElement,
1341
  apr_xml_doc* doc,
1342
  AppenderMap& appenders)
1343
0
{}
1344
void DOMConfigurator::parseChildrenOfLoggerElement(
1345
  LOG4CXX_NS::helpers::Pool& p,
1346
  LOG4CXX_NS::helpers::CharsetDecoderPtr& utf8Decoder,
1347
  apr_xml_elem* loggerElement, LoggerPtr logger, bool isRoot,
1348
  apr_xml_doc* doc,
1349
  AppenderMap& appenders)
1350
0
{}
1351
LayoutPtr DOMConfigurator::parseLayout (
1352
  LOG4CXX_NS::helpers::Pool& p,
1353
  LOG4CXX_NS::helpers::CharsetDecoderPtr& utf8Decoder,
1354
  apr_xml_elem* layout_element)
1355
0
{ return LayoutPtr{}; }
1356
ObjectPtr DOMConfigurator::parseTriggeringPolicy (
1357
  LOG4CXX_NS::helpers::Pool& p,
1358
  LOG4CXX_NS::helpers::CharsetDecoderPtr& utf8Decoder,
1359
  apr_xml_elem* policy_element)
1360
0
{ return ObjectPtr{}; }
1361
RollingPolicyPtr DOMConfigurator::parseRollingPolicy (
1362
  LOG4CXX_NS::helpers::Pool& p,
1363
  LOG4CXX_NS::helpers::CharsetDecoderPtr& utf8Decoder,
1364
  apr_xml_elem* policy_element)
1365
0
{ return RollingPolicyPtr{}; }
1366
void DOMConfigurator::parseLevel(
1367
  LOG4CXX_NS::helpers::Pool& p,
1368
  LOG4CXX_NS::helpers::CharsetDecoderPtr& utf8Decoder,
1369
  apr_xml_elem* element, LoggerPtr logger, bool isRoot)
1370
0
{}
1371
void DOMConfigurator::setParameter(LOG4CXX_NS::helpers::Pool& p,
1372
  LOG4CXX_NS::helpers::CharsetDecoderPtr& utf8Decoder,
1373
  apr_xml_elem* elem,
1374
  PropertySetter& propSetter)
1375
0
{}
1376
void DOMConfigurator::parse(
1377
  Pool& p,
1378
  LOG4CXX_NS::helpers::CharsetDecoderPtr& utf8Decoder,
1379
  apr_xml_elem* element,
1380
  apr_xml_doc* doc,
1381
  AppenderMap& appenders)
1382
0
{}
1383
LogString DOMConfigurator::getAttribute(
1384
  LOG4CXX_NS::helpers::CharsetDecoderPtr& utf8Decoder,
1385
  apr_xml_elem* element,
1386
  const std::string& attrName)
1387
0
{ return LogString{}; }
1388
LogString DOMConfigurator::subst(const LogString& value)
1389
0
{ return LogString{}; }
1390
#endif