On Feb 27, 2006, at 3:12 PM, Andreas Fester wrote:

I indent to commit the attached patch. It adds the
possibility to set system properties (they are
still retrieved from the environment if they do not exist yet
when they are read the first time).
This will allow applications to set any kind of system
property to configure very basic behaviour of log4cxx.

Its primarily a preparation for LOGCXX-126:
it will allow to set a system property like "log4cxx.useWideStreams"
very early in the application to switch to wide streams output
(We need a runtime configuration there; see my comment
at http://issues.apache.org/jira/browse/LOGCXX-126#action_12367428).


I'll add comments back to that bug report. I'm scrambling on this, but it looks like appropriate use of fwide() could ensure that ConsoleAppender uses the correct mode if somebody else already wrote to stdout before the first call to ConsoleAppender. Using a system property to control this is down on my list of ways to approach the problem, I'd rather had configuration parameters or a distinct WideConsoleAppender before depending on a system property.

Comments on the proposed patch:

Thanks,

        Andreas
Index: include/log4cxx/helpers/properties.h
===================================================================
--- include/log4cxx/helpers/properties.h        (Revision 378958)
+++ include/log4cxx/helpers/properties.h        (Arbeitskopie)
@@ -139,6 +139,15 @@
LogString getProperty(const LogString& key) const;

                         /**
+ Tests if this property list contains the specified key.
+
+                        @param   key   possible key.
+ @return <code>true</code> if this property list contains the + specified key, <code>false</code> otherwise.
+                        */
+                        bool containsKey(const LogString& key);
+
+                        /**
Returns an enumeration of all the keys in this property list, including distinct keys in the default property list if a key of the same name has not already been found from the main


Looks okay, follows the JDK's Properties.containsKey()


Index: include/log4cxx/helpers/system.h
===================================================================
--- include/log4cxx/helpers/system.h    (Revision 378958)
+++ include/log4cxx/helpers/system.h    (Arbeitskopie)
@@ -31,6 +31,10 @@
                 */
                 class LOG4CXX_EXPORT System
                 {
+                static Properties* props;
+
+                static void initStatic();
+
                 public:

                 /**
@@ -45,6 +49,15 @@
                 */
                 static LogString getProperty(const LogString& key);

+                /**
+ Sets the system property indicated by the specified key.
+
+                 @param  key   the name of the system property.
+                 @param  value the value of the system property.
+ @return the previous value of the system property or an empty string
+                          if it did not have one.
+                */
+ static LogString setProperty(const LogString& key, const LogString& value);
                 };
         } // namespace helpers
  } //  namespace log4cxx

Been trying to avoid non-local static variables. In this case, I doubt that props is ever reclaimed. I'd prefer something like:

static PropertiesPtr getProperties() {
     static PropertiesPtr properties(new Properties());
     return properties;
}


Index: src/system.cpp
===================================================================
--- src/system.cpp      (Revision 378958)
+++ src/system.cpp      (Arbeitskopie)
@@ -37,65 +37,88 @@
 using namespace log4cxx::helpers;


