00001 #ifndef s11n_net_s11nlite_CLIENT_API_HPP_INCLUDED 00002 #define s11n_net_s11nlite_CLIENT_API_HPP_INCLUDED 1 00003 //////////////////////////////////////////////////////////////////////// 00004 // License: Do As You Damned Well Please 00005 // Author: stephan@s11n.net 00006 00007 #include <memory> // auto_ptr 00008 #include <iterator> // insert_interator<> 00009 00010 #include <s11n.net/s11n/s11n.hpp> // the core s11n framework 00011 #include <s11n.net/s11n/io/data_node_io.hpp> // s11n::io::data_node_serializer interface 00012 #include <s11n.net/s11n/io/serializers.hpp> // create_serializer() 00013 #include <s11n.net/s11n/mutex.hpp> 00014 namespace s11nlite { 00015 00016 /** 00017 client_api is an abstraction of the 1.0.x s11nlite 00018 interface (GAWD, NOT ANOTHER ABSTRACTION LAYER!), providing 00019 an interface which works with all compatible S11n Node 00020 types. 00021 00022 The intention of this class is for projects to have easy 00023 access to an s11nlite-like interface for their own node 00024 types. s11nlite, as of s11n 1.2, will be based off of 00025 this type. 00026 00027 Another use of this class is in conjunction with 00028 s11n::fac::instance_hook: clients may specialize that type 00029 to make this type's instance() function return a custom 00030 client_api object. The intention of this feature is to allow 00031 clients to extend the s11nlite interface "from inside" while 00032 allowing client code to keep using the s11nlite interface. 00033 This allows, amongst other things, extending s11nlite 00034 to support special i/o channels (as provided, e.g., 00035 by pclasses.com's libraries) without actually touching 00036 s11nlite. See http://s11n.net/ps11n/ for where this is 00037 headed... 00038 00039 Particularly observant users might notice that many of this 00040 type's functions which "probably should be" const are not 00041 const. This is because subclasses are encouraged to add 00042 features behind the basic API, and many would not be 00043 practical without a non-const object. As an example, a 00044 subclass might want to do DLL lookups and may need to 00045 modify internal tables when it does so. Template functions 00046 which can be made const are const. This would appear to be 00047 inconsistent, but it is in fact me trying to make up for 00048 more of the API not being const. 00049 00050 The NodeType parameterized type must be compatible with the 00051 s11n's "Data Node" type conventions (e.g., 00052 s11n::s11n_node). 00053 00054 00055 Clients may notice that not much of this API is 00056 virtual. That's not because i'm anal, but because most of 00057 the API is template functions, and those can't be virual. 00058 00059 While this type's interface does not require it, it is 00060 believed that all of the member functions of client_api's 00061 base implementation are thread-safe and reentrant EXCEPT 00062 for the serializer_class() getter/setter pair. Even with 00063 thread locking, there are a lot of possible race conditions 00064 regarding setting that value and fetching it. Since the 00065 setter is rarely used (typically once per application), 00066 this is not considered to be a serious problem. 00067 00068 TODOs: 00069 00070 - Figure out how best to accomodate the 00071 serializer_interface type as a template parameter. Right 00072 now that's not feasible because the API depends too much on 00073 the s11n::io namespace in general. 00074 */ 00075 template <typename NodeType> 00076 class client_api 00077 { 00078 private: 00079 /** Class name of preferred serializer type. */ 00080 std::string m_serclass; 00081 mutable s11n::mutex m_mutex; 00082 public: 00083 00084 client_api() 00085 : m_serclass(s11n_S11NLITE_DEFAULT_SERIALIZER_TYPE_NAME /* defined in s11n_config.hpp */ ), 00086 m_mutex() 00087 { 00088 } 00089 00090 explicit client_api( const std::string & default_serializer_class ) 00091 : m_serclass(default_serializer_class), 00092 m_mutex() 00093 { 00094 } 00095 00096 virtual ~client_api() 00097 { 00098 } 00099 00100 /** 00101 node_type is the type used to store/load a Serializable 00102 object's data. 00103 */ 00104 typedef NodeType node_type; 00105 00106 /** The s11n::node_traits type for node_type. */ 00107 typedef s11n::node_traits<node_type> node_traits; 00108 00109 00110 /** 00111 This is the base-most type of the serializers used by s11nlite clients. 00112 */ 00113 typedef s11n::io::data_node_serializer<node_type> serializer_interface; 00114 00115 00116 /** 00117 Returns create_serialize( serializer_class() ). 00118 The caller owns the returned pointer. 00119 */ 00120 inline serializer_interface * create_serializer() 00121 { 00122 s11n::mutex_sentry lock(this->m_mutex); 00123 return this->create_serializer( this->m_serclass ); 00124 } 00125 00126 /** 00127 Returns a new instance of the given serializer class, or 0 00128 if one could not be loaded. classname must represent a subtype 00129 of serializer_interface. 00130 00131 The caller owns the returned pointer. 00132 00133 You can also pass a serializer's cookie here, and that 00134 should return the same thing as it's class name would. 00135 00136 The internally-supported serializers all register a 00137 "friendly form" of the name, an alias registered 00138 with their classloader. Passing either this name or 00139 the cookie of the Serializer should return the same 00140 thing as the classname itself would. 00141 00142 Subclasses may do, e.g., lookups for 00143 externally-linked serializers. 00144 */ 00145 virtual serializer_interface * 00146 create_serializer( const std::string & classname ) 00147 { 00148 return ::s11n::io::create_serializer<node_type>( classname ); 00149 } 00150 00151 00152 /** 00153 Sets the current Serializer class used by s11nlite's 00154 create_serializer(). Pass it a class name, or one of 00155 the convenience names, e.g.: 00156 00157 compact, funtxt, funxml, simplexml, parens, wesnoth, 00158 and expat (if your s11n was built with it). 00159 00160 You may use provides_serializer() to check for the 00161 existence of a class. This function does no 00162 validation of classname: this is delayed until 00163 save/load-time, to allow for DLL lookups during the 00164 normal classloading process (as opposed to 00165 duplicating that check here). 00166 */ 00167 inline void serializer_class( const std::string & classname ) 00168 { 00169 s11n::mutex_sentry lock(this->m_mutex); 00170 // ^^^ keep m_serclass from changing during create_serializer() 00171 this->m_serclass = classname; 00172 } 00173 00174 00175 /** 00176 Gets the name of the current Serializer type. 00177 */ 00178 inline std::string serializer_class() const 00179 { 00180 return this->m_serclass; 00181 } 00182 00183 /** 00184 Returns true if key can be used to create a Serializer 00185 object via a call to serializer_class(). Subclasses 00186 may do additional work here, like look up DLLs, which is 00187 why the function is not const. 00188 */ 00189 virtual bool provides_serializer( const std::string & key ) 00190 { 00191 typedef ::s11n::fac::factory_mgr<serializer_interface> FacMgr; 00192 return FacMgr::instance().provides( key ); 00193 } 00194 00195 00196 /** 00197 See s11n::serialize(). 00198 */ 00199 template <typename SerializableType> 00200 inline bool serialize( node_type & dest, const SerializableType & src ) const 00201 { 00202 return s11n::serialize<node_type,SerializableType>( dest, src ); 00203 } 00204 00205 /** 00206 See s11n::serialize_subnode(). 00207 */ 00208 template <typename SerializableType> 00209 inline bool serialize_subnode( node_type & dest, const std::string & subnodename, const SerializableType & src ) const 00210 { 00211 // todo: consider custom-implementing to go through the local de/serialize() funcs. 00212 // The end result would be the same, since those funcs aren't virtual and we know 00213 // in advance that they will behave exactly the same as this approach. 00214 // return s11n::serialize_subnode<node_type,SerializableType>( dest, subnodename, src ); 00215 // Nevermind... we can't. If we do, then (SerializableType*) is not forwarded properly 00216 // without some additional type juggling. 00217 std::auto_ptr<node_type> n( node_traits::create( subnodename ) ); 00218 if( this->serialize<SerializableType>( *n, src ) ) 00219 { 00220 node_traits::children(dest).push_back( n.release() ); 00221 return true; 00222 } 00223 return false; 00224 00225 } 00226 00227 00228 /** 00229 Saves the given node to the given ostream using the default 00230 serializer type. 00231 00232 Returns true on success, false on error. 00233 00234 ONLY use this for saving root nodes! 00235 */ 00236 virtual bool save( const node_type & src, std::ostream & dest ) 00237 { 00238 std::auto_ptr<serializer_interface> s(this->create_serializer()); 00239 return s.get() 00240 ? s->serialize( src, dest ) 00241 : false; 00242 } 00243 00244 /** 00245 Saves the given node to the given filename using the default 00246 serializer type. 00247 00248 Returns true on success, false on error. 00249 00250 ONLY use this for saving root nodes! 00251 00252 Subclasses are free to interpret the filename 00253 however they like, e.g., as a URL or database 00254 record name. 00255 */ 00256 virtual bool save( const node_type & src, const std::string & filename ) 00257 { 00258 std::auto_ptr<serializer_interface> s(this->create_serializer()); 00259 return s.get() 00260 ? s->serialize( src, filename ) 00261 : false; 00262 // Maintenance note: we used to just convert 00263 // filename to a stream and call this->save( 00264 // src, ostr ), but this poses a problem with 00265 // serializers, like mysql_serializer, which 00266 // behave differently in the face of streams 00267 // and filenames. Currently (1.1.3) 00268 // mysql_serializer is the only one which 00269 // needs this distinction (because it can't 00270 // write db records to a stream). The experimental 00271 // ps11n support also distinguishes, as it supports 00272 // serialization over ftp URLs. 00273 } 00274 00275 00276 /** 00277 Saves the given Serializable to the given ostream using the default 00278 serializer type. 00279 Returns true on success, false on error. 00280 00281 ONLY use this for saving root nodes! 00282 00283 Subclassers: this function serializes src to a node and then 00284 calls save(node,dest). 00285 */ 00286 template <typename SerializableType> 00287 inline bool save( const SerializableType & src, std::ostream & dest ) 00288 { 00289 node_type n; 00290 return this->serialize( n, src ) 00291 ? this->save( n, dest ) 00292 : false; 00293 } 00294 /** 00295 00296 Saves the given Serializable to the given filename using the default 00297 serializer type. 00298 00299 Returns true on success, false on error. 00300 00301 ONLY use this for saving root nodes! 00302 00303 Subclassers: this function serializes src to a node and then 00304 calls save(node,dest). 00305 */ 00306 template <typename SerializableType> 00307 bool save( const SerializableType & src, const std::string & dest ) 00308 { 00309 // See save(node,string) for why we don't wan this: 00310 // typedef std::auto_ptr<std::ostream> AP; 00311 // AP os = AP( s11n::io::get_ostream( dest ) ); 00312 // if( ! os.get() ) return 0; 00313 // return this->save( src, *os ); 00314 node_type n; 00315 return this->serialize( n, src ) 00316 ? this->save( n, dest ) 00317 : false; 00318 } 00319 00320 /** 00321 Tries to load a node from the given filename. 00322 00323 The caller owns the returned pointer. 00324 00325 Subclasses are free to interpret the filename 00326 however they like, e.g., as a URL or database 00327 record name. 00328 */ 00329 virtual node_type * load_node( const std::string & src ) 00330 { 00331 return s11n::io::load_node<node_type>( src ); 00332 } 00333 00334 00335 /** 00336 Tries to load a node from the given input stream. 00337 00338 The caller owns the returned pointer, which may be 00339 0. 00340 00341 Only usable for loading ROOT nodes. 00342 */ 00343 virtual node_type * load_node( std::istream & src ) 00344 { 00345 return s11n::io::load_node<node_type>( src ); 00346 } 00347 00348 00349 00350 /** 00351 Returns s11n::deserialize<node_type,SerializableType>(src). 00352 00353 Caller owns the returned pointer, which may be 0. 00354 00355 Note that this function is non-const because deserialization 00356 may indirectly classload other types or affect this object. 00357 00358 See the one-argument variant of s11n::deserialize() for 00359 IMPORTANT error-handling considerations for this function. 00360 */ 00361 template <typename SerializableType> 00362 inline SerializableType * deserialize( const node_type & src ) const 00363 { 00364 return s11n::deserialize<node_type,SerializableType>( src ); 00365 } 00366 00367 00368 00369 /** 00370 See s11n::deserialize(). 00371 */ 00372 template <typename DeserializableT> 00373 inline bool deserialize( const node_type & src, DeserializableT & target ) const 00374 { 00375 return s11n::deserialize<node_type,DeserializableT>( src, target ); 00376 } 00377 00378 00379 /** 00380 See s11n::deserialize_subnode(). 00381 */ 00382 template <typename DeserializableT> 00383 inline bool deserialize_subnode( const node_type & src, const std::string & subnodename, DeserializableT & target ) const 00384 { 00385 return s11n::deserialize_subnode< node_type, DeserializableT >( src, subnodename, target ); 00386 } 00387 00388 /** 00389 See s11n::deserialize_subnode(). 00390 */ 00391 template <typename DeserializableT> 00392 inline DeserializableT * deserialize_subnode( const node_type & src, const std::string & subnodename ) const 00393 { 00394 return s11n::deserialize_subnode< node_type, DeserializableT >( src, subnodename ); 00395 } 00396 00397 00398 /** 00399 Tries to load a data_node from src, then deserialize that 00400 to a SerializableType. 00401 */ 00402 template <typename SerializableType> 00403 inline SerializableType * load_serializable( std::istream & src ) 00404 { 00405 std::auto_ptr<node_type> n( this->load_node( src ) ); 00406 return n.get() 00407 ? this->deserialize<SerializableType>( *n ) 00408 : 0; 00409 } 00410 00411 /** 00412 Overloaded form which takes a file name. 00413 00414 1.1.3: removed the never-used 2nd parameter. 00415 00416 Subclassers: the loading is done via load_node(), 00417 so you can intercept the src string there. 00418 */ 00419 template <typename SerializableType> 00420 inline SerializableType * load_serializable( const std::string & src ) 00421 { 00422 std::auto_ptr<node_type> node( this->load_node(src) ); 00423 return node.get() 00424 ? this->deserialize<SerializableType>( *node ) 00425 : 0; 00426 } 00427 00428 /** 00429 See s11n::s11n_clone(). 00430 */ 00431 template <typename SerializableType> 00432 inline SerializableType * clone( const SerializableType & tocp ) const 00433 { 00434 return s11n::s11n_clone<node_type,SerializableType>( tocp ); 00435 } 00436 00437 /** 00438 See s11n::s11n_cast(). 00439 */ 00440 template <typename Type1, typename Type2> 00441 inline bool cast( const Type1 & t1, Type2 & t2 ) const 00442 { 00443 // Hmmmm.... should we jump directly to s11n_cast() or perform that same 00444 // operation using our de/serialize() API???? 00445 // They aren't necessarily equivalent, and the inconsistency might come 00446 // to light one day. i can't imagine a use case, but there's gotta 00447 // be one. 00448 // node_type n; 00449 // return this->serialize<Type1>( n, t1 ) && this->deserialize<Type2>( n, t2 ); 00450 return ::s11n::s11n_cast<node_type,Type1,Type2>( t1, t2 ); 00451 } 00452 00453 /** 00454 Returns a shared instance of this class. The object 00455 itself is post-main() safe (on most systems), 00456 meaning if this function is called after the shared 00457 object is destroy (after main() exits), it "should" 00458 actually behave properly be re-instantiating the 00459 object in-place. See s11n/phoenix.hpp for details 00460 and caveats. In the worst case, it's no less safe than 00461 any other post-main() object. 00462 */ 00463 static client_api<node_type> & 00464 instance() 00465 { 00466 return ::s11n::Detail::phoenix< client_api<node_type> >::instance(); 00467 } 00468 00469 }; // client_api<> class 00470 00471 } // namespace s11nlite 00472 00473 #endif // s11n_net_s11nlite_CLIENT_API_HPP_INCLUDED