1 /*----------------------------------------------------------------------------
  2 Name:      Property.h
  3 Project:   xmlBlaster.org
  4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
  5 Comment:   Class used to read, store & write (java) properties.
  6 -----------------------------------------------------------------------------*/
  7 #ifndef _UTIL_PROPERTY_H
  8 #define _UTIL_PROPERTY_H
  9 
 10 #include <util/xmlBlasterDef.h>
 11 #include <map>
 12 #include <string>
 13 
 14 namespace org { namespace xmlBlaster {
 15 namespace util {
 16 
 17    /**
 18     * The class Property does handle properties in the java-way. It does not
 19     * throw any exception. Errors in file-reading, writing etc. are handled
 20     * by returning a special value (which for integers is zero and for bool
 21     * is false and empty std::strings for std::strings.
 22     * <br />
 23     * When reading or writing, comments and empty lines are ignored.
 24     * When writing, properties are written in alphabetical order (of the 
 25     * property name).
 26     * <br />
 27     * In properties like <code>SomeValue-${xy}-somePostValue</code> the <code>${}</code>
 28     * are replaced by the value of <code>xy</code>.
 29     * <br />
 30     * Fills during construction the properties <code>user.home</code> and
 31     * <code>file.separator</code> and <code>path.separator</code> and others
 32     * as described at method <code>initializeDefaultProperties()</code>.
 33     * This simplifies the reuse of the xmlBlaster.properties
 34     * which uses those settings from the Java environment.
 35     */
 36    class Dll_Export Property {
 37       
 38       public: typedef std::map<std::string, std::string, std::less<std::string> > MapType;
 39   
 40    private:
 41       MapType properties_;
 42       
 43       /**
 44        * Replace all ${...} variables in value. 
 45        * @param key The property key
 46        * @param value the corresponding value
 47        * @param env If true the environment is scanned as well
 48        */
 49       std::string replaceVariable(const std::string &key, const std::string &value, bool env);
 50 
 51       /**
 52        * Set a property without replacing ${...} variables in value. 
 53        * @return false if an old entry existed which was not overwritten
 54        */
 55       bool setProperty_(const std::string &name, const std::string &value,
 56                        bool overwrite=true);
 57 
 58       /**
 59        * Initialize some default properties, similar to the java virtual machine. 
 60        * Add some predefined variables to be useful in xmlBlaster.properties as ${user.home} etc:
 61        * <pre>
 62        * user.home       For example "/home/marcel"
 63        * user.name       Your login name on the OS.
 64        * java.io.tmpdir  The temporary directory of your OS.
 65        * file.separator  On UNIX "/", on Windows "\"
 66        * path.separator  On UNIX ":", on Windows ";"
 67        * </pre>
 68        */
 69       void initializeDefaultProperties();
 70 
 71    protected:
 72       /**
 73        * returns true if the line is a comment, or if it is empty. Returns
 74        * false if the line is a possible property line. "Possible" in the sense
 75        * that its validity is not checked yet.
 76        */
 77       bool isComment(const std::string &line) const {
 78          if (line.length() == 0) return false;
 79          return (line.c_str()[0] == '#');
 80       }
 81       
 82       /**
 83        * Filters (throws away) all whitespaces from the specified std::string.
 84        */
 85       std::string filter(const std::string &line) const {
 86          std::string ret;
 87          for (std::string::size_type i=0; i<line.length(); i++) {
 88             if (line.c_str()[i] != ' ') ret += line.c_str()[i];
 89          }
 90          return ret;
 91       }
 92 
 93       
 94       /**
 95        * gets the property in the line specified in the argument list. It 
 96        * returns this property as a pair name,value. If the line does not
 97        * contain a valid property(for example if the = sign is not present)
 98        * then a pair of empty std::strings is returned.
 99        */
100       std::pair<const std::string, std::string> getPair(const std::string &line) const {
101          std::string::size_type pos = line.find("=");
102          if ((pos < 2) || (pos >= line.length()) || (isComment(line)) ) {
103             return std::pair<const std::string, std::string>("","");
104          }
105          std::string name, value;
106          name.assign(line, 0, pos);
107          value = line.substr(pos+1);
108          return std::pair<const std::string, std::string>(filter(name), filter(value));
109       }
110       
111       
112    public:
113       
114       /**
115        * The default constructor allocate the storage
116        * std::map for the properties and parses the command line properties.<p />
117        * NOTE: You have to call loadPropertyFile() separatly
118                  * @param args Length of argv
119                  * @param argv The command line arguments, for example "-protocol SOCKET"
120        */
121       Property(int args=0, const char * const argv[]=0);
122 
123       /**
124        * Initialize with the given key/value std::map. 
125        * NOTE: You have to call loadPropertyFile() separately
126        * @param propertyMap A std::map which contains key and values pairs,
127        *                    for example key="protocol" and value="SOCKET"
128        */
129       Property(MapType propMap);
130 
131       /*
132        * xmlBlaster.properties is searched in this sequence:
133        * <ul>
134        *    <li>the command line parameter '-propertyFile', e.g. "-propertyFile /tmp/xy.properties"</li>
135        *    <li>the environment variable 'propertyFile', e.g. "propertyFile=/tmp/xy.properties"</li>
136        *    <li>the local directory: ./xmlBlaster.properties</li>
137        *    <li>in your home directory, HOME/xmlBlaster.properties</li>
138        *    <li>in the $XMLBLASTER_HOME directory</li>
139        * </ul>
140        * Command line properties have precedence<p />
141        * Environment variables are weakest
142        */
143       void loadPropertyFile();
144       
145 
146       ~Property() {
147          properties_.erase(properties_.begin(), properties_.end());
148       }
149 
150       /**
151        * Replace all ${...} variables in value. 
152        * @param env If true the environment is scanned as well
153        */
154       void replaceVariables(bool env);
155 
156       const MapType& getPropertyMap() const {
157          return properties_;
158       }
159 
160       /**
161        * Reads the file specified in filename. If the name is not valid, or if
162        * the system can not write to the specified file, then -1 is returned.
163        * If you specify overwrite=true (the default) then the properties read
164        * from the file are inserted into the properties even if a property 
165        * with the same name has been defined earlier. 
166        * <p />
167        * Note: The ${...} tokens are not replaced in this method
168        */
169       int readPropertyFile(const std::string &filename, bool overwrite=true);
170       
171 
172       /**
173        * writes the properties to a file specified in the argument list. If it
174        * could not write to the file, a zero is returned.
175        * Returns the number of properties written to the file.
176        */
177       int writePropertyFile(const char *filename) const ;
178 
179 
180       /**
181        * Gets the propety with the specified name. If no such property exists,
182        * an empty std::string is returned. If the std::string is not found, it searches
183        * in among the environment variables (only if env is set to true which
184        * is the default). In the property is not found there either, it returns
185        * an empty std::string.
186        */
187       std::string getProperty(const std::string &name, bool env=true);
188 
189 
190       bool propertyExists(const std::string &name, bool env=true);
191 
192 
193       int get(const std::string &name, int def) { return getIntProperty(name, def, false); }
194       int getIntProperty(const std::string &name, int def, bool env=true);
195 
196       long get(const std::string &name, long def) { return getLongProperty(name, def, false); }
197       long getLongProperty(const std::string &name, long def, bool env=true);
198 
199       org::xmlBlaster::util::Timestamp getTimestampProperty(const std::string &name, org::xmlBlaster::util::Timestamp def, bool env=true);
200 
201       bool get(const std::string &name, bool def) { return getBoolProperty(name, def, false); }
202       bool getBoolProperty(const std::string &name, bool def, bool env=true);
203 
204 
205       std::string get(const std::string &name, const char *def) { std::string defS=def; return getStringProperty(name, defS, false); }
206       std::string get(const std::string &name, const std::string &def) { return getStringProperty(name, def, false); }
207       std::string getStringProperty(const std::string &name, const std::string &def, 
208                             bool env=true);
209 
210       /**
211        * To allow templatized getting of properties. It returns true if the property has been found. In that
212        * case, the return value is put into the 'value' argument.
213        */
214       bool getTypedProperty(const std::string& name, std::string& value, bool env=true);
215       bool getTypedProperty(const std::string& name, int& value, bool env=true);
216       bool getTypedProperty(const std::string& name, long& value, bool env=true);
217       bool getTypedProperty(const std::string& name, bool& value, bool env=true);
218 #     if __LP64__
219       // long === long long === 64 bit
220 #     else
221       bool getTypedProperty(const std::string& name, org::xmlBlaster::util::Timestamp& value, bool env=true);
222 #     endif
223         
224        bool setProperty(const std::string &name, const std::string &value,
225                        bool overwrite=true);
226  
227       /**
228        * Loads the properties read from the command line (or another array).
229        * The syntax for passing properties is the same as in java if the 
230        * switch javaStyle is true (default). That is "-Dprop1=val1" is 
231        * then equivalent as prop1=val1 in a property file. If the switch 
232        * javaStyle is false, then the Corba style is chosen, i.e. the 
233        * following is correct syntax: "-ORBNameService whatever" (so no
234        * equality sign between name and value).
235        * Errors in syntax are silently ignored (the property just isn't load).
236        *
237        * @param args The length of argv[]
238        * @param argv The command line arguments, argv[0] is the executable name,
239        *             for example { "HelloWorld2" "-trace" "true" }
240        * @param sep The property praefix, for example "-" for "-trace true"
241        */
242       int loadCommandLineProps(int args, const char * const argv[], const std::string &sep="-D", 
243                     bool javaStyle=true);
244       
245 
246       /**
247        * It searches in the argument list specified by argv the argument 
248        * specified by name. If nothing is found it returns -1, otherwise it
249        * returns the index of argv corresponding to what specified in name.
250        */
251       int findArgument(int args, const char * const argv[], const std::string &name) {
252          for (int i=1; i < args; i++) {
253             if (std::string(argv[i]) == name) return i;
254          }
255          return -1;
256       }
257       
258       std::string toXml(const std::string& extraOffset="");
259 
260    }; // class Property
261 
262 }}} // namespace
263 
264 #endif // _UTIL_PROPERTY_H
265 
266 
267       
268       


syntax highlighted by Code2HTML, v. 0.9.1