Coverage Report

Created: 2025-07-01 06:08

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