-LogString System::getProperty(const LogString& lkey)
-{
-        if (lkey.empty())
-        {
-                throw IllegalArgumentException("key is empty");
+Properties* System::props;
+
+void System::initStatic() {
+        static bool isInitialized = false;
+        if (isInitialized) {
+          return;
         }
+        isInitialized = true;

-        LogString rv;
-        if (lkey == LOG4CXX_STR("java.io.tmpdir")) {
-          Pool p;
-          const char* dir = NULL;
- apr_status_t stat = apr_temp_dir_get(&dir, (apr_pool_t*) p.getAPRPool());
-          if (stat == APR_SUCCESS) {
-            Transcoder::decode(dir, strlen(dir), rv);
-          }
-          return rv;
+        // system properties live until the application terminates
+        props = new Properties();
+
+        Pool pool;
+        apr_pool_t* p = (apr_pool_t*) pool.getAPRPool();
+
+        // java.io.tmpdir
+        LogString tempDir;
+        const char* dir = NULL;
+        apr_status_t stat = apr_temp_dir_get(&dir, p);
+        if (stat == APR_SUCCESS) {
+          Transcoder::decode(dir, strlen(dir), tempDir);
         }
+        props->setProperty(LOG4CXX_STR("java.io.tmpdir"), tempDir);

-        if (lkey == LOG4CXX_STR("user.dir")) {
-          Pool p;
-          char* dir = NULL;
- apr_status_t stat = apr_filepath_get(&dir, APR_FILEPATH_NATIVE,
-              (apr_pool_t*) p.getAPRPool());
-          if (stat == APR_SUCCESS) {
-            Transcoder::decode(dir, strlen(dir), rv);
-          }
-          return rv;
+        // user.dir
+        char* userdir = NULL;
+        LogString userDir;
+        stat = apr_filepath_get(&userdir, APR_FILEPATH_NATIVE, p);
+        if (stat == APR_SUCCESS) {
+          Transcoder::decode(userdir, strlen(userdir), userDir);
         }
+        props->setProperty(LOG4CXX_STR("user.dir"), userDir);
+
+        // user.home
+        // user.name
 #if APR_HAS_USER
- if (lkey == LOG4CXX_STR("user.home") || lkey == LOG4CXX_STR ("user.name")) {
-          Pool pool;
-          apr_uid_t userid;
-          apr_gid_t groupid;
-          apr_pool_t* p = (apr_pool_t*) pool.getAPRPool();
-          apr_status_t stat = apr_uid_current(&userid, &groupid, p);
+        LogString userName;
+        LogString userHome;
+
+        apr_uid_t userid;
+        apr_gid_t groupid;
+        stat = apr_uid_current(&userid, &groupid, p);
+        if (stat == APR_SUCCESS) {
+          char* username = NULL;
+          stat = apr_uid_name_get(&username, userid, p);
           if (stat == APR_SUCCESS) {
-            char* username = NULL;
-            stat = apr_uid_name_get(&username, userid, p);
+            Transcoder::decode(username, strlen(username), userName);
+
+            char* dirname = NULL;
+            stat = apr_uid_homepath_get(&dirname, username, p);
             if (stat == APR_SUCCESS) {
-              if (lkey == LOG4CXX_STR("user.name")) {
-                Transcoder::decode(username, strlen(username), rv);
-              } else {
-                char* dirname = NULL;
-                stat = apr_uid_homepath_get(&dirname, username, p);
-                if (stat == APR_SUCCESS) {
-                  Transcoder::decode(dirname, strlen(dirname), rv);
-                }
-              }
+              Transcoder::decode(dirname, strlen(dirname), userHome);
             }
           }
-          return rv;
         }
+
+        props->setProperty(LOG4CXX_STR("user.home"), userHome);
+        props->setProperty(LOG4CXX_STR("user.name"), userName);
 #endif
+}

-        LOG4CXX_ENCODE_CHAR(key, lkey);
-        const char * value = ::getenv(key.c_str());
-        if (value != 0) {
-                Transcoder::decode(value, rv);
+
+LogString System::getProperty(const LogString& lkey)
+{
+        initStatic();
+
+        // if the key is not yet in the properties, then add it
+        if (!props->containsKey(lkey)) {
+          LogString envVar;
+          LOG4CXX_ENCODE_CHAR(key, lkey);
+          const char * value = ::getenv(key.c_str());
+          if (value != 0) {
+            Transcoder::decode(value, envVar);
+          }
+          props->setProperty(lkey, envVar);
         }
-        return rv;
+
+        return props->getProperty(lkey);
 }

+
+LogString System::setProperty(const LogString& key, const LogString& value) {
+        initStatic();
+        return props->setProperty(key, value);
+}

I could be misinterpreting this code since I'm looking at the patch itself and not the patched code. It looks like your patch would likely cache the values of java.io.tmpdir, user.home, environment at initialization and would not reflect changes that occur after that time.



Index: src/properties.cpp
===================================================================
--- src/properties.cpp  (Revision 378958)
+++ src/properties.cpp  (Arbeitskopie)
@@ -318,6 +318,12 @@
         return oldValue;
 }

+bool Properties::containsKey(const LogString& key)
+{
+ std::map<LogString, LogString>::const_iterator it = properties.find(key);
+        return (it != properties.end());
+}
+
 LogString Properties::getProperty(const LogString& key) const
 {
std::map<LogString, LogString>::const_iterator it = properties.find(key);


Okay.

Index: tests/src/helpers/systemtestcase.cpp
===================================================================
--- tests/src/helpers/systemtestcase.cpp        (Revision 0)
+++ tests/src/helpers/systemtestcase.cpp        (Revision 0)
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+
+#include <log4cxx/helpers/system.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include <log4cxx/helpers/loglog.h>
+
+using namespace log4cxx;
+using namespace log4cxx::helpers;
+
+/**
+   Unit tests for the System class
+   @author Andreas Fester
+   @since 0.9.8
+*/
+class SystemTestCase : public CppUnit::TestFixture {
+
+    CPPUNIT_TEST_SUITE( SystemTestCase );
+      CPPUNIT_TEST( testSystemProperties );
+    CPPUNIT_TEST_SUITE_END();
+
+public:
+  /**
+   * Check that System::getProperty() returns some values
+   */
+  void testSystemProperties() {
+    // java.io.tmpdir and user.dir always exist
+    LogString tmpDir = System::getProperty("java.io.tmpdir");
+    CPPUNIT_ASSERT(!tmpDir.empty());
+
+    LogString usrDir = System::getProperty("user.dir");
+    CPPUNIT_ASSERT(!usrDir.empty());
+
+    // check propagation of environment variables
+    LogString totoValue = System::getProperty("TOTO");
+    CPPUNIT_ASSERT(totoValue == "wonderful");
+
+    // check unknown property
+    LogString unknown = System::getProperty("unknown.property");
+    CPPUNIT_ASSERT(unknown.empty());
+  }
+};
+

Okay.


+
+CPPUNIT_TEST_SUITE_REGISTRATION(SystemTestCase);
Index: tests/src/Makefile.am
===================================================================
--- tests/src/Makefile.am       (Revision 378958)
+++ tests/src/Makefile.am       (Arbeitskopie)
@@ -37,6 +37,7 @@
         helpers/relativetimedateformattestcase.cpp \
         helpers/stringtokenizertestcase.cpp \
         helpers/stringhelpertestcase.cpp \
+        helpers/systemtestcase.cpp \
         helpers/timezonetestcase.cpp \
         helpers/transcodertestcase.cpp \
         helpers/unicodehelpertestcase.cpp

Okay.

Reply via email to