1 
  2 #ifndef _UTIL_PROPERTY_C
  3 #define _UTIL_PROPERTY_C
  4 
  5 #include "Property.h"
  6 #include <cstdlib> //<stdlib.h>
  7 #include <fstream>
  8 #include <iostream>
  9 #include <util/lexical_cast.h>
 10 #include <util/PropertyDef.h>
 11 #include <util/Constants.h>
 12 #include <util/StringTrim.h>
 13 
 14 using namespace std;
 15 using namespace org::xmlBlaster::util;
 16 
 17 #if defined(WINCE) /* No getenv() for Windows CE. TODO: Use some registry workaround as others do */
 18 char *getenv(const char *key) {
 19       return 0;
 20 }
 21 #endif
 22 
 23 #define  MAX_NEST 50
 24 
 25 Property::Property(int args, const char * const argv[]) : properties_() {
 26    initializeDefaultProperties();
 27    if (args && argv) {
 28       loadCommandLineProps(args, argv, std::string("-"), false); // xmlBlaster-style properties
 29    }
 30    //loadPropertyFile();
 31 }
 32 
 33 Property::Property(MapType propMap) : properties_(propMap)
 34 {
 35    initializeDefaultProperties();
 36         replaceVariables(true);
 37 }
 38 
 39 void Property::initializeDefaultProperties()
 40 {
 41    // Add some predefined variables to be useful in xmlBlaster.properties as ${user.home} etc.
 42    bool useEnv = true;
 43    bool overwrite = false;
 44    
 45 #if defined(_WINDOWS)
 46    // Windows: _WINDOWS
 47    // HOMEDRIVE=C:
 48    // HOMEPATH=\Documents and Settings\Marcel
 49    char *driveP = getenv("HOMEDRIVE");
 50    string drive = (driveP != 0) ? string(driveP) : string("");
 51    char *pathP = getenv("HOMEPATH");
 52    string path = (pathP != 0) ? string(pathP) : string("");
 53    setProperty("user.home", drive + path);
 54 #else
 55    if (!propertyExists("user.home", false)) {
 56       string value = getProperty("HOME", useEnv);
 57       if (value != "") {
 58          setProperty("user.home", value, true); // UNIX
 59       }
 60    }
 61 #endif
 62    //std::cout << "user.home=" << getProperty("user.home", "??") << std::endl;
 63 
 64    if (!propertyExists("user.name", false)) {
 65       string value = getProperty("USER", useEnv);
 66       if (value != "") {
 67          setProperty("user.name", value, true); // UNIX
 68       }
 69       else {
 70          // Windows: _WINDOWS
 71          // USERNAME=joe
 72          char *puser = getenv("USERNAME");
 73          if (puser) {
 74             string tmp = puser;
 75             setProperty("user.name", tmp, true);
 76          }
 77          else {
 78             // HOMEPATH=\Documents and Settings\Marcel
 79             char *pathP = getenv("HOMEPATH");
 80             string path = (pathP != 0) ? string(pathP) : string("");
 81             std::string::size_type pos = path.rfind(FILE_SEP);
 82             if (pos != string::npos && pos < path.size()-1) {
 83                setProperty("user.name", path.substr(pos+1));
 84             }
 85          }
 86       }
 87    }
 88    
 89    if (!propertyExists("java.io.tmpdir", false)) {
 90       string value = getProperty("TMP", useEnv);
 91       if (value != "") {
 92          setProperty("java.io.tmpdir", value, true);
 93       }
 94    }
 95 
 96    // XMLBLASTER_HOME
 97 
 98    setProperty("file.separator", FILE_SEP, overwrite);  // '/' on UNIX
 99    setProperty("path.separator", PATH_SEP, overwrite);  // ':' on UNIX
100 
101    // _WINDOWS:
102    // COMPUTERNAME=myserver
103    // LOGONSERVER=\\myserver
104    // NUMBER_OF_PROCESSORS=1
105    // OS=Windows_NT
106    // PROCESSOR_ARCHITECTURE=x86
107    // PROCESSOR_IDENTIFIER=x86 Family 15 Model 2 Stepping 4, GenuineIntel
108    // PROCESSOR_LEVEL=15
109    // PROCESSOR_REVISION=0204
110    // USERDOMAIN=myserver
111    // USERNAME=joe
112    // USERPROFILE=C:\Documents and Settings\marcel
113    // VC7=1
114    // HOMEDRIVE=C:
115    // HOMEPATH=\Documents and Settings\marcel
116    // TMP=C:\DOCUME~1\marcel\LOCALS~1\Temp
117 
118    // os.name = Linux
119    // os.name = "Windows XP"     os.version=5.1 (_WINDOWS)
120    // line.separator = CRLF ...
121    // java.io.tmpdir = /tmp ...   C:\DOCUME~1\marcel\LOCALS~1\Temp\ == C:\Documents and Settings\marcel\Local Settings\Temp  (_WINDOWS)
122    // user.dir = /home/xmlblast/test -> getcwd()
123    // sun.cpu.endian = little
124 }
125 
126 /**
127  * @see Property.h#loadCommandLineProps
128  */
129 int 
130 Property::loadCommandLineProps(int args,
131                                const char * const argv[],
132                                const string &prefix, 
133                                bool javaStyle) 
134 {
135 
136    int    count = 1, ret=0, nmax = args;
137    string value;
138    //if (!javaStyle) nmax--; // they come in separated pairs
139    while (count < nmax) {
140       string name = argv[count];
141       if (name.find(prefix) == 0) { // it is a property
142          name = name.substr(prefix.length()); // remove separator e.g. "-trace" -> "trace"
143          if (!javaStyle) { // Corba style (or other non-java styles)
144             //if (name == "h" || name == "help" || name == "?" ) {
145             value = (count < nmax-1) ? argv[count+1] : "";
146             if (value == ""/* || value.find(prefix) == 0*/) { // A property without a value -> we set it to true, for example --help
147                if (setProperty_(name, lexical_cast<std::string>(true))) ret++;
148             }
149             else {
150                count++;
151                //std::cout << "readPropertyCommandLine: " << name << "=" << value << std::endl;
152                if (setProperty_(name, value)) ret++;
153             }
154          }
155          else { // java style: prop1=val1
156             pair<const string, string> propPair(getPair(name));
157             if (setProperty_(propPair.first, propPair.second)) ret++;
158          }
159       }
160       count++;
161    }
162 //   if (count > 0)
163 //      std::cout << "Successfully read " << (count-1)/2 << " command line arguments" << std::endl;
164    if (ret > 0) {
165       replaceVariables(true);
166    }
167    return ret;
168 }
169 
170 
171 /*
172  * xmlBlaster.properties is searched in this sequence:
173  * <ul>
174  *    <li>the command line parameter '-propertyFile', e.g. "-propertyFile /tmp/xy.properties"</li>
175  *    <li>the environment variable 'propertyFile', e.g. "propertyFile=/tmp/xy.properties"</li>
176  *    <li>the local directory: ./xmlBlaster.properties</li>
177  *    <li>in your home directory, HOME/xmlBlaster.properties</li>
178  *    <li>in the $XMLBLASTER_HOME directory</li>
179  * </ul>
180  * Command line properties have precedence<p />
181  * Environment variables are weakest
182  */
183 
184 void 
185 Property::loadPropertyFile()
186 {
187    const string filename = "xmlBlaster.properties";
188    string path="";
189    int num=0;
190 
191    if (num < 1) {
192       path = getProperty("propertyFile", false); // command line property
193       if (!path.empty())
194          num = readPropertyFile(path, false);
195    }
196    if (num < 1) {
197       path = getProperty("propertyFile", true); // looking in environment as well
198       if (!path.empty())
199          num = readPropertyFile(path, false);
200    }
201    if (num < 1) {
202       num = readPropertyFile(filename, false);
203    }
204    if (num < 1) {      
205      path = getStringProperty("user.home", "", true); // Check home directory $HOME
206      if (!path.empty()) {
207        num = readPropertyFile(path + FILE_SEP + filename, false);
208      }
209    }
210    if (num < 1) {
211      if(getenv("XMLBLASTER_HOME")) {
212        path = getenv("XMLBLASTER_HOME");
213      if (!path.empty())
214        num = readPropertyFile(path + FILE_SEP + filename, false);
215      }
216    }
217    if (num > 0) {
218       replaceVariables(true);
219    }
220 }
221 
222 
223 int Property::readPropertyFile(const string &filename, bool overwrite) 
224 {
225    ifstream in(filename.c_str());
226    string  line, tmp;
227    int     count = 0;
228    if (in == 0) return -1;
229    std::cout << "Reading property file " << filename << std::endl;
230    while (!in.eof()) {
231       getline(in, tmp);
232       StringTrim::trimEnd(tmp);
233       if (tmp.size() > 0 && tmp[tmp.size()-1] == '\\') {
234          line += tmp.substr(0,tmp.size()-1);
235          continue;
236       }
237       line += tmp;
238       if (!in.eof()) {
239          pair<const string, string> valuePair(getPair(line));
240          if ((valuePair.first != "") && (valuePair.second != "")) {
241             //std::cout << "readPropertyFile: " << valuePair.first << "=" << valuePair.second << std::endl;
242             if (setProperty_(valuePair.first, valuePair.second, overwrite))
243                count++;
244          }
245       }
246       line = "";
247    }
248    in.close();
249 //   if (count > 0)
250 //      std::cout << "Successfully read " << count << " entries from " << filename << std::endl;
251    return count;
252 }
253 
254 
255 /**
256  * writes the properties to a file specified in the argument list. If it
257  * could not write to the file, a zero is returned.
258  * Returns the number of properties written to the file.
259  */
260 int 
261 Property::writePropertyFile(const char *filename) const 
262 {
263    ofstream out(filename);
264    int      count = 0;
265    if (out == 0) return count;
266    MapType::const_iterator iter = properties_.begin();
267    while (iter != properties_.end()) {
268      out << (*iter).first << "=" << (*iter).second << std::endl;
269       iter++;
270       count++;
271    }
272    out.close();
273    return count;
274 }
275 
276 /**
277  * Gets the property with the specified name. If no such property exists,
278  * an empty string is returned. If the string is not found, it searches
279  * in among the environment variables (only if env is set to true which
280  * is the default). In the property is not found there either, it returns
281  * an empty string.
282  */
283 string 
284 Property::getProperty(const string &name, bool env) 
285 {
286    MapType::const_iterator iter = properties_.find(name);
287    if (iter == properties_.end()) {
288       if (!env) return "";
289       char* envStr = getenv(name.c_str());
290       if (envStr == 0) return "";
291       setProperty(name, envStr);
292       return string(envStr);
293    }
294    return (*iter).second;
295 }
296 
297 
298 bool 
299 Property::propertyExists(const string &name, bool env) 
300 {
301    MapType::const_iterator iter = properties_.find(name);
302    if (iter == properties_.end()) {
303       if (!env) return false;
304       char* envStr = getenv(name.c_str());
305       if (envStr == 0) return false;
306       setProperty(name, envStr);
307    }
308    return true;
309 }
310 
311 
312 int 
313 Property::getIntProperty(const string &name, int def, bool env) 
314 {
315    string value = getProperty(name, env);
316    if (value.length() == 0) return def;
317    char *test = (char*)0;
318    int ret = (int)strtol(value.c_str(), &test, 10);
319    if (test == value.c_str()) return def;
320 //   int ret = lexical_cast<int>(value);
321    return ret;
322 }
323 
324 long
325 Property::getLongProperty(const string &name, long def, bool env)
326 {
327    string value = getProperty(name, env);
328    if (value.empty()) return def;
329    char *test = (char*)0;
330    long ret = atol(value.c_str());
331    if (test == value.c_str()) return def;
332 //   long ret = lexical_cast<long>(value);
333    return ret;
334 }
335 
336 Timestamp
337 Property::getTimestampProperty(const string &name, Timestamp def, bool env)
338 {
339    string value = getProperty(name, env);
340    if (value.length() == 0) return def;
341    char *test = (char*)0;
342 //   Timestamp ret = STRING_TO_TIMESTAMP(value.c_str());
343    if (test == value.c_str()) return def;
344    Timestamp ret = 0;
345    try {
346       lexical_cast<Timestamp>(value);
347    }
348    catch (...) {
349       ret = 0;
350    }
351    return ret;
352 }
353 
354 bool
355 Property::getBoolProperty(const string &name, bool def, bool env) 
356 {
357    string value = getProperty(name, env);
358    return StringTrim::isTrue(value, def);
359 }
360 
361 
362 string 
363 Property::getStringProperty(const string &name, const string &def, 
364                       bool env) 
365 {
366    string value = getProperty(name, env);
367    if (value.length() == 0) return def;
368    return value;
369 }
370 
371 
372 // private
373 bool Property::setProperty_(const string &name, const string &value,
374                       bool overwrite) 
375 {
376    MapType::iterator iter = properties_.find(name);
377    if (iter != properties_.end()) {
378       if (overwrite) (*iter).second = value;
379       else return false;
380    }
381    else {
382       pair<const string, string> valuePair(name, value);
383       properties_.insert(valuePair);
384    }
385    return true;                                                                                                                                         
386 }
387 
388 bool Property::setProperty(const string &name, const string &value,
389                       bool overwrite) 
390 {
391    string newValue = replaceVariable(name, value, true);
392    bool ret = setProperty_(name, newValue, overwrite);
393    return ret;
394 }
395 
396 
397 /**
398  * To allow templatized getting of properties. It returns true if the property has been found. In that
399  * case, the return value is put into the 'value' argument.
400  */
401 bool Property::getTypedProperty(const string& name, string& value, bool env)
402 {
403    if (!propertyExists(name, env)) return false;
404    value = getStringProperty(name, "", env);
405    return true;
406 }
407 
408 bool Property::getTypedProperty(const string& name, int& value, bool env)
409 {
410    if (!propertyExists(name, env)) return false;
411    value = getIntProperty(name, 0, env);
412    return true;
413 }
414 
415 bool Property::getTypedProperty(const string& name, long& value, bool env)
416 {
417    if (!propertyExists(name, env)) return false;
418    value = getLongProperty(name, 0, env);
419    return true;
420 }
421 
422 bool Property::getTypedProperty(const string& name, bool& value, bool env)
423 {
424    if (!propertyExists(name, env)) return false;
425    value = getBoolProperty(name, false, env);
426    return true;
427 }
428 
429 #if __LP64__
430    // long === long long === 64 bit
431 #else
432 bool Property::getTypedProperty(const string& name, Timestamp& value, bool env)
433 {
434    if (!propertyExists(name, env)) return false;
435    value = getTimestampProperty(name, 0, env);
436    return true;
437 }
438 #endif
439   
440 std::string Property::toXml(const std::string& extraOffset)
441 {
442    string offset = Constants::OFFSET + extraOffset;
443    string sb;
444    MapType::const_iterator it;
445    sb += offset;
446    sb += "<Property>";
447    for (it=properties_.begin(); it!=properties_.end(); ++it) {
448       const string& key = (*it).first;
449       const string& value = (*it).second;
450       sb += offset + Constants::INDENT;
451       sb += "<" + key + ">" + value + "</" + key + ">";
452    }
453    sb += offset;
454    sb += "</Property>";
455    return sb;
456 }
457 
458 void Property::replaceVariables(bool env) {
459    MapType::const_iterator it;
460    for (it=properties_.begin(); it!=properties_.end(); ++it) {
461       const string& key = (*it).first;
462       const string& value = (*it).second;
463       const string newValue = replaceVariable(key, value, env);
464       if (value != newValue) {
465          properties_[key] = newValue;
466       }
467    }
468 }
469 
470 string Property::replaceVariable(const string &/*key*/, const string &valueOrig, bool env) {
471    //if (replaceVariables == false)
472    //   return value;
473    string value = valueOrig;
474    string origValue = value;
475    string tok = "${";
476    string endTok = "}";
477    for (int ii = 0;; ii++) {
478       string::size_type from = value.find(tok);
479       if (from != string::npos) {
480          string::size_type to = value.find(endTok, from);
481          if (to == string::npos) {
482             //std::cout << "Property.InvalidVariable: Invalid variable '" << value.substr(from) << "', expecting ${} syntax." << std::endl;
483          }
484          string sub = value.substr(from, to + endTok.size() - from); // "${XY}"
485          string subKey = sub.substr(tok.size(), sub.length() - endTok.size() - tok.size()); // "XY"
486          string subValue = getProperty(subKey, env);
487          if (subValue.empty()) {
488             //if (verbose>=2) std::cout << "Property: Unknown variable " << sub << " is not replaced" << std::endl;
489             return value;
490          }
491          value = StringTrim::replaceAll(value, sub, subValue);
492       }
493       else {
494          //if (ii > 0 && verbose>=2) {
495          //   std::cout << "Property: Replacing '" << key << "=" << origValue << "' to '" << value << "'" << std::endl;
496          //}
497          return value;
498       }
499       if (ii > MAX_NEST) {
500          //if (verbose>=1) std::cout << "Property: Maximum nested depth of " << MAX_NEST << " reached for variable '" << getProperty(key, env) << "'." << std::endl;
501          return value;
502       }
503    }
504 }
505 
506 
507 #endif 


syntax highlighted by Code2HTML, v. 0.9.1