Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

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

Generated on Fri Nov 25 17:19:28 2005 for libs11n-1.2.0 by  doxygen 1.4.4