This is an automated email from the ASF dual-hosted git repository.

swebb2066 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git


The following commit(s) were added to refs/heads/master by this push:
     new a4ebf8f8 Require the configuration file specify an appender to be 
valid (#533)
a4ebf8f8 is described below

commit a4ebf8f81f294bb85020db1fb6f067d1a3abe24f
Author: Stephen Webb <stephen.w...@ieee.org>
AuthorDate: Thu Sep 4 10:22:57 2025 +1000

    Require the configuration file specify an appender to be valid (#533)
    
    * Simplify DOMConfigurator
    
    * Require that a properties file has an appender to be valid
    
    * In the next ABI, require that a properties file adds an appender to be 
valid
    
    * Log a warning when the configuration file did not add an appender
    
    * Upgrade sonarcube version to avoid Github action command injection 
vulnerability
    
    * Improve the layout of a logged XML syntax error
---
 .github/workflows/sonarcloud.yml                   |   4 +-
 src/main/cpp/charsetdecoder.cpp                    |   7 ++
 src/main/cpp/defaultconfigurator.cpp               |   1 -
 src/main/cpp/domconfigurator.cpp                   | 137 +++++++++++----------
 src/main/cpp/propertyconfigurator.cpp              |  99 ++++++++++-----
 src/main/include/log4cxx/helpers/charsetdecoder.h  |  22 +++-
 src/main/include/log4cxx/propertyconfigurator.h    |   7 +-
 src/test/cpp/asyncappendertestcase.cpp             |   3 +-
 src/test/cpp/customlogger/xloggertestcase.cpp      |   3 +-
 src/test/cpp/db/odbcappendertestcase.cpp           |   3 +-
 src/test/cpp/fmttest.cpp                           |   9 +-
 src/test/cpp/helpers/messagebuffertest.cpp         |   3 +-
 src/test/cpp/hierarchythresholdtestcase.cpp        |  24 ++--
 src/test/cpp/l7dtestcase.cpp                       |   3 +-
 src/test/cpp/locationdisabledtest.cpp              |   3 +-
 src/test/cpp/locationtest.cpp                      |   3 +-
 src/test/cpp/ndctestcase.cpp                       |   3 +-
 src/test/cpp/net/smtpappendertestcase.cpp          |   6 +-
 src/test/cpp/net/xmlsocketappendertestcase.cpp     |   3 +-
 src/test/cpp/patternlayouttest.cpp                 |  45 ++++---
 src/test/cpp/propertyconfiguratortest.cpp          |   9 +-
 src/test/cpp/rolling/filterbasedrollingtest.cpp    |   5 +-
 src/test/cpp/varia/errorhandlertestcase.cpp        |   6 +-
 src/test/cpp/xml/customleveltestcase.cpp           |  10 +-
 src/test/cpp/xml/domtestcase.cpp                   |  51 ++++++--
 src/test/resources/input/xml/DOMTestCase5_bad0.xml |  22 ++++
 src/test/resources/input/xml/DOMTestCase5_bad1.xml |  33 +++++
 src/test/resources/input/xml/DOMTestCase5_bad2.xml |  33 +++++
 src/test/resources/input/xml/DOMTestCase5_bad3.xml |  22 ++++
 src/test/resources/input/xml/DOMTestCase5_good.xml |  33 +++++
 30 files changed, 449 insertions(+), 163 deletions(-)

diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml
index 526b6e41..85a304e6 100644
--- a/.github/workflows/sonarcloud.yml
+++ b/.github/workflows/sonarcloud.yml
@@ -55,7 +55,7 @@ jobs:
           sudo apt-get install -y libapr1-dev libaprutil1-dev
 
       - name: Install Build Wrapper
-        uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v4.2.1
+        uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v5.3.1
         env:
           SONAR_HOST_URL: ${{ env.SONAR_SERVER_URL }}
 
@@ -84,7 +84,7 @@ jobs:
             -o "$BaseDir/build/coverage.xml"
 
       - name: SonarQube Scan
-        uses: SonarSource/sonarqube-scan-action@v4.2.1
+        uses: SonarSource/sonarqube-scan-action@v5.3.1
         env:
           SONAR_TOKEN: ${{ secrets.SONARCLOUD_TOKEN }}
           SONAR_HOST_URL: ${{ env.SONAR_SERVER_URL }}
diff --git a/src/main/cpp/charsetdecoder.cpp b/src/main/cpp/charsetdecoder.cpp
index b985f475..ed79d440 100644
--- a/src/main/cpp/charsetdecoder.cpp
+++ b/src/main/cpp/charsetdecoder.cpp
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 #define NOMINMAX /* tell windows not to define min/max macros */
+#include <log4cxx/private/string_c11.h>
 #include <log4cxx/logstring.h>
 #include <log4cxx/helpers/charsetdecoder.h>
 #include <log4cxx/helpers/bytebuffer.h>
@@ -585,6 +586,12 @@ CharsetDecoderPtr CharsetDecoder::getDecoder(const 
LogString& charset)
 #endif
 }
 
+log4cxx_status_t CharsetDecoder::decode(const char* in, size_t maxByteCount, 
LogString& out)
+{
+       ByteBuffer buf((char*)in, strnlen_s(in, maxByteCount));
+       return decode(buf, out);
+}
+
 
 
 
diff --git a/src/main/cpp/defaultconfigurator.cpp 
b/src/main/cpp/defaultconfigurator.cpp
index fe19df32..c34f3d64 100644
--- a/src/main/cpp/defaultconfigurator.cpp
+++ b/src/main/cpp/defaultconfigurator.cpp
@@ -214,7 +214,6 @@ DefaultConfigurator::configureFromFile(const 
std::vector<LogString>& directories
                                        std::get<0>(result) = 
ConfigurationStatus::Configured;
                                        return result;
                                }
-                               LogLog::warn(LOG4CXX_STR("Unable to load: ") + 
candidate_str);
                        }
                }
        }
diff --git a/src/main/cpp/domconfigurator.cpp b/src/main/cpp/domconfigurator.cpp
index 6f78b3ac..7c940858 100644
--- a/src/main/cpp/domconfigurator.cpp
+++ b/src/main/cpp/domconfigurator.cpp
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <log4cxx/private/string_c11.h>
 #include <log4cxx/logstring.h>
 #include <log4cxx/xml/domconfigurator.h>
 #include <log4cxx/appender.h>
@@ -68,6 +67,7 @@ struct DOMConfigurator::DOMConfiguratorPrivate
        helpers::Properties props = Configurator::properties();
        spi::LoggerRepositoryPtr repository;
        spi::LoggerFactoryPtr loggerFactory;
+       bool appenderAdded{ false };
 };
 
 namespace LOG4CXX_NS
