client_api.hpp

Go to the documentation of this file.
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

Generated on Sat Mar 20 12:29:24 2010 for libs11n-1.2.10 by  doxygen 1.6.1