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 Data 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 return s.get() 00230 ? s->serialize( src, dest ) 00231 : false; 00232 } 00233 00234 /** 00235 Saves the given node to the given filename using the default 00236 serializer type. 00237 00238 Returns true on success, false on error. 00239 00240 ONLY use this for saving root nodes! 00241 00242 Subclasses are free to interpret the filename 00243 however they like, e.g., as a URL or database 00244 record name. 00245 */ 00246 virtual bool save( const node_type & src, const std::string & filename ) 00247 { 00248 std::auto_ptr<serializer_interface> s(this->create_serializer()); 00249 return s.get() 00250 ? s->serialize( src, filename ) 00251 : false; 00252 // Maintenance note: we used to just convert 00253 // filename to a stream and call this->save( 00254 // src, ostr ), but this poses a problem with 00255 // serializers, like mysql_serializer, which 00256 // behave differently in the face of streams 00257 // and filenames. Currently (1.1.3) 00258 // mysql_serializer is the only one which 00259 // needs this distinction (because it can't 00260 // write db records to a stream). The experimental 00261 // ps11n support also distinguishe, as it supports 00262 // serialization over ftp URLs. 00263 } 00264 00265 00266 /** 00267 Saves the given Serializable to the given ostream using the default 00268 serializer type. 00269 Returns true on success, false on error. 00270 00271 ONLY use this for saving root nodes! 00272 00273 Subclassers: this function serializes src to a node and then 00274 calls save(node,dest). 00275 */ 00276 template <typename SerializableType> 00277 inline bool save( const SerializableType & src, std::ostream & dest ) 00278 { 00279 node_type n; 00280 return this->serialize( n, src ) 00281 ? this->save( n, dest ) 00282 : false; 00283 } 00284 /** 00285 00286 Saves the given Serializable to the given filename using the default 00287 serializer type. 00288 00289 Returns true on success, false on error. 00290 00291 ONLY use this for saving root nodes! 00292 00293 Subclassers: this function serializes src to a node and then 00294 calls save(node,dest). 00295 */ 00296 template <typename SerializableType> 00297 bool save( const SerializableType & src, const std::string & dest ) 00298 { 00299 // See save(node,string) for why we don't wan this: 00300 // typedef std::auto_ptr<std::ostream> AP; 00301 // AP os = AP( s11n::io::get_ostream( dest ) ); 00302 // if( ! os.get() ) return 0; 00303 // return this->save( src, *os ); 00304 node_type n; 00305 return this->serialize( n, src ) 00306 ? this->save( n, dest ) 00307 : false; 00308 } 00309 00310 /** 00311 Tries to load a node from the given filename. 00312 00313 The caller owns the returned pointer. 00314 00315 Subclasses are free to interpret the filename 00316 however they like, e.g., as a URL or database 00317 record name. 00318 */ 00319 virtual node_type * load_node( const std::string & src ) 00320 { 00321 return s11n::io::load_node<node_type>( src ); 00322 } 00323 00324 00325 /** 00326 Tries to load a node from the given input stream. 00327 00328 The caller owns the returned pointer, which may be 00329 0. 00330 00331 Only usable for loading ROOT nodes. 00332 */ 00333 virtual node_type * load_node( std::istream & src ) 00334 { 00335 return s11n::io::load_node<node_type>( src ); 00336 } 00337 00338 00339 00340 /** 00341 Returns s11n::deserialize<node_type,SerializableType>(src). 00342 00343 Caller owns the returned pointer, which may be 0. 00344 00345 Note that this function is non-const because deserialization 00346 may indirectly classload other types or affect this object. 00347 00348 See the one-argument variant of s11n::deserialize() for 00349 IMPORTANT error-handling considerations for this function. 00350 */ 00351 template <typename SerializableType> 00352 inline SerializableType * deserialize( const node_type & src ) const 00353 { 00354 return s11n::deserialize<node_type,SerializableType>( src ); 00355 } 00356 00357 00358 00359 /** 00360 See s11n::deserialize(). 00361 */ 00362 template <typename DeserializableT> 00363 inline bool deserialize( const node_type & src, DeserializableT & target ) const 00364 { 00365 return s11n::deserialize<node_type,DeserializableT>( src, target ); 00366 } 00367 00368 00369 /** 00370 See s11n::deserialize_subnode(). 00371 */ 00372 template <typename DeserializableT> 00373 inline bool deserialize_subnode( const node_type & src, const std::string & subnodename, DeserializableT & target ) const 00374 { 00375 return s11n::deserialize_subnode< node_type, DeserializableT >( src, subnodename, target ); 00376 } 00377 00378 /** 00379 See s11n::deserialize_subnode(). 00380 */ 00381 template <typename DeserializableT> 00382 inline DeserializableT * deserialize_subnode( const node_type & src, const std::string & subnodename ) const 00383 { 00384 return s11n::deserialize_subnode< node_type, DeserializableT >( src, subnodename ); 00385 } 00386 00387 00388 /** 00389 Tries to load a data_node from src, then deserialize that 00390 to a SerializableType. 00391 */ 00392 template <typename SerializableType> 00393 inline SerializableType * load_serializable( std::istream & src ) 00394 { 00395 std::auto_ptr<node_type> n( this->load_node( src ) ); 00396 return n.get() 00397 ? this->deserialize<SerializableType>( *n ) 00398 : 0; 00399 } 00400 00401 /** 00402 Overloaded form which takes a file name. 00403 00404 1.1.3: removed the never-used 2nd parameter. 00405 00406 Subclassers: the loading is done via load_node(), 00407 so you can intercept the src string there. 00408 */ 00409 template <typename SerializableType> 00410 inline SerializableType * load_serializable( const std::string & src ) 00411 { 00412 std::auto_ptr<node_type> node( this->load_node(src) ); 00413 return node.get() 00414 ? this->deserialize<SerializableType>( *node ) 00415 : 0; 00416 } 00417 00418 /** 00419 See s11n::s11n_clone(). 00420 */ 00421 template <typename SerializableType> 00422 inline SerializableType * clone( const SerializableType & tocp ) const 00423 { 00424 return s11n::s11n_clone<node_type,SerializableType>( tocp ); 00425 // node_type node; 00426 // return this->serialize( node, tocp ) 00427 // ? this->deserialize<SerializableType>( node ) 00428 // : 0; 00429 } 00430 00431 /** 00432 See s11n::s11n_cast(). 00433 */ 00434 template <typename Type1, typename Type2> 00435 inline bool cast( const Type1 & t1, Type2 & t2 ) const 00436 { 00437 // Hmmmm.... should we jump directly to s11n_cast() or perform that same 00438 // operation using our de/serialize() API???? 00439 // They aren't necessarily equivalent, and the inconsistent might come 00440 // to light one day. i can't imagine a use case, but there's gotta 00441 // be one. 00442 // node_type n; 00443 // return this->serialize<Type1>( n, t1 ) && this->deserialize<Type2>( n, t2 ); 00444 return ::s11n::s11n_cast<node_type,Type1,Type2>( t1, t2 ); 00445 } 00446 00447 /** 00448 Returns a shared instance of this class. The object 00449 itself is post-main() safe (on most systems), 00450 meaning if this function is called after the shared 00451 object is destroy (after main() exits), it "should" 00452 actually behave properly be re-instantiating the 00453 object in-place. See s11n/phoenix.hpp for details 00454 and caveats. In the worst case, it's no less safe than 00455 any other post-main() object. 00456 */ 00457 static client_api<node_type> & 00458 instance() 00459 { 00460 return ::s11n::Detail::phoenix< client_api<node_type> >::instance(); 00461 } 00462 00463 }; // client_api<> class 00464 00465 } // namespace s11nlite 00466 00467 #endif // s11n_net_s11nlite_CLIENT_API_HPP_INCLUDED