@@ -190,9 +190,19 @@ AppenderPtr DOMConfigurator::findAppenderByReference(
        apr_xml_doc* doc,
        AppenderMap& appenders)
 {
+       AppenderPtr appender;
        LogString appenderName(subst(getAttribute(utf8Decoder, appenderRef, 
REF_ATTR)));
+       if (appenderName.empty())
+       {
+               LogString msg(LOG4CXX_STR("["));
+               utf8Decoder->decode(appenderRef->name, MAX_ATTRIBUTE_NAME_LEN, 
msg);
+               msg += LOG4CXX_STR("] attribute [");
+               utf8Decoder->decode(REF_ATTR, MAX_ATTRIBUTE_NAME_LEN, msg);
+               msg += LOG4CXX_STR("] not found");
+               LogLog::warn(msg);
+               return appender;
+       }
        AppenderMap::const_iterator match = appenders.find(appenderName);
-       AppenderPtr appender;
 
        if (match != appenders.end())
        {
@@ -311,27 +321,23 @@ AppenderPtr DOMConfigurator::parseAppender(Pool& p,
                        }
                        else if (tagName == APPENDER_REF_TAG)
                        {
-                               LogString refName = 
subst(getAttribute(utf8Decoder, currentElement, REF_ATTR));
-
-                               if (!refName.empty() && 
appender->instanceof(AppenderAttachable::getStaticClass()))
+                               if 
(appender->instanceof(AppenderAttachable::getStaticClass()))
                                {
                                        AppenderAttachablePtr aa = 
LOG4CXX_NS::cast<AppenderAttachable>(appender);
-                                       if (LogLog::isDebugEnabled())
+                                       if (auto delegateAppender = 
findAppenderByReference(p, utf8Decoder, currentElement, doc, appenders))
                                        {
-                                               
LogLog::debug(LOG4CXX_STR("Attaching ") + Appender::getStaticClass().getName()
-                                                       + LOG4CXX_STR(" named 
[") + refName + LOG4CXX_STR("] to ") + Appender::getStaticClass().getName()
-                                                       + LOG4CXX_STR(" named 
[") + appender->getName() + LOG4CXX_STR("]"));
+                                               if (LogLog::isDebugEnabled())
+                                               {
+                                                       
LogLog::debug(LOG4CXX_STR("Attaching ") + Appender::getStaticClass().getName()
+                                                               + LOG4CXX_STR(" 
named [") + delegateAppender->getName() + LOG4CXX_STR("] to ") + 
Appender::getStaticClass().getName()
+                                                               + LOG4CXX_STR(" 
named [") + appender->getName() + LOG4CXX_STR("]"));
+                                               }
+                                               
aa->addAppender(delegateAppender);
                                        }
-                                       
aa->addAppender(findAppenderByReference(p, utf8Decoder, currentElement, doc, 
appenders));
-                               }
-                               else if (refName.empty())
-                               {
-                                       LogLog::error(LOG4CXX_STR("Can't add ") 
+ Appender::getStaticClass().getName() + LOG4CXX_STR(" with empty ref 
attribute"));
                                }
                                else
                                {
-                                       LogLog::error(LOG4CXX_STR("Requesting 
attachment of ") + Appender::getStaticClass().getName()
-                                               + LOG4CXX_STR(" named [") + 
refName + LOG4CXX_STR("] to ") + Appender::getStaticClass().getName()
+                                       LogLog::error(LOG4CXX_STR("Cannot 
attach to ") + Appender::getStaticClass().getName()
                                                + LOG4CXX_STR(" named [") + 
appender->getName() + LOG4CXX_STR("]")
                                                + LOG4CXX_STR(" which does not 
implement ") + AppenderAttachable::getStaticClass().getName());
                                }
@@ -386,7 +392,8 @@ void DOMConfigurator::parseErrorHandler(Pool& p,
                        }
                        else if (tagName == APPENDER_REF_TAG)
                        {
-                               
eh->setBackupAppender(findAppenderByReference(p, utf8Decoder, currentElement, 
doc, appenders));
+                               if (auto appender = findAppenderByReference(p, 
utf8Decoder, currentElement, doc, appenders))
+                                       eh->setBackupAppender(appender);
                        }
                        else if (tagName == LOGGER_REF)
                        {
@@ -461,7 +468,7 @@ void DOMConfigurator::parseLogger(
 
        if (LogLog::isDebugEnabled())
        {
-               LogLog::debug(LOG4CXX_STR("Retreiving an instance of ") + 
loggerName);
+               LogLog::debug(LOG4CXX_STR("Getting [") + loggerName + 
LOG4CXX_STR("]"));
        }
        LoggerPtr logger = m_priv->repository->getLogger(loggerName, 
m_priv->loggerFactory);
 
@@ -493,7 +500,12 @@ void DOMConfigurator::parseLoggerFactory(
 
        if (className.empty())
        {
-               LogLog::error(LOG4CXX_STR("Logger Factory tag class attribute 
not found."));
+               LogString msg(LOG4CXX_STR("["));
+               utf8Decoder->decode(factoryElement->name, 
MAX_ATTRIBUTE_NAME_LEN, msg);
+               msg += LOG4CXX_STR("] attribute [");
+               utf8Decoder->decode(CLASS_ATTR, MAX_ATTRIBUTE_NAME_LEN, msg);
+               msg += LOG4CXX_STR("] not found");
+               LogLog::warn(msg);
        }
        else
        {
@@ -558,25 +570,16 @@ void DOMConfigurator::parseChildrenOfLoggerElement(
 
                if (tagName == APPENDER_REF_TAG)
                {
-                       AppenderPtr appender = findAppenderByReference(p, 
utf8Decoder, currentElement, doc, appenders);
-                       LogString refName =  subst(getAttribute(utf8Decoder, 
currentElement, REF_ATTR));
-
-                       if (appender)
+                       if (auto appender = findAppenderByReference(p, 
utf8Decoder, currentElement, doc, appenders))
                        {
                                if (LogLog::isDebugEnabled())
                                {
                                        LogLog::debug(LOG4CXX_STR("Adding ") + 
Appender::getStaticClass().getName()
-                                               + LOG4CXX_STR(" named [") + 
refName + LOG4CXX_STR("]")
+                                               + LOG4CXX_STR(" named [") + 
appender->getName() + LOG4CXX_STR("]")
                                                + LOG4CXX_STR(" to logger [") + 
logger->getName() + LOG4CXX_STR("]"));
                                }
                                newappenders.push_back(appender);
                        }
-                       else
-                       {
-                               LogLog::debug(LOG4CXX_STR("Appender named [") + 
refName +
-                                       LOG4CXX_STR("] not found."));
-                       }
-
                }
                else if (tagName == LEVEL_TAG)
                {
@@ -594,8 +597,10 @@ void DOMConfigurator::parseChildrenOfLoggerElement(
        if (newappenders.empty())
                logger->removeAllAppenders();
        else
+       {
                logger->replaceAppenders(newappenders);
-
+               m_priv->appenderAdded = true;
+       }
        propSetter.activate(p);
 }
 
@@ -760,7 +765,7 @@ void DOMConfigurator::parseLevel(
        LogString levelStr(subst(getAttribute(utf8Decoder, element, 
VALUE_ATTR)));
        if (LogLog::isDebugEnabled())
        {
-               LogLog::debug(LOG4CXX_STR("Level value for ") + loggerName + 
LOG4CXX_STR(" is [") + levelStr + LOG4CXX_STR("]"));
+               LogLog::debug(LOG4CXX_STR("Setting [") + loggerName + 
LOG4CXX_STR("] level to [") + levelStr + LOG4CXX_STR("]"));
        }
 
        if (StringHelper::equalsIgnoreCase(levelStr, LOG4CXX_STR("INHERITED"), 
LOG4CXX_STR("inherited"))
@@ -815,7 +820,7 @@ void DOMConfigurator::parseLevel(
 
        if (LogLog::isDebugEnabled())
        {
-               LogLog::debug(loggerName + LOG4CXX_STR(" level set to ") +
+               LogLog::debug(LOG4CXX_STR("[") + loggerName + LOG4CXX_STR("] 
level is ") +
                        logger->getEffectiveLevel()->toString());
        }
 }
@@ -841,7 +846,6 @@ spi::ConfigurationStatus DOMConfigurator::doConfigure
        )
 {
        m_priv->repository = repository ? repository : 
LogManager::getLoggerRepository();
-       m_priv->repository->setConfigured(true);
 
 #if LOG4CXX_ABI_VERSION <= 15
        m_priv->loggerFactory = std::make_shared<DefaultLoggerFactory>();
@@ -856,15 +860,9 @@ spi::ConfigurationStatus DOMConfigurator::doConfigure
 
        if (rv != APR_SUCCESS)
        {
-               // There is not technically an exception thrown here, but this 
behavior matches
-               // what the PropertyConfigurator does
-               IOException io(rv);
-               LogString msg2(LOG4CXX_STR("Could not read configuration file 
["));
-               msg2.append(filename.getPath());
-               msg2.append(LOG4CXX_STR("]. "));
-               LOG4CXX_DECODE_CHAR(msg, io.what());
-               msg2.append(msg);
-               LogLog::error(msg2);
+               LogLog::error(LOG4CXX_STR("Could not open configuration file [")
+                       + filename.getPath() + LOG4CXX_STR("]")
+                       , IOException(rv));
                return spi::ConfigurationStatus::NotConfigured;
        }
        else
@@ -874,32 +872,32 @@ spi::ConfigurationStatus DOMConfigurator::doConfigure
 
                if (LogLog::isDebugEnabled())
                {
-                       LogString debugMsg = LOG4CXX_STR("Loading configuration 
file [")
-                                       + filename.getPath() + LOG4CXX_STR("]");
-                       LogLog::debug(debugMsg);
+                       LogLog::debug(LOG4CXX_STR("Loading configuration file 
[")
+                                       + filename.getPath() + 
LOG4CXX_STR("]"));
                }
 
                rv = apr_xml_parse_file(p.getAPRPool(), &parser, &doc, fd, 
2000);
 
                if (rv != APR_SUCCESS)
                {
-                       char errbuf[2000];
-                       char errbufXML[2000];
-                       LogString msg2(LOG4CXX_STR("Error parsing file ["));
-                       msg2.append(filename.getPath());
-                       msg2.append(LOG4CXX_STR("], "));
-                       apr_strerror(rv, errbuf, sizeof(errbuf));
-                       LOG4CXX_DECODE_CHAR(lerrbuf, std::string(errbuf));
-                       msg2.append(lerrbuf);
-
+                       LogString reason;
                        if (parser)
                        {
-                               apr_xml_parser_geterror(parser, errbufXML, 
sizeof(errbufXML));
-                               LOG4CXX_DECODE_CHAR(lerrbufXML, 
std::string(errbufXML));
-                               msg2.append(lerrbufXML);
+                               char errbuf[2000];
+                               apr_xml_parser_geterror(parser, errbuf, 
sizeof(errbuf));
+                               LOG4CXX_DECODE_CHAR(lsErrbuf, 
std::string(errbuf));
+                               reason.append(lsErrbuf);
                        }
-
-                       LogLog::error(msg2);
+                       else
+                       {
+                               char errbuf[2000];
+                               apr_strerror(rv, errbuf, sizeof(errbuf));
+                               LOG4CXX_DECODE_CHAR(lsErrbuf, 
std::string(errbuf));
+                               reason.append(lsErrbuf);
+                       }
+                       LogLog::error(LOG4CXX_STR("Error parsing file [")
+                               + filename.getPath() + LOG4CXX_STR("]")
+                               , RuntimeException(reason));
                        return spi::ConfigurationStatus::NotConfigured;
                }
                else
@@ -910,6 +908,15 @@ spi::ConfigurationStatus DOMConfigurator::doConfigure
                }
        }
 
+       if (!m_priv->appenderAdded)
+       {
+               LogLog::warn(LOG4CXX_STR("[") + filename.getPath()
+                       + LOG4CXX_STR("] did not add an ") + 
Appender::getStaticClass().getName()
+                       + LOG4CXX_STR(" to a logger"));
+               return spi::ConfigurationStatus::NotConfigured;
+       }
+
+       m_priv->repository->setConfigured(true);
        return spi::ConfigurationStatus::Configured;
 }
 
@@ -1042,7 +1049,12 @@ void DOMConfigurator::parse(
                }
                else
                {
-                       LogLog::error(LOG4CXX_STR("DOM element is - not a 
<configuration> element."));
+                       LogString msg(LOG4CXX_STR("Root element ["));
+                       utf8Decoder->decode(element->name, 
MAX_ATTRIBUTE_NAME_LEN, msg);
+                       msg += LOG4CXX_STR("] is not [");
+                       utf8Decoder->decode(CONFIGURATION_TAG, 
MAX_ATTRIBUTE_NAME_LEN, msg);
+                       msg += LOG4CXX_STR("]");
+                       LogLog::error(msg);
                        return;
                }
        }
@@ -1163,8 +1175,7 @@ LogString DOMConfigurator::getAttribute(
        {
                if (attrName == attr->name)
                {
-                       ByteBuffer buf((char*) attr->value, 
strnlen_s(attr->value, MAX_ATTRIBUTE_NAME_LEN));
-                       utf8Decoder->decode(buf, attrValue);
+                       utf8Decoder->decode(attr->value, 
MAX_ATTRIBUTE_NAME_LEN, attrValue);
                }
        }
 
diff --git a/src/main/cpp/propertyconfigurator.cpp 
b/src/main/cpp/propertyconfigurator.cpp
index 6dd2036b..b1c1d939 100644
--- a/src/main/cpp/propertyconfigurator.cpp
+++ b/src/main/cpp/propertyconfigurator.cpp
@@ -86,19 +86,44 @@ class PropertyWatchdog  : public FileWatchdog
 
 IMPLEMENT_LOG4CXX_OBJECT(PropertyConfigurator)
 
+using RegistryType = std::map<LogString, AppenderPtr>;
+using RegistryPtr = std::unique_ptr<RegistryType>;
+
+#if 15 < LOG4CXX_ABI_VERSION
+struct PropertyConfigurator::PrivateData
+{
+
+       /**
+       Used internally to keep track of configured appenders.
+       */
+       RegistryPtr registry{ std::make_unique<RegistryType>() };
+
+       /**
+       Used to create new instances of logger
+       */
+       spi::LoggerFactoryPtr loggerFactory{ std::make_shared<LoggerFactory>() 
};
+
+       /**
+       True if an appender was added to a logger
+       */
+       bool appenderAdded{ false };
+};
+PropertyConfigurator::PropertyConfigurator()
+       : m_priv{ std::make_unique<PrivateData>() }
+#else
+#define m_priv this
 PropertyConfigurator::PropertyConfigurator()
        : registry(new std::map<LogString, AppenderPtr>())
-#if LOG4CXX_ABI_VERSION <= 15
        , loggerFactory(new DefaultLoggerFactory())
-#else
-       , loggerFactory(new LoggerFactory())
 #endif
 {
 }
 
 PropertyConfigurator::~PropertyConfigurator()
 {
+#if LOG4CXX_ABI_VERSION <= 15
        delete registry;
+#endif
 }
 
 spi::ConfigurationStatus PropertyConfigurator::doConfigure
@@ -110,11 +135,13 @@ spi::ConfigurationStatus PropertyConfigurator::doConfigure
 #endif
        )
 {
-       auto hierarchy = repository ? repository : 
LogManager::getLoggerRepository();
-       hierarchy->setConfigured(true);
-
+       auto result = spi::ConfigurationStatus::NotConfigured;
+       if (LogLog::isDebugEnabled())
+       {
+               LogLog::debug(LOG4CXX_STR("Loading configuration file [")
+                       + configFileName.getPath() + LOG4CXX_STR("]"));
+       }
        Properties props = Configurator::properties();
-
        try
        {
                InputStreamPtr inputStream = InputStreamPtr( new 
FileInputStream(configFileName) );
@@ -122,29 +149,32 @@ spi::ConfigurationStatus PropertyConfigurator::doConfigure
        }
        catch (const IOException& ex)
        {
-               LOG4CXX_DECODE_CHAR(lsMsg, ex.what());
-               LogLog::error(((LogString) LOG4CXX_STR("Could not read 
configuration file ["))
-                       + configFileName.getPath() + LOG4CXX_STR("]: ") + 
lsMsg);
-               return spi::ConfigurationStatus::NotConfigured;
+               LogLog::error(LOG4CXX_STR("Could not load properties from [")
+                       + configFileName.getPath() + LOG4CXX_STR("]"), ex);
+               return result;
        }
 
        try
        {
-               if (LogLog::isDebugEnabled())
+               result = doConfigure(props, repository ? repository : 
LogManager::getLoggerRepository());
+#if LOG4CXX_ABI_VERSION <= 15
+               if (m_priv->registry->empty())
+#else
+               if (!m_priv->appenderAdded)
+#endif
                {
-                       LogString debugMsg = LOG4CXX_STR("Loading configuration 
file [")
-                                       + configFileName.getPath() + 
LOG4CXX_STR("]");
-                       LogLog::debug(debugMsg);
+                       LogLog::warn(LOG4CXX_STR("[") + configFileName.getPath()
+                               + LOG4CXX_STR("] did not add an ") + 
Appender::getStaticClass().getName()
+                               + LOG4CXX_STR(" to a logger"));
                }
-               return doConfigure(props, hierarchy);
        }
        catch (const std::exception& ex)
        {
-               LogLog::error(((LogString) LOG4CXX_STR("Could not parse 
configuration file ["))
+               LogLog::error(LOG4CXX_STR("Exception thrown processing [")
                        + configFileName.getPath() + LOG4CXX_STR("]: "), ex);
        }
 
-       return spi::ConfigurationStatus::NotConfigured;
+       return result;
 }
 
 spi::ConfigurationStatus PropertyConfigurator::configure(const File& 
configFilename)
@@ -175,8 +205,6 @@ spi::ConfigurationStatus 
PropertyConfigurator::configureAndWatch(
 spi::ConfigurationStatus 
PropertyConfigurator::doConfigure(helpers::Properties& properties,
        spi::LoggerRepositoryPtr hierarchy)
 {
-       hierarchy->setConfigured(true);
-
        LogString 
debugValue(properties.getProperty(LOG4CXX_STR("log4j.debug")));
        if (!debugValue.empty())
        {
@@ -225,14 +253,18 @@ spi::ConfigurationStatus 
PropertyConfigurator::doConfigure(helpers::Properties&
        configureRootLogger(properties, hierarchy);
        configureLoggerFactory(properties);
        parseCatsAndRenderers(properties, hierarchy);
-
        LogLog::debug(LOG4CXX_STR("Finished configuring."));
+#if LOG4CXX_ABI_VERSION <= 15
+       auto result = m_priv->registry->empty()
+#else
+       auto result = !m_priv->appenderAdded
+#endif
+               ? spi::ConfigurationStatus::NotConfigured
+               : spi::ConfigurationStatus::Configured;
 
-       // We don't want to hold references to appenders preventing their
-       // destruction.
-       registry->clear();
-
-       return spi::ConfigurationStatus::Configured;
+       if (spi::ConfigurationStatus::Configured == result)
+               hierarchy->setConfigured(true);
+       return result;
 }
 
 void PropertyConfigurator::configureLoggerFactory(helpers::Properties& props)
@@ -252,9 +284,9 @@ void 
PropertyConfigurator::configureLoggerFactory(helpers::Properties& props)
 #endif
                        );
 
-               loggerFactory = LOG4CXX_NS::cast<LoggerFactory>( instance );
+               m_priv->loggerFactory = LOG4CXX_NS::cast<LoggerFactory>( 
instance );
                Pool p;
-               PropertySetter::setProperties(loggerFactory, props, 
LOG4CXX_STR("log4j.factory."), p);
+               PropertySetter::setProperties(m_priv->loggerFactory, props, 
LOG4CXX_STR("log4j.factory."), p);
        }
 }
 
@@ -296,7 +328,7 @@ void 
PropertyConfigurator::parseCatsAndRenderers(helpers::Properties& props,
                                ).length();
                        auto loggerName = key.substr(prefixLength);
                        auto value = OptionConverter::findAndSubst(key, props);
-                       auto logger = hierarchy->getLogger(loggerName, 
loggerFactory);
+                       auto logger = hierarchy->getLogger(loggerName, 
m_priv->loggerFactory);
                        auto additivity = parseAdditivityForLogger(props, 
logger, loggerName);
                        parseLogger(props, logger, key, loggerName, value, 
additivity);
 
@@ -406,7 +438,10 @@ void PropertyConfigurator::parseLogger(
                        newappenders.push_back(appender);
                }
        }
-
+#if 15 < LOG4CXX_ABI_VERSION
+       if (!newappenders.empty())
+               m_priv->appenderAdded = true;
+#endif
        logger->reconfigure( newappenders, additivity );
 }
 
@@ -545,10 +580,10 @@ AppenderPtr PropertyConfigurator::parseAppender(
 
 void PropertyConfigurator::registryPut(const AppenderPtr& appender)
 {
-       (*registry)[appender->getName()] = appender;
+       (*m_priv->registry)[appender->getName()] = appender;
 }
 
 AppenderPtr PropertyConfigurator::registryGet(const LogString& name)
 {
-       return (*registry)[name];
+       return (*m_priv->registry)[name];
 }
diff --git a/src/main/include/log4cxx/helpers/charsetdecoder.h 
b/src/main/include/log4cxx/helpers/charsetdecoder.h
index 3c276ac8..d801e70b 100644
--- a/src/main/include/log4cxx/helpers/charsetdecoder.h
+++ b/src/main/include/log4cxx/helpers/charsetdecoder.h
@@ -77,14 +77,24 @@ class LOG4CXX_EXPORT CharsetDecoder : public Object
 
 
                /**
-                *  Decodes as many bytes as possible from the given
-                *   input buffer, writing the results to the given output 
string.
-                *  @param in input buffer.
-                *  @param out output string.
+                *  Decodes as many bytes as possible from \c in,
+                *  appending the result onto \c out.
+                *  @param in a null terminated string.
+                *  @param out the string onto which characters are appended.
                 *  @return APR_SUCCESS if not encoding errors were found.
                 */
-               virtual log4cxx_status_t decode(ByteBuffer& in,
-                       LogString& out) = 0;
+               virtual log4cxx_status_t decode(ByteBuffer& in, LogString& out) 
= 0;
+
+
+               /**
+                *  Decodes up to \c maxByteCount bytes from \c in,
+                *  appending the result onto \c out.
+                *  @param in a null terminated string.
+                *  @param maxByteCount the limit on the size of \c in.
+                *  @param out the string onto which characters are appended.
+                *  @return APR_SUCCESS if not encoding errors were found.
+                */
+               log4cxx_status_t decode(const char* in, size_t maxByteCount, 
LogString& out);
 
                /**
                 *  Determins if status value indicates an invalid byte 
sequence.
diff --git a/src/main/include/log4cxx/propertyconfigurator.h 
b/src/main/include/log4cxx/propertyconfigurator.h
index b5e5872b..eac2aba4 100644
--- a/src/main/include/log4cxx/propertyconfigurator.h
+++ b/src/main/include/log4cxx/propertyconfigurator.h
@@ -249,6 +249,11 @@ class LOG4CXX_EXPORT PropertyConfigurator :
        virtual public spi::Configurator,
        virtual public helpers::Object
 {
+#if 15 < LOG4CXX_ABI_VERSION
+       private:
+               struct PrivateData;
+               LOG4CXX_DECLARE_PRIVATE_MEMBER_PTR(PrivateData, m_priv)
+#else
        protected:
 
                /**
@@ -260,7 +265,7 @@ class LOG4CXX_EXPORT PropertyConfigurator :
                Used to create new instances of logger
                */
                LOG4CXX_DECLARE_PRIVATE_MEMBER(spi::LoggerFactoryPtr, 
loggerFactory)
-
+#endif
        public:
                DECLARE_LOG4CXX_OBJECT(PropertyConfigurator)
                BEGIN_LOG4CXX_CAST_MAP()
diff --git a/src/test/cpp/asyncappendertestcase.cpp 
b/src/test/cpp/asyncappendertestcase.cpp
index ea6781fc..206efc1f 100644
--- a/src/test/cpp/asyncappendertestcase.cpp
+++ b/src/test/cpp/asyncappendertestcase.cpp
@@ -360,7 +360,8 @@ class AsyncAppenderTestCase : public 
AppenderSkeletonTestCase
 #if LOG4CXX_HAS_DOMCONFIGURATOR
                void testConfiguration()
                {
-                       
log4cxx::xml::DOMConfigurator::configure("input/xml/asyncAppender1.xml");
+                       auto status = 
xml::DOMConfigurator::configure("input/xml/asyncAppender1.xml");
+                       LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                        AsyncAppenderPtr asyncAppender = 
log4cxx::cast<AsyncAppender>(Logger::getRootLogger()->getAppender(LOG4CXX_STR("ASYNC")));
                        LOGUNIT_ASSERT(!(asyncAppender == 0));
                        LOGUNIT_ASSERT_EQUAL(100, 
asyncAppender->getBufferSize());
diff --git a/src/test/cpp/customlogger/xloggertestcase.cpp 
b/src/test/cpp/customlogger/xloggertestcase.cpp
index 74302e5c..7a4ef690 100644
--- a/src/test/cpp/customlogger/xloggertestcase.cpp
+++ b/src/test/cpp/customlogger/xloggertestcase.cpp
@@ -74,7 +74,8 @@ public:
                std::string fn("input/xml/customLogger");
                fn.append(number);
                fn.append(".xml");
-               DOMConfigurator::configure(fn);
+               auto status = DOMConfigurator::configure(fn);
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
 
                int i = 0;
                LOG4CXX_LOG(logger, log4cxx::XLevel::getTrace(), "Message " << 
i);
diff --git a/src/test/cpp/db/odbcappendertestcase.cpp 
b/src/test/cpp/db/odbcappendertestcase.cpp
index ca568aed..2e7dec99 100644
--- a/src/test/cpp/db/odbcappendertestcase.cpp
+++ b/src/test/cpp/db/odbcappendertestcase.cpp
@@ -84,7 +84,8 @@ class ODBCAppenderTestCase : public AppenderSkeletonTestCase
 //
                void testConnectUsingDSN()
                {
-                       
xml::DOMConfigurator::configure("input/xml/odbcAppenderDSN-Log4cxxTest.xml");
+                       auto status = 
xml::DOMConfigurator::configure("input/xml/odbcAppenderDSN-Log4cxxTest.xml");
+                       LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                        auto odbc = Logger::getLogger("DB.UnitTest");
                        for (int i = 0; i < 100; ++i)
                        {
diff --git a/src/test/cpp/fmttest.cpp b/src/test/cpp/fmttest.cpp
index 3827f69c..c7674d70 100644
--- a/src/test/cpp/fmttest.cpp
+++ b/src/test/cpp/fmttest.cpp
@@ -85,21 +85,24 @@ public:
 
        void test1()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/fmtLayout1.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/fmtLayout1.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                LOGUNIT_ASSERT(Compare::compare(TEMP, 
LOG4CXX_FILE("witness/patternLayout.1")));
        }
 
        void test1_expanded()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/fmtLayout1_expanded.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/fmtLayout1_expanded.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                LOGUNIT_ASSERT(Compare::compare(TEMP, 
LOG4CXX_FILE("witness/patternLayout.1")));
        }
 
        void test10()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/fmtLayout10.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/fmtLayout10.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
 
                ControlFilter filter1;
diff --git a/src/test/cpp/helpers/messagebuffertest.cpp 
b/src/test/cpp/helpers/messagebuffertest.cpp
index f953ea30..e257528d 100644
--- a/src/test/cpp/helpers/messagebuffertest.cpp
+++ b/src/test/cpp/helpers/messagebuffertest.cpp
@@ -148,7 +148,8 @@ public:
                root = Logger::getRootLogger();
                logger = 
Logger::getLogger(LOG4CXX_STR("java.org.apache.log4j.PatternLayoutTest"));
 
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/messagebuffer1.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/messagebuffer1.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
 
                int num = 220;
                LOG4CXX_INFO(logger, "number in hex: " << std::hex << num);
diff --git a/src/test/cpp/hierarchythresholdtestcase.cpp 
b/src/test/cpp/hierarchythresholdtestcase.cpp
index de836f09..65383cd8 100644
--- a/src/test/cpp/hierarchythresholdtestcase.cpp
+++ b/src/test/cpp/hierarchythresholdtestcase.cpp
@@ -59,56 +59,64 @@ public:
 
        void test1()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/hierarchyThreshold1.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/hierarchyThreshold1.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                LOGUNIT_ASSERT(Compare::compare(TEMP, 
LOG4CXX_FILE("witness/hierarchyThreshold.1")));
        }
 
        void test2()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/hierarchyThreshold2.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/hierarchyThreshold2.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                LOGUNIT_ASSERT(Compare::compare(TEMP, 
LOG4CXX_FILE("witness/hierarchyThreshold.2")));
        }
 
        void test3()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/hierarchyThreshold3.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/hierarchyThreshold3.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                LOGUNIT_ASSERT(Compare::compare(TEMP, 
LOG4CXX_FILE("witness/hierarchyThreshold.3")));
        }
 
        void test4()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/hierarchyThreshold4.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/hierarchyThreshold4.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                LOGUNIT_ASSERT(Compare::compare(TEMP, 
LOG4CXX_FILE("witness/hierarchyThreshold.4")));
        }
 
        void test5()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/hierarchyThreshold5.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/hierarchyThreshold5.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                LOGUNIT_ASSERT(Compare::compare(TEMP, 
LOG4CXX_FILE("witness/hierarchyThreshold.5")));
        }
 
        void test6()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/hierarchyThreshold6.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/hierarchyThreshold6.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                LOGUNIT_ASSERT(Compare::compare(TEMP, 
LOG4CXX_FILE("witness/hierarchyThreshold.6")));
        }
 
        void test7()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/hierarchyThreshold7.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/hierarchyThreshold7.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                LOGUNIT_ASSERT(Compare::compare(TEMP, 
LOG4CXX_FILE("witness/hierarchyThreshold.7")));
        }
 
        void test8()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/hierarchyThreshold8.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/hierarchyThreshold8.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                LOGUNIT_ASSERT(Compare::compare(TEMP, 
LOG4CXX_FILE("witness/hierarchyThreshold.8")));
        }
diff --git a/src/test/cpp/l7dtestcase.cpp b/src/test/cpp/l7dtestcase.cpp
index 7c70b74a..36b5eea8 100644
--- a/src/test/cpp/l7dtestcase.cpp
+++ b/src/test/cpp/l7dtestcase.cpp
@@ -77,7 +77,8 @@ public:
 
        void test1()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/l7d1.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/l7d1.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
 
                log4cxx::helpers::Pool pool;
 
diff --git a/src/test/cpp/locationdisabledtest.cpp 
b/src/test/cpp/locationdisabledtest.cpp
index fa682f61..976e4d81 100644
--- a/src/test/cpp/locationdisabledtest.cpp
+++ b/src/test/cpp/locationdisabledtest.cpp
@@ -48,7 +48,8 @@ public:
 
        void test1()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/locationdisabled.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/locationdisabled.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                
LOGUNIT_ASSERT(Compare::compare(LOG4CXX_STR("output/location-disabled-test"), 
LOG4CXX_FILE("witness/location1-disabled")));
        }
diff --git a/src/test/cpp/locationtest.cpp b/src/test/cpp/locationtest.cpp
index aa98a63d..701e1896 100644
--- a/src/test/cpp/locationtest.cpp
+++ b/src/test/cpp/locationtest.cpp
@@ -48,7 +48,8 @@ public:
 
        void test1()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/location1.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/location1.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                
LOGUNIT_ASSERT(Compare::compare(LOG4CXX_STR("output/location-good-test"), 
LOG4CXX_FILE("witness/location1-good")));
        }
diff --git a/src/test/cpp/ndctestcase.cpp b/src/test/cpp/ndctestcase.cpp
index 75e55371..383f7a71 100644
--- a/src/test/cpp/ndctestcase.cpp
+++ b/src/test/cpp/ndctestcase.cpp
@@ -68,7 +68,8 @@ public:
 
        void test1()
        {
-               
PropertyConfigurator::configure(File("input/ndc/NDC1.properties"));
+               auto status = 
PropertyConfigurator::configure(File("input/ndc/NDC1.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                LOGUNIT_ASSERT(Compare::compare(TEMP, 
File("witness/ndc/NDC.1")));
        }
diff --git a/src/test/cpp/net/smtpappendertestcase.cpp 
b/src/test/cpp/net/smtpappendertestcase.cpp
index 213cf4f3..d3036239 100644
--- a/src/test/cpp/net/smtpappendertestcase.cpp
+++ b/src/test/cpp/net/smtpappendertestcase.cpp
@@ -106,7 +106,8 @@ class SMTPAppenderTestCase : public AppenderSkeletonTestCase
                 */
                void testTrigger()
                {
-                       
xml::DOMConfigurator::configure("input/xml/smtpAppender1.xml");
+                       auto status = 
xml::DOMConfigurator::configure("input/xml/smtpAppender1.xml");
+                       LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                        auto appender = 
log4cxx::cast<SMTPAppender>(Logger::getRootLogger()->getAppender(LOG4CXX_STR("A1")));
                        LOGUNIT_ASSERT(appender);
                        auto evaluator = appender->getEvaluator();
@@ -135,7 +136,8 @@ class SMTPAppenderTestCase : public AppenderSkeletonTestCase
 
                void testValid()
                {
-                       
xml::DOMConfigurator::configure("input/xml/smtpAppenderValid.xml");
+                       auto status = 
xml::DOMConfigurator::configure("input/xml/smtpAppenderValid.xml");
+                       LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                        auto root = Logger::getRootLogger();
                        LOG4CXX_INFO(root, "Hello, World.\n\nThis paragraph 
should be preceeded by a blank line.");
 
diff --git a/src/test/cpp/net/xmlsocketappendertestcase.cpp 
b/src/test/cpp/net/xmlsocketappendertestcase.cpp
index cfd715b8..95b450e7 100644
--- a/src/test/cpp/net/xmlsocketappendertestcase.cpp
+++ b/src/test/cpp/net/xmlsocketappendertestcase.cpp
@@ -48,7 +48,8 @@ class XMLSocketAppenderTestCase : public 
AppenderSkeletonTestCase
 
                void test_fluent_bit()
                {
-                       
xml::DOMConfigurator::configure("input/xml/fluent-bit.xml");
+                       auto status = 
xml::DOMConfigurator::configure("input/xml/fluent-bit.xml");
+                       LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                        auto log = Logger::getRootLogger();
                        for (int i = 0; i < 100; ++i)
                        {
diff --git a/src/test/cpp/patternlayouttest.cpp 
b/src/test/cpp/patternlayouttest.cpp
index a5723bbf..c142ae04 100644
--- a/src/test/cpp/patternlayouttest.cpp
+++ b/src/test/cpp/patternlayouttest.cpp
@@ -105,14 +105,16 @@ public:
 
        void test1()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout1.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout1.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                LOGUNIT_ASSERT(Compare::compare(TEMP, 
LOG4CXX_FILE("witness/patternLayout.1")));
        }
 
        void test2()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout2.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout2.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
 
                ControlFilter filter1;
@@ -140,7 +142,8 @@ public:
 
        void test3()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout3.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout3.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
 
                ControlFilter filter1;
@@ -170,7 +173,8 @@ public:
        // 06 avr. 2002 18:30:58,937 [12345] DEBUG atternLayoutTest - Message 0
        void test4()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout4.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout4.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
 
                ControlFilter filter1;
@@ -198,7 +202,8 @@ public:
 
        void test5()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout5.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout5.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
 
                ControlFilter filter1;
@@ -226,7 +231,8 @@ public:
 
        void test6()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout6.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout6.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
 
                ControlFilter filter1;
@@ -254,7 +260,8 @@ public:
 
        void test7()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout7.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout7.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
 
                ControlFilter filter1;
@@ -282,7 +289,8 @@ public:
 
        void test8()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout8.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout8.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
 
 
@@ -313,7 +321,8 @@ public:
 
        void test9()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout9.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout9.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
 
                ControlFilter filter1;
@@ -339,7 +348,8 @@ public:
 
        void test10()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout10.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout10.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
 
                ControlFilter filter1;
@@ -371,7 +381,8 @@ public:
 
        void test11()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout11.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout11.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
 
                ControlFilter filter1;
@@ -397,7 +408,8 @@ public:
 
        void test12()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout12.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout12.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
 
                ControlFilter filter1;
@@ -427,21 +439,24 @@ public:
 
        void test13()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout13.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout13.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                LOGUNIT_ASSERT(Compare::compare(TEMP, 
LOG4CXX_FILE("witness/patternLayout.13")));
        }
 
        void test14()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout14.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout14.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                LOGUNIT_ASSERT(Compare::compare(TEMP, 
LOG4CXX_FILE("witness/patternLayout.14")));
        }
 
        void testMDC1()
        {
-               
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout.mdc.1.properties"));
+               auto status = 
PropertyConfigurator::configure(LOG4CXX_FILE("input/patternLayout.mdc.1.properties"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                MDC::put(LOG4CXX_TEST_STR("key1"), LOG4CXX_TEST_STR("va11"));
                MDC::put(LOG4CXX_TEST_STR("key2"), LOG4CXX_TEST_STR("va12"));
                logger->debug(LOG4CXX_TEST_STR("Hello World"));
diff --git a/src/test/cpp/propertyconfiguratortest.cpp 
b/src/test/cpp/propertyconfiguratortest.cpp
index b051614e..2d57ee67 100644
--- a/src/test/cpp/propertyconfiguratortest.cpp
+++ b/src/test/cpp/propertyconfiguratortest.cpp
@@ -41,7 +41,8 @@ public:
                
props.put(LOG4CXX_STR("log4j.logger.org.apache.log4j.PropertyConfiguratorTest"),
 LOG4CXX_STR("inherited,VECTOR2"));
                props.put(LOG4CXX_STR("log4j.appender.VECTOR1"), 
LOG4CXX_STR("org.apache.log4j.VectorAppender"));
                props.put(LOG4CXX_STR("log4j.appender.VECTOR2"), 
LOG4CXX_STR("org.apache.log4j.VectorAppender"));
-               PropertyConfigurator::configure(props);
+               auto status = PropertyConfigurator::configure(props);
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                LoggerPtr logger = 
Logger::getLogger("org.apache.log4j.PropertyConfiguratorTest");
                LOGUNIT_ASSERT_EQUAL((int) Level::DEBUG_INT,
                        logger->getEffectiveLevel()->toInt());
@@ -58,7 +59,8 @@ public:
                
props.put(LOG4CXX_STR("log4j.logger.org.apache.log4j.PropertyConfiguratorTest"),
 LOG4CXX_STR("NuLL,VECTOR2"));
                props.put(LOG4CXX_STR("log4j.appender.VECTOR1"), 
LOG4CXX_STR("org.apache.log4j.VectorAppender"));
                props.put(LOG4CXX_STR("log4j.appender.VECTOR2"), 
LOG4CXX_STR("org.apache.log4j.VectorAppender"));
-               PropertyConfigurator::configure(props);
+               auto status = PropertyConfigurator::configure(props);
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                LoggerPtr logger = 
Logger::getLogger("org.apache.log4j.PropertyConfiguratorTest");
                LOGUNIT_ASSERT_EQUAL((int) Level::DEBUG_INT,
                        logger->getEffectiveLevel()->toInt());
@@ -74,7 +76,8 @@ public:
                props.put(LOG4CXX_STR("log4j.rootLogger"), 
LOG4CXX_STR("ALL,VECTOR1"));
                props.put(LOG4CXX_STR("log4j.appender.VECTOR1"), 
LOG4CXX_STR("org.apache.log4j.VectorAppender"));
                props.put(LOG4CXX_STR("log4j.appender.VECTOR1.threshold"), 
LOG4CXX_STR("WARN"));
-               PropertyConfigurator::configure(props);
+               auto status = PropertyConfigurator::configure(props);
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                LoggerPtr root(Logger::getRootLogger());
                VectorAppenderPtr appender = 
log4cxx::cast<VectorAppender>(root->getAppender(LOG4CXX_STR("VECTOR1")));
                LOGUNIT_ASSERT_EQUAL((int) Level::WARN_INT, 
appender->getThreshold()->toInt());
diff --git a/src/test/cpp/rolling/filterbasedrollingtest.cpp 
b/src/test/cpp/rolling/filterbasedrollingtest.cpp
index 43448125..bbff3fdc 100644
--- a/src/test/cpp/rolling/filterbasedrollingtest.cpp
+++ b/src/test/cpp/rolling/filterbasedrollingtest.cpp
@@ -60,9 +60,8 @@ public:
        void test1()
        {
 #if LOG4CXX_HAS_DOMCONFIGURATOR
-               log4cxx::xml::DOMConfigurator::configure(
-                       "./input/rolling/filter1.xml" /*, 
LogManager::getLoggerRepository() */);
-
+               auto status = 
xml::DOMConfigurator::configure("./input/rolling/filter1.xml");
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common(LOG4CXX_STR("output/filterBased-test1"));
 #endif
        }
diff --git a/src/test/cpp/varia/errorhandlertestcase.cpp 
b/src/test/cpp/varia/errorhandlertestcase.cpp
index 468ab4bf..5a479258 100644
--- a/src/test/cpp/varia/errorhandlertestcase.cpp
+++ b/src/test/cpp/varia/errorhandlertestcase.cpp
@@ -85,7 +85,8 @@ public:
 
        void test1()
        {
-               DOMConfigurator::configure("input/xml/fallback1.xml");
+               auto status = 
DOMConfigurator::configure("input/xml/fallback1.xml");
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                auto appender = root->getAppender(LOG4CXX_STR("PRIMARY"));
                auto primary = log4cxx::cast<FileAppender>(appender);
                auto errHandle = primary->getErrorHandler();
@@ -127,7 +128,8 @@ public:
 
        void test2()
        {
-               DOMConfigurator::configure("input/xml/fallback2.xml");
+               auto status = 
DOMConfigurator::configure("input/xml/fallback2.xml");
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                auto appender = root->getAppender(LOG4CXX_STR("PRIMARY"));
                auto primary = log4cxx::cast<FileAppender>(appender);
                auto errHandle = primary->getErrorHandler();
diff --git a/src/test/cpp/xml/customleveltestcase.cpp 
b/src/test/cpp/xml/customleveltestcase.cpp
index d2259a56..b58c0081 100644
--- a/src/test/cpp/xml/customleveltestcase.cpp
+++ b/src/test/cpp/xml/customleveltestcase.cpp
@@ -69,7 +69,8 @@ public:
 
        void test1()
        {
-               
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/customLevel1.xml"));
+               auto status = 
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/customLevel1.xml"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                const File witness("witness/customLevel.1");
                LOGUNIT_ASSERT(Compare::compare(TEMP, witness));
@@ -77,7 +78,8 @@ public:
 
        void test2()
        {
-               
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/customLevel2.xml"));
+               auto status = 
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/customLevel2.xml"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                const File witness("witness/customLevel.2");
                LOGUNIT_ASSERT(Compare::compare(TEMP, witness));
@@ -86,6 +88,7 @@ public:
        void test3()
        {
                
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/customLevel3.xml"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                const File witness("witness/customLevel.3");
                LOGUNIT_ASSERT(Compare::compare(TEMP, witness));
@@ -93,7 +96,8 @@ public:
 
        void test4()
        {
-               
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/customLevel4.xml"));
+               auto status = 
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/customLevel4.xml"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
                const File witness("witness/customLevel.4");
                LOGUNIT_ASSERT(Compare::compare(TEMP, witness));
diff --git a/src/test/cpp/xml/domtestcase.cpp b/src/test/cpp/xml/domtestcase.cpp
index 5f98b29e..b94ab641 100644
--- a/src/test/cpp/xml/domtestcase.cpp
+++ b/src/test/cpp/xml/domtestcase.cpp
@@ -17,6 +17,7 @@
 
 #include <log4cxx/logger.h>
 #include <log4cxx/xml/domconfigurator.h>
+#include <log4cxx/defaultconfigurator.h>
 #include "../logunit.h"
 #include "../util/compare.h"
 #include "xlevel.h"
@@ -56,6 +57,7 @@ LOGUNIT_CLASS(DOMTestCase)
        LOGUNIT_TEST(recursiveAppenderRef);
        LOGUNIT_TEST(invalidAppender);
        LOGUNIT_TEST(invalidLevel);
+       LOGUNIT_TEST(testAutoFallback);
        LOGUNIT_TEST_SUITE_END();
 
        LoggerPtr root;
@@ -73,6 +75,7 @@ LOGUNIT_CLASS(DOMTestCase)
 public:
        void setUp()
        {
+               LogLog::setInternalDebugging(true);
                root = Logger::getRootLogger();
                logger = 
Logger::getLogger(LOG4CXX_TEST_STR("org.apache.log4j.xml.DOMTestCase"));
        }
@@ -89,8 +92,8 @@ public:
 
        void test1()
        {
-               LogLog::setInternalDebugging(true);
-               
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/DOMTestCase1.xml"));
+               auto status = 
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/DOMTestCase1.xml"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
 
                ControlFilter cf1;
@@ -134,7 +137,8 @@ public:
        //
        void test2()
        {
-               
DOMConfigurator::configure(LOG4CXX_TEST_STR("input\\xml\\DOMTestCase2.xml"));
+               auto status = 
DOMConfigurator::configure(LOG4CXX_TEST_STR("input\\xml\\DOMTestCase2.xml"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                common();
 
                ThreadFilter threadFilter;
@@ -196,7 +200,8 @@ public:
         */
        void test3()
        {
-               
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/DOMTestCase3.xml"));
+               auto status = 
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/DOMTestCase3.xml"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                LOG4CXX_INFO(logger, "File name is expected to end with a 
superscript 3");
 #if LOG4CXX_LOGCHAR_IS_UTF8
                const logchar fname[] = { 0x6F, 0x75, 0x74, 0x70, 0x75, 0x74, 
0x2F, 0x64, 0x6F, 0x6D, static_cast<logchar>(0xC2), static_cast<logchar>(0xB3), 
0 };
@@ -216,7 +221,8 @@ public:
         */
        void test4()
        {
-               
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/DOMTestCase4.xml"));
+               auto status = 
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/DOMTestCase4.xml"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
                LOG4CXX_INFO(logger, "File name is expected to end with an 
ideographic 4");
 #if LOG4CXX_LOGCHAR_IS_UTF8
                const logchar fname[] = { 0x6F, 0x75, 0x74, 0x70, 0x75, 0x74, 
0x2F, 0x64, 0x6F, 0x6D, static_cast<logchar>(0xE3), static_cast<logchar>(0x86), 
static_cast<logchar>(0x95), 0 };
@@ -234,22 +240,47 @@ public:
        void recursiveAppenderRef()
        {
                // Load a bad XML file, make sure that we don't crash in 
endless recursion
-               
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/DOMConfiguratorRecursive.xml"));
-  }
+               auto status = 
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/DOMConfiguratorRecursive.xml"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::NotConfigured);
+       }
 
        void invalidAppender()
        {
                // Load an XML file that attempts to use a levelmatchfilter as 
an appender.
                // We should not crash when loading this file.
-               
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/DOMInvalidAppender.xml"));
-  }
+               auto status = 
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/DOMInvalidAppender.xml"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::NotConfigured);
+       }
   
        void invalidLevel()
        {
                // Load an XML file that attempts to use a filter as a level.
                // We should not crash when loading this file.
-               
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/DOMInvalidLevel.xml"));
+               auto status = 
DOMConfigurator::configure(LOG4CXX_TEST_STR("input/xml/DOMInvalidLevel.xml"));
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
        }
+
+       void testAutoFallback()
+       {
+               std::vector<LogString> paths
+                       { LOG4CXX_STR("input/xml")
+                       };
+               std::vector<LogString> names
+                       { LOG4CXX_STR("DOMTestCase5_bad0.xml")
+                       , LOG4CXX_STR("DOMTestCase5_bad1.xml")
+                       , LOG4CXX_STR("DOMTestCase5_bad2.xml")
+                       , LOG4CXX_STR("DOMTestCase5_bad3.xml")
+                       , LOG4CXX_STR("DOMTestCase5_good.xml")
+                       };
+               LogString configFile;
+               spi::ConfigurationStatus status;
+               std::tie(status, configFile) = 
DefaultConfigurator::configureFromFile(paths, names);
+               LOGUNIT_ASSERT_EQUAL(status, 
spi::ConfigurationStatus::Configured);
+               LOGUNIT_ASSERT(configFile.npos != 
configFile.find(LOG4CXX_STR("DOMTestCase5_good.xml")));
+               // Prevent "DOMTestCase5_good.xml" use in subsequent default 
configuration
+               DefaultConfigurator::setConfigurationFileName(LogString());
+       }
+
 };
 
 LOGUNIT_TEST_SUITE_REGISTRATION(DOMTestCase);
diff --git a/src/test/resources/input/xml/DOMTestCase5_bad0.xml 
b/src/test/resources/input/xml/DOMTestCase5_bad0.xml
new file mode 100644
index 00000000..afd73782
--- /dev/null
+++ b/src/test/resources/input/xml/DOMTestCase5_bad0.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/";>
+</log4j:configuration>
diff --git a/src/test/resources/input/xml/DOMTestCase5_bad1.xml 
b/src/test/resources/input/xml/DOMTestCase5_bad1.xml
new file mode 100644
index 00000000..213a8824
--- /dev/null
+++ b/src/test/resources/input/xml/DOMTestCase5_bad1.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/";>
+  <appender name="A1" class="org.apache.log4j.UnknownAppender">
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="%-5p %c{2} - %m%n"/>
+    </layout>
+  </appender>
+
+  <root>
+    <priority value ="debug" />
+    <appender-ref ref="A1" />
+  </root>
+
+</log4j:configuration>
diff --git a/src/test/resources/input/xml/DOMTestCase5_bad2.xml 
b/src/test/resources/input/xml/DOMTestCase5_bad2.xml
new file mode 100644
index 00000000..bc26d9fc
--- /dev/null
+++ b/src/test/resources/input/xml/DOMTestCase5_bad2.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/";>
+  <appender class="org.apache.log4j.FileAppender">
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="%-5p %c{2} - %m%n"/>
+    </layout>
+  </appender>
+
+  <root>
+    <priority value ="debug" />
+    <appender-ref ref="A1" />
+  </root>
+
+</log4j:configuration>
diff --git a/src/test/resources/input/xml/DOMTestCase5_bad3.xml 
b/src/test/resources/input/xml/DOMTestCase5_bad3.xml
new file mode 100644
index 00000000..fe1696ab
--- /dev/null
+++ b/src/test/resources/input/xml/DOMTestCase5_bad3.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/";>
+</log4j:confguration>
diff --git a/src/test/resources/input/xml/DOMTestCase5_good.xml 
b/src/test/resources/input/xml/DOMTestCase5_good.xml
new file mode 100644
index 00000000..568df13e
--- /dev/null
+++ b/src/test/resources/input/xml/DOMTestCase5_good.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/";>
+  <appender name="A1" class="org.apache.log4j.ConsoleAppender">
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="%Y%-5p %c{2} - %m%y%n"/>
+    </layout>
+  </appender>
+
+  <root>
+    <priority value ="debug" />
+    <appender-ref ref="A1" />
+  </root>
+
+</log4j:configuration>

Reply via email to