00001 00002 #ifndef _UTIL_PROPERTY_C 00003 #define _UTIL_PROPERTY_C 00004 00005 #include "Property.h" 00006 #include <cstdlib> //<stdlib.h> 00007 #include <fstream> 00008 #include <iostream> 00009 #include <util/lexical_cast.h> 00010 #include <util/PropertyDef.h> 00011 #include <util/Constants.h> 00012 #include <util/StringTrim.h> 00013 00014 using namespace std; 00015 using namespace org::xmlBlaster::util; 00016 00017 #if defined(WINCE) /* No getenv() for Windows CE. TODO: Use some registry workaround as others do */ 00018 char *getenv(const char *key) { 00019 return 0; 00020 } 00021 #endif 00022 00023 #define MAX_NEST 50 00024 00025 Property::Property(int args, const char * const argv[]) : properties_() { 00026 initializeDefaultProperties(); 00027 if (args && argv) { 00028 loadCommandLineProps(args, argv, std::string("-"), false); // xmlBlaster-style properties 00029 } 00030 //loadPropertyFile(); 00031 } 00032 00033 Property::Property(MapType propMap) : properties_(propMap) 00034 { 00035 initializeDefaultProperties(); 00036 replaceVariables(true); 00037 } 00038 00039 void Property::initializeDefaultProperties() 00040 { 00041 // Add some predefined variables to be useful in xmlBlaster.properties as ${user.home} etc. 00042 bool useEnv = true; 00043 bool overwrite = false; 00044 00045 #if defined(_WINDOWS) 00046 // Windows: _WINDOWS 00047 // HOMEDRIVE=C: 00048 // HOMEPATH=\Documents and Settings\Marcel 00049 char *driveP = getenv("HOMEDRIVE"); 00050 string drive = (driveP != 0) ? string(driveP) : string(""); 00051 char *pathP = getenv("HOMEPATH"); 00052 string path = (pathP != 0) ? string(pathP) : string(""); 00053 setProperty("user.home", drive + path); 00054 #else 00055 if (!propertyExists("user.home", false)) { 00056 string value = getProperty("HOME", useEnv); 00057 if (value != "") { 00058 setProperty("user.home", value, true); // UNIX 00059 } 00060 } 00061 #endif 00062 //std::cout << "user.home=" << getProperty("user.home", "??") << std::endl; 00063 00064 if (!propertyExists("user.name", false)) { 00065 string value = getProperty("USER", useEnv); 00066 if (value != "") { 00067 setProperty("user.name", value, true); // UNIX 00068 } 00069 else { 00070 // Windows: _WINDOWS 00071 // USERNAME=joe 00072 char *puser = getenv("USERNAME"); 00073 if (puser) { 00074 string tmp = puser; 00075 setProperty("user.name", tmp, true); 00076 } 00077 else { 00078 // HOMEPATH=\Documents and Settings\Marcel 00079 char *pathP = getenv("HOMEPATH"); 00080 string path = (pathP != 0) ? string(pathP) : string(""); 00081 std::string::size_type pos = path.rfind(FILE_SEP); 00082 if (pos != string::npos && pos < path.size()-1) { 00083 setProperty("user.name", path.substr(pos+1)); 00084 } 00085 } 00086 } 00087 } 00088 00089 if (!propertyExists("java.io.tmpdir", false)) { 00090 string value = getProperty("TMP", useEnv); 00091 if (value != "") { 00092 setProperty("java.io.tmpdir", value, true); 00093 } 00094 } 00095 00096 // XMLBLASTER_HOME 00097 00098 setProperty("file.separator", FILE_SEP, overwrite); // '/' on UNIX 00099 setProperty("path.separator", PATH_SEP, overwrite); // ':' on UNIX 00100 00101 // _WINDOWS: 00102 // COMPUTERNAME=myserver 00103 // LOGONSERVER=\\myserver 00104 // NUMBER_OF_PROCESSORS=1 00105 // OS=Windows_NT 00106 // PROCESSOR_ARCHITECTURE=x86 00107 // PROCESSOR_IDENTIFIER=x86 Family 15 Model 2 Stepping 4, GenuineIntel 00108 // PROCESSOR_LEVEL=15 00109 // PROCESSOR_REVISION=0204 00110 // USERDOMAIN=myserver 00111 // USERNAME=joe 00112 // USERPROFILE=C:\Documents and Settings\marcel 00113 // VC7=1 00114 // HOMEDRIVE=C: 00115 // HOMEPATH=\Documents and Settings\marcel 00116 // TMP=C:\DOCUME~1\marcel\LOCALS~1\Temp 00117 00118 // os.name = Linux 00119 // os.name = "Windows XP" os.version=5.1 (_WINDOWS) 00120 // line.separator = CRLF ... 00121 // java.io.tmpdir = /tmp ... C:\DOCUME~1\marcel\LOCALS~1\Temp\ == C:\Documents and Settings\marcel\Local Settings\Temp (_WINDOWS) 00122 // user.dir = /home/xmlblast/test -> getcwd() 00123 // sun.cpu.endian = little 00124 } 00125 00129 int 00130 Property::loadCommandLineProps(int args, 00131 const char * const argv[], 00132 const string &prefix, 00133 bool javaStyle) 00134 { 00135 00136 int count = 1, ret=0, nmax = args; 00137 string value; 00138 //if (!javaStyle) nmax--; // they come in separated pairs 00139 while (count < nmax) { 00140 string name = argv[count]; 00141 if (name.find(prefix) == 0) { // it is a property 00142 name = name.substr(prefix.length()); // remove separator e.g. "-trace" -> "trace" 00143 if (!javaStyle) { // Corba style (or other non-java styles) 00144 //if (name == "h" || name == "help" || name == "?" ) { 00145 value = (count < nmax-1) ? argv[count+1] : ""; 00146 if (value == ""/* || value.find(prefix) == 0*/) { // A property without a value -> we set it to true, for example --help 00147 if (setProperty_(name, lexical_cast<std::string>(true))) ret++; 00148 } 00149 else { 00150 count++; 00151 //std::cout << "readPropertyCommandLine: " << name << "=" << value << std::endl; 00152 if (setProperty_(name, value)) ret++; 00153 } 00154 } 00155 else { // java style: prop1=val1 00156 pair<const string, string> propPair(getPair(name)); 00157 if (setProperty_(propPair.first, propPair.second)) ret++; 00158 } 00159 } 00160 count++; 00161 } 00162 // if (count > 0) 00163 // std::cout << "Successfully read " << (count-1)/2 << " command line arguments" << std::endl; 00164 if (ret > 0) { 00165 replaceVariables(true); 00166 } 00167 return ret; 00168 } 00169 00170 00171 /* 00172 * xmlBlaster.properties is searched in this sequence: 00173 * <ul> 00174 * <li>the command line parameter '-propertyFile', e.g. "-propertyFile /tmp/xy.properties"</li> 00175 * <li>the environment variable 'propertyFile', e.g. "propertyFile=/tmp/xy.properties"</li> 00176 * <li>the local directory: ./xmlBlaster.properties</li> 00177 * <li>in your home directory, HOME/xmlBlaster.properties</li> 00178 * <li>in the $XMLBLASTER_HOME directory</li> 00179 * </ul> 00180 * Command line properties have precedence<p /> 00181 * Environment variables are weakest 00182 */ 00183 00184 void 00185 Property::loadPropertyFile() 00186 { 00187 const string filename = "xmlBlaster.properties"; 00188 string path=""; 00189 int num=0; 00190 00191 if (num < 1) { 00192 path = getProperty("propertyFile", false); // command line property 00193 if (!path.empty()) 00194 num = readPropertyFile(path, false); 00195 } 00196 if (num < 1) { 00197 path = getProperty("propertyFile", true); // looking in environment as well 00198 if (!path.empty()) 00199 num = readPropertyFile(path, false); 00200 } 00201 if (num < 1) { 00202 num = readPropertyFile(filename, false); 00203 } 00204 if (num < 1) { 00205 path = getStringProperty("user.home", "", true); // Check home directory $HOME 00206 if (!path.empty()) { 00207 num = readPropertyFile(path + FILE_SEP + filename, false); 00208 } 00209 } 00210 if (num < 1) { 00211 if(getenv("XMLBLASTER_HOME")) { 00212 path = getenv("XMLBLASTER_HOME"); 00213 if (!path.empty()) 00214 num = readPropertyFile(path + FILE_SEP + filename, false); 00215 } 00216 } 00217 if (num > 0) { 00218 replaceVariables(true); 00219 } 00220 } 00221 00222 00223 int Property::readPropertyFile(const string &filename, bool overwrite) 00224 { 00225 ifstream in(filename.c_str()); 00226 string line, tmp; 00227 int count = 0; 00228 if (in == 0) return -1; 00229 std::cout << "Reading property file " << filename << std::endl; 00230 while (!in.eof()) { 00231 getline(in, tmp); 00232 StringTrim::trimEnd(tmp); 00233 if (tmp.size() > 0 && tmp[tmp.size()-1] == '\\') { 00234 line += tmp.substr(0,tmp.size()-1); 00235 continue; 00236 } 00237 line += tmp; 00238 if (!in.eof()) { 00239 pair<const string, string> valuePair(getPair(line)); 00240 if ((valuePair.first != "") && (valuePair.second != "")) { 00241 //std::cout << "readPropertyFile: " << valuePair.first << "=" << valuePair.second << std::endl; 00242 if (setProperty_(valuePair.first, valuePair.second, overwrite)) 00243 count++; 00244 } 00245 } 00246 line = ""; 00247 } 00248 in.close(); 00249 // if (count > 0) 00250 // std::cout << "Successfully read " << count << " entries from " << filename << std::endl; 00251 return count; 00252 } 00253 00254 00260 int 00261 Property::writePropertyFile(const char *filename) const 00262 { 00263 ofstream out(filename); 00264 int count = 0; 00265 if (out == 0) return count; 00266 MapType::const_iterator iter = properties_.begin(); 00267 while (iter != properties_.end()) { 00268 out << (*iter).first << "=" << (*iter).second << std::endl; 00269 iter++; 00270 count++; 00271 } 00272 out.close(); 00273 return count; 00274 } 00275 00283 string 00284 Property::getProperty(const string &name, bool env) 00285 { 00286 MapType::const_iterator iter = properties_.find(name); 00287 if (iter == properties_.end()) { 00288 if (!env) return ""; 00289 char* envStr = getenv(name.c_str()); 00290 if (envStr == 0) return ""; 00291 setProperty(name, envStr); 00292 return string(envStr); 00293 } 00294 return (*iter).second; 00295 } 00296 00297 00298 bool 00299 Property::propertyExists(const string &name, bool env) 00300 { 00301 MapType::const_iterator iter = properties_.find(name); 00302 if (iter == properties_.end()) { 00303 if (!env) return false; 00304 char* envStr = getenv(name.c_str()); 00305 if (envStr == 0) return false; 00306 setProperty(name, envStr); 00307 } 00308 return true; 00309 } 00310 00311 00312 int 00313 Property::getIntProperty(const string &name, int def, bool env) 00314 { 00315 string value = getProperty(name, env); 00316 if (value.length() == 0) return def; 00317 char *test = (char*)0; 00318 int ret = (int)strtol(value.c_str(), &test, 10); 00319 if (test == value.c_str()) return def; 00320 // int ret = lexical_cast<int>(value); 00321 return ret; 00322 } 00323 00324 long 00325 Property::getLongProperty(const string &name, long def, bool env) 00326 { 00327 string value = getProperty(name, env); 00328 if (value.empty()) return def; 00329 char *test = (char*)0; 00330 long ret = atol(value.c_str()); 00331 if (test == value.c_str()) return def; 00332 // long ret = lexical_cast<long>(value); 00333 return ret; 00334 } 00335 00336 Timestamp 00337 Property::getTimestampProperty(const string &name, Timestamp def, bool env) 00338 { 00339 string value = getProperty(name, env); 00340 if (value.length() == 0) return def; 00341 char *test = (char*)0; 00342 // Timestamp ret = STRING_TO_TIMESTAMP(value.c_str()); 00343 if (test == value.c_str()) return def; 00344 Timestamp ret = 0; 00345 try { 00346 lexical_cast<Timestamp>(value); 00347 } 00348 catch (...) { 00349 ret = 0; 00350 } 00351 return ret; 00352 } 00353 00354 bool 00355 Property::getBoolProperty(const string &name, bool def, bool env) 00356 { 00357 string value = getProperty(name, env); 00358 return StringTrim::isTrue(value, def); 00359 } 00360 00361 00362 string 00363 Property::getStringProperty(const string &name, const string &def, 00364 bool env) 00365 { 00366 string value = getProperty(name, env); 00367 if (value.length() == 0) return def; 00368 return value; 00369 } 00370 00371 00372 // private 00373 bool Property::setProperty_(const string &name, const string &value, 00374 bool overwrite) 00375 { 00376 MapType::iterator iter = properties_.find(name); 00377 if (iter != properties_.end()) { 00378 if (overwrite) (*iter).second = value; 00379 else return false; 00380 } 00381 else { 00382 pair<const string, string> valuePair(name, value); 00383 properties_.insert(valuePair); 00384 } 00385 return true; 00386 } 00387 00388 bool Property::setProperty(const string &name, const string &value, 00389 bool overwrite) 00390 { 00391 string newValue = replaceVariable(name, value, true); 00392 bool ret = setProperty_(name, newValue, overwrite); 00393 return ret; 00394 } 00395 00396 00401 bool Property::getTypedProperty(const string& name, string& value, bool env) 00402 { 00403 if (!propertyExists(name, env)) return false; 00404 value = getStringProperty(name, "", env); 00405 return true; 00406 } 00407 00408 bool Property::getTypedProperty(const string& name, int& value, bool env) 00409 { 00410 if (!propertyExists(name, env)) return false; 00411 value = getIntProperty(name, 0, env); 00412 return true; 00413 } 00414 00415 bool Property::getTypedProperty(const string& name, long& value, bool env) 00416 { 00417 if (!propertyExists(name, env)) return false; 00418 value = getLongProperty(name, 0, env); 00419 return true; 00420 } 00421 00422 bool Property::getTypedProperty(const string& name, bool& value, bool env) 00423 { 00424 if (!propertyExists(name, env)) return false; 00425 value = getBoolProperty(name, false, env); 00426 return true; 00427 } 00428 00429 #if __LP64__ 00430 // long === long long === 64 bit 00431 #else 00432 bool Property::getTypedProperty(const string& name, Timestamp& value, bool env) 00433 { 00434 if (!propertyExists(name, env)) return false; 00435 value = getTimestampProperty(name, 0, env); 00436 return true; 00437 } 00438 #endif 00439 00440 std::string Property::toXml(const std::string& extraOffset) 00441 { 00442 string offset = Constants::OFFSET + extraOffset; 00443 string sb; 00444 MapType::const_iterator it; 00445 sb += offset; 00446 sb += "<Property>"; 00447 for (it=properties_.begin(); it!=properties_.end(); ++it) { 00448 const string& key = (*it).first; 00449 const string& value = (*it).second; 00450 sb += offset + Constants::INDENT; 00451 sb += "<" + key + ">" + value + "</" + key + ">"; 00452 } 00453 sb += offset; 00454 sb += "</Property>"; 00455 return sb; 00456 } 00457 00458 void Property::replaceVariables(bool env) { 00459 MapType::const_iterator it; 00460 for (it=properties_.begin(); it!=properties_.end(); ++it) { 00461 const string& key = (*it).first; 00462 const string& value = (*it).second; 00463 const string newValue = replaceVariable(key, value, env); 00464 if (value != newValue) { 00465 properties_[key] = newValue; 00466 } 00467 } 00468 } 00469 00470 string Property::replaceVariable(const string &/*key*/, const string &valueOrig, bool env) { 00471 //if (replaceVariables == false) 00472 // return value; 00473 string value = valueOrig; 00474 string origValue = value; 00475 string tok = "${"; 00476 string endTok = "}"; 00477 for (int ii = 0;; ii++) { 00478 string::size_type from = value.find(tok); 00479 if (from != string::npos) { 00480 string::size_type to = value.find(endTok, from); 00481 if (to == string::npos) { 00482 //std::cout << "Property.InvalidVariable: Invalid variable '" << value.substr(from) << "', expecting ${} syntax." << std::endl; 00483 } 00484 string sub = value.substr(from, to + endTok.size() - from); // "${XY}" 00485 string subKey = sub.substr(tok.size(), sub.length() - endTok.size() - tok.size()); // "XY" 00486 string subValue = getProperty(subKey, env); 00487 if (subValue.empty()) { 00488 //if (verbose>=2) std::cout << "Property: Unknown variable " << sub << " is not replaced" << std::endl; 00489 return value; 00490 } 00491 value = StringTrim::replaceAll(value, sub, subValue); 00492 } 00493 else { 00494 //if (ii > 0 && verbose>=2) { 00495 // std::cout << "Property: Replacing '" << key << "=" << origValue << "' to '" << value << "'" << std::endl; 00496 //} 00497 return value; 00498 } 00499 if (ii > MAX_NEST) { 00500 //if (verbose>=1) std::cout << "Property: Maximum nested depth of " << MAX_NEST << " reached for variable '" << getProperty(key, env) << "'." << std::endl; 00501 return value; 00502 } 00503 } 00504 } 00505 00506 00507 #endif