00001 /* $Id: db_property.hh,v 1.12 2003/07/24 23:08:35 reed Exp $ */ 00002 00003 /* 00004 @file db_property.hh 00005 00006 Defines interface for property with database backend. 00007 00008 Copyright (C) 2001, 2002 Reed Hedges 00009 00010 This library is free software; you can redistribute it and/or 00011 modify it under the terms of the GNU Lesser General Public 00012 License as published by the Free Software Foundation; either 00013 version 2 of the License, or (at your option) any later version. 00014 00015 This library is distributed in the hope that it will be useful, 00016 but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 Lesser General Public License for more details. 00019 00020 You should have received a copy of the GNU Lesser General Public 00021 License along with this library; if not, write to the Free Software 00022 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00023 00024 */ 00025 #ifndef _DB_PROPERTY_HH_ 00026 #define _DB_PROPERTY_HH_ 00027 00028 #include <string> 00029 #include "property.hh" 00030 00031 00032 00033 /** @class DBProperty db_property.hh vos/metaobjects/property/db_property.hh 00034 * 00035 * General database-backend interface. By itself this doesn't do anything; 00036 use a subclass like PGDBProperty (For Postgres databases). This class 00037 is intended to be subclassed in order to implement VOS/database 00038 bridges with various SQL-based database systems. Subclasses will 00039 have to implement the actual updateToDB() and updateFromDB(), and 00040 methods, and the open() method to connect to the database. 00041 See database-specific classes for full usage details but the basic idea 00042 is that the constructor should open a connection to the database, 00043 and create the associated table and columns if they don't exist, 00044 or just fetch the existing values if they do. 00045 write() and replace() immediately update the database with new data, 00046 but read() only returns cached data. updateFromDB() 00047 will get values from the database and replace cached data, and send 00048 property-update messages to all property listeners and remote objects. 00049 Some mechanism should be set up to call this function when necesary 00050 If the database backend has no such functionality, then 00051 the the subclass should extend read() to do an update before a read, 00052 and also periodically call updateFromDB() in case it changes. 00053 00054 Use init() to set up the queries used to read and write to the database. 00055 00056 00057 Subclasses of DBProperty should open the database connection (in init), and 00058 actually do the communication with the database. 00059 */ 00060 class DBProperty : public virtual LocalProperty 00061 { 00062 00063 protected: 00064 00065 /* Query strings for getting stuff from the database. */ 00066 string select_data_query; 00067 string select_type_query; 00068 string select_all_query; 00069 00070 /* Query strings for setting stuff in the database. */ 00071 string update_data_query; 00072 string update_type_query; // this is really not needed, because type is only updated on replace, and we should use update_all for that. but for now... 00073 string update_all_query; 00074 00075 /* If this isn't empty (""), then this contains the constant datatype. */ 00076 string force_type; 00077 00078 public: 00079 00080 00081 /** Database Access Error exception */ 00082 class DBAccessError : public runtime_error { 00083 public: DBAccessError(const string& w) : runtime_error(w){}; 00084 }; 00085 00086 00087 /** basic constructor */ 00088 DBProperty(MetaObject *superobject) : LocalProperty(superobject), Property(superobject), MetaObject(superobject) { 00089 // lala 00090 } 00091 00092 00093 /** called by factory to create a new instance */ 00094 static MetaObject* new_DBProperty(MetaObject* superobject, const string& type) { 00095 return new DBProperty(superobject); 00096 } 00097 00098 /** Register MetaObject extender for DBProperty. You must also call Property::registerExtenders() for stuff to work!. 00099 */ 00100 static void registerExtenders() { 00101 LocalSite::addLocalObjectExtension(typeid(DBProperty).name(), &DBProperty::new_DBProperty); 00102 } 00103 00104 /** Set up query strings, for getting or changing just data, with constant 00105 data type. 00106 @param select_query Query for getting just data. Must return scalar. 00107 @param update_query Query for setting the data. %d is replaced with the new data. 00108 @param type Data type to always use. 00109 */ 00110 00111 virtual void init(const string& select_query, const string& update_query, const string& type); 00112 00113 /** Set up query strings, for getting or changing both data value and data type. 00114 In the update queries, %d will 00115 be replaced by property data, and %t will be replaced by the datatype. 00116 These query strings should be in the format applicable to the 00117 implementation subclass you are using. 00118 @param select_all_q Query for getting data and type. (in that order) 00119 @param select_data_q Query for getting just data. 00120 @param select_type_q Query for getting type. 00121 @param update_all_q Query for changing data and type. %d will be replaced by property data, and %t with type 00122 @param update_data_q Query for changing data. %d will be replaced by data. 00123 @param update_type_q Query for changing type. Eventually will be removed, in favor of the update_all query @deprecated. 00124 */ 00125 virtual void init(const string& select_all_q, const string& select_data_q, const string& select_type_q, const string& update_all_q, const string& update_data_q, const string& update_type_q) ; 00126 00127 /** Use given values to construct standard (I think) SQL query strings. 00128 @warning may be broken; untested by author; use at own risk..... but then send a patch, please :) 00129 @param table Name of the table we are interested in. 00130 @param name_col Column in the table used as primary key when looking up data. 00131 @param val_col Column containing property value. 00132 @param type_col Column containing property data type. 00133 @param name_val Value to use to identify this property in the database, as primary key. 00134 */ 00135 void init_components(const string& table, const string& name_col, const string& val_col, const string& type_col, const string& name_val) ; 00136 00137 /** change property data, starting at given byte (updated in DB) */ 00138 virtual void write(int start, const string& newdata) throw(DBAccessError) { 00139 LocalProperty::write(start, newdata); 00140 updateToDB(); 00141 } 00142 00143 /** change all the property data, and datatype (updated in DB) */ 00144 virtual void replace(const string& newdata, const string& newtype = "?") throw(DBAccessError) { 00145 LocalProperty::replace(newdata, newtype); 00146 updateToDB(); 00147 } 00148 00149 00150 /** open database. this method must be overridden in implementation subclasses. */ 00151 virtual void open(string dbinfo = "") { 00152 cout << "** OPEN: " << dbinfo << "\n"; 00153 } 00154 00155 /** perform a query on the database (in the implementation's language; e.g. SQL) This method must be overridden in implementation subclasses. This method 00156 may throw range_error if there is an error in the query-string substiution. 00157 TODO: how shall non-scalars be returned? 00158 */ 00159 00160 virtual string queryDB(const string& query) throw(DBAccessError) { 00161 cout << "** QUERY: " << query << "\n"; 00162 return "**UNIMPLEMENTED**"; 00163 } 00164 00165 /** fetch stuff from database and do a replace. */ 00166 virtual void updateFromDB() throw(DBAccessError) ; 00167 00168 /** write current data and type to DB. */ 00169 virtual void updateToDB() throw(DBAccessError) ; 00170 00171 00172 00173 private: 00174 /* Do replacement of substring key with value on s. Note: only replaces the first key in s. 00175 throws range_error exception if key is not found in s. 00176 */ 00177 static string sreplace( const string& s, const string& key, const string& value) throw (range_error); 00178 00179 }; 00180 00181 00182 #endif