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 whole 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 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 There is a theoretical solution, for those wanting more 00059 control: subclass this type with another template type: 00060 serializable_api<SerializableType>. Then you can add virtual 00061 functions which take the place of the templated members. 00062 Not sure if overloading rules will let you get away with 00063 it, but it sounds halfway reasonable. 00064 00065 00066 TODOs: 00067 00068 - Figure out how best to accomodate the 00069 serializer_interface type as a template parameter. Right 00070 now that's not feasible because the API depends too much on 00071 the s11n::io namespace in general. 00072 */ 00073 template <typename NodeType> 00074 class client_api 00075 { 00076 private: 00077 /** Class name of preferred serializer type. */ 00078 std::string m_serclass; 00079 public: 00080 00081 client_api() : m_serclass(s11n_S11NLITE_DEFAULT_SERIALIZER_TYPE_NAME /* defined in s11n_config.hpp */ ) 00082 { 00083 } 00084 00085 explicit client_api( const std::string & default_serializer_class ) : m_serclass(default_serializer_class) 00086 { 00087 } 00088 00089 virtual ~client_api() 00090 { 00091 } 00092 00093 /** 00094 node_type is the type used to store/load a Serializable 00095 object's data. 00096 */ 00097 typedef NodeType node_type; 00098 00099 /** The s11n::node_traits type for node_type. */ 00100 typedef s11n::node_traits<node_type> node_traits; 00101 00102 00103 /** 00104 This is the base-most type of the serializers used by s11nlite clients. 00105 */ 00106 typedef s11n::io::data_node_serializer<node_type> serializer_interface; 00107 00108 00109 /** 00110 Returns create_serialize( serializer_class() ). 00111 The caller owns the returned pointer. 00112 */ 00113 inline serializer_interface * create_serializer() 00114 { 00115 return this->create_serializer( this->serializer_class() ); 00116 } 00117 00118 /** 00119 Returns a new instance of the given serializer class, or 0 00120 if one could not be loaded. classname must represent a subtype 00121 of serializer_interface. 00122 00123 The caller owns the returned pointer. 00124 00125 You can also pass a serializer's cookie here, and that 00126 should return the same thing as it's class name would. 00127 00128 The internally-supported serializers all register a 00129 "friendly form" of the name, an alias registered 00130 with their classloader. Passing either this name or 00131 the cookie of the Serializer should return the same 00132 thing as the classname itself would. 00133 00134 Subclasses may do, e.g., lookups for 00135 externally-linked serializers. 00136 */ 00137 virtual serializer_interface * 00138 create_serializer( const std::string & classname ) 00139 { 00140 return ::s11n::io::create_serializer<node_type>( classname ); 00141 } 00142 00143 00144 /** 00145 Sets the current Serializer class used by s11nlite's 00146 create_serializer(). Pass it a class name, or one of 00147 the convenience names, e.g.: 00148 00149 compact, funtxt, funxml, simplexml, parens, wesnoth, 00150 and expat (if your s11n was built with it). 00151 00152 You may use provides_serializer() to check for the 00153 existence of a class. This function does no 00154 validation of classname: this is delayed until 00155 save/load-time, to allow for DLL lookups during the 00156 normal classloading process (as opposed to 00157 duplicating that check here). 00158 */ 00159 inline void serializer_class( const std::string & classname ) 00160 { 00161 this->m_serclass = classname; 00162 } 00163 00164 00165 /** 00166 Gets the name of the current Serializer type. 00167 */ 00168 inline std::string serializer_class() const 00169 { 00170 return this->m_serclass; 00171 } 00172 00173 /** 00174 Returns true if key can be used to create a Serializer 00175 object via a call to serializer_class(). Subclasses 00176 may do additional work here, like look up DLLs, which is 00177 why the function is not const. 00178 */ 00179 virtual bool provides_serializer( const std::string & key ) 00180 { 00181 typedef ::s11n::fac::factory_mgr<serializer_interface> FacMgr; 00182 return FacMgr::instance().provides( key ); 00183 } 00184 00185 00186 /** 00187 See s11n::serialize(). 00188 */ 00189 template <typename SerializableType> 00190 inline bool serialize( node_type & dest, const SerializableType & src ) const 00191 { 00192 return s11n::serialize<node_type,SerializableType>( dest, src ); 00193 } 00194 00195 /** 00196 See s11n::serialize_subnode(). 00197 */ 00198 template <typename SerializableType> 00199 inline bool serialize_subnode( node_type & dest, const std::string & subnodename, const SerializableType & src ) const 00200 { 00201 // todo: consider custom-implementing to go through the local de/serialize() funcs. 00202 // The end result would be the same, since those funcs aren't virtual and we know 00203 // in advance that they will behave exactly the same as this approach. 00204 // return s11n::serialize_subnode<node_type,SerializableType>( dest, subnodename, src ); 00205 // Nevermind... we can't. If we do, then (SerializableType*) is not forwarded properly 00206 // without some additional type juggling. 00207 std::auto_ptr<node_type> n( node_traits::create( subnodename ) ); 00208 if( this->serialize<SerializableType>( *n, src ) ) 00209 { 00210 node_traits::children(dest).push_back( n.release() ); 00211 return true; 00212 } 00213 return false; 00214 00215 } 00216 00217 00218 /** 00219 Saves the given node to the given ostream using the default 00220 serializer type. 00221 00222 Returns true on success, false on error. 00223 00224 ONLY use this for saving root nodes! 00225 */ 00226 virtual bool save( const node_type & src, std::ostream & dest ) 00227 { 00228 std::auto_ptr<serializer_interface> s(this->create_serializer()); 00229 if( s.get() ) 00230 { 00231 return s->serialize( src, dest ); 00232 } 00233 else 00234 { 00235 return false; 00236 } 00237 } 00238 00239 /** 00240 Saves the given node to the given filename using the default 00241 serializer type. 00242 00243 Returns true on success, false on error. 00244 00245 ONLY use this for saving root nodes! 00246 00247 Subclasses are free to interpret the filename 00248 however they like, e.g., as a URL or database 00249 record name. 00250 */ 00251 virtual bool save( const node_type & src, const std::string & filename ) 00252 { 00253 std::auto_ptr<serializer_interface> s(this->create_serializer()); 00254 return s.get() 00255 ? s->serialize( src, filename ) 00256 : false; 00257 // Maintenance note: we used to just convert 00258 // filename to a stream and call this->save( 00259 // src, ostr ), but this poses a problem with 00260 // serializers, like mysql_serializer, which 00261 // behave differently in the face of streams 00262 // and filenames. Currently (1.1.3) 00263 // mysql_serializer is the only one which 00264 // needs this distinction (because it can't 00265 // write db records to a stream). The experimental 00266 // ps11n support also distinguishe, as it supports 00267 // serialization over ftp URLs. 00268 } 00269 00270 00271 /** 00272 Saves the given Serializable to the given ostream using the default 00273 serializer type. 00274 Returns true on success, false on error. 00275 00276 ONLY use this for saving root nodes! 00277 00278 Subclassers: this function serializes src to a node and then 00279 calls save(node,dest). 00280 */ 00281 template <typename SerializableType> 00282 inline bool save( const SerializableType & src, std::ostream & dest ) 00283 { 00284 node_type n; 00285 if( this->serialize( n, src ) ) 00286 { 00287 return this->save( n, dest ); 00288 } 00289 else 00290 { 00291 return false; 00292 } 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