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 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

Generated on Sun Apr 27 13:16:03 2008 for libs11n by  doxygen 1.5.3