micro_api.hpp

Go to the documentation of this file.
00001 #ifndef s11nlite_MICROAPI_HPP_INCLUDED
00002 #define s11nlite_MICROAPI_HPP_INCLUDED 1
00003 
00004 #include <s11n.net/s11n/s11nlite.hpp>
00005 #include <s11n.net/s11n/mutex.hpp>
00006 
00007 namespace s11nlite
00008 {
00009 
00010     /**
00011        micro_api is of arguable utility, written just to see what
00012        happens. It is intended to be used for saving and loading
00013        sets of like-typed Serializables. For apps which do lots of
00014        loading and saving of homogeonous Serializables, micro_api
00015        can cut down on the amount of typing (intentionally
00016        ambiguous) needed:
00017 
00018 <pre>
00019 s11nlite::micro_api<MyT> micro;
00020 MyT my;
00021 ... populate my ...
00022 micro.save( my, "somefile" );
00023 ...
00024 MyT * your = micro.load( "somefile" );
00025 </pre>
00026 
00027            Unlike the s11nlite interface, micro_api explicitely hides
00028            all node-level details. It does allow the user to set an
00029            output format (serializer class), as it may be desirable to
00030            save different collections of objects in different formats.
00031            For loading it uses s11nlite, so it supports any formats
00032        supported there.
00033 
00034        Templatized on:
00035 
00036        - SerializableType must be the base-most Serializable type
00037        in a given Serializable hierarchy (or the Serializable type
00038        itself, for monomorphs).
00039 
00040        Any functions in this class might throw if their s11n[lite]
00041        counterparts do.
00042 
00043        Multi-threading:
00044 
00045        Using a single micro_api instance from multiple
00046        threads is not encouraged, but it just might work.
00047        Even so, some operations must be locked from the client side
00048        to avoid undesired racing, such as operation sequences
00049        like (micro.buffer(Object); string s=micro.buffer())
00050        to ensure that the buffer is not hammered by a parallel
00051        call to micro.buffer(XXX) just before (s=micro.buffer())
00052        is called.
00053     */
00054     template <typename SerializableType>
00055     class micro_api
00056     {
00057     public:
00058         /**
00059            The base Serializable interface associated with
00060            this object.
00061         */
00062         typedef SerializableType serializable_type;
00063 
00064     private:
00065         typedef s11nlite::node_type node_type;
00066         typedef s11nlite::node_traits node_traits;
00067         typedef s11nlite::serializer_interface serializer_interface;
00068         std::string m_serclass;
00069         std::string m_buffer;
00070         mutable s11n::mutex m_mutex;
00071         /**
00072            Internal helper to reduce a small amount of code duplication
00073            in the two save() variants.
00074 
00075            Serializes src to dest, returning 0 if that fails.
00076            If serialization to the node succeeds, it returns
00077            s11nlite::create_serialize(this->serializer_class()). The
00078            caller owns the returned pointer, which may be 0.
00079         */
00080         serializer_interface *
00081         prepare_save( node_type & dest, const serializable_type & src ) const
00082         {
00083             if( ! ::s11n::serialize<node_type,serializable_type>( dest, src ) )
00084             {
00085                 return 0;
00086             }
00087             return ::s11nlite::create_serializer(this->m_serclass);
00088         }
00089     public:
00090         /**
00091            Constructs an object with the given serializer_class().
00092         */
00093         explicit micro_api( const std::string & serclass )
00094             : m_serclass(serclass),
00095               m_buffer(),
00096               m_mutex()
00097         {
00098         }
00099 
00100         /** Does nothing. */
00101         ~micro_api() {}
00102         
00103         /**
00104            Constructs an object with the same
00105            serializer_class() as s11nlite::serializer_class().
00106         */
00107         micro_api()
00108             : m_serclass(::s11nlite::serializer_class()),
00109               m_buffer(),
00110               m_mutex()
00111         {
00112         }
00113 
00114         /** Returns the current serializer class name. */
00115         std::string serializer_class() const
00116         {
00117             return this->m_serclass;
00118         }
00119 
00120         /**
00121            Sets the current serializer class name.
00122         */
00123         void serializer_class(const std::string & s)
00124         {
00125             s11n::mutex_sentry lock(this->m_mutex);
00126             // ^^^ keep m_serclass from changing during save()
00127             this->m_serclass = s;
00128         }
00129 
00130         /**
00131            Serializes src to an internal buffer, which may be fetched
00132            and cleared with buffer() and clear_buffer(), respectively.
00133         */
00134         bool buffer( const serializable_type & src )
00135         {
00136             std::ostringstream os;
00137             if( ! this->save( src, os ) ) return false;
00138             // save() locks, so we can't lock until after save() completes.
00139             s11n::mutex_sentry lock(this->m_mutex);
00140             this->m_buffer = os.str();
00141             return true;
00142         }
00143 
00144         /**
00145            Returns this object's buffered data, if any has
00146            been set using buffer(serializable_type). The
00147            buffer can be deserialized by wrapping it in an
00148            istringstream.
00149 
00150            Note that only Serializers which can write to
00151            streams can be used here (e.g., not
00152            sqlite3_serializer).
00153         */
00154         std::string buffer() const
00155         {
00156             s11n::mutex_sentry lock(this->m_mutex);
00157             // ^^^ buffer might be changing right now.
00158             return this->m_buffer;
00159         }
00160 
00161         /**
00162            Clears any buffered data saved using
00163            buffer(serializable_type).
00164         */
00165         void clear_buffer()
00166         {
00167             s11n::mutex_sentry lock(this->m_mutex);
00168             // ^^^ buffer might be changing right now.
00169             this->m_buffer = std::string();
00170         }
00171 
00172         /**
00173            Saves src to dest, returning true on success and false on error.
00174            If the underlying call(s) to serialize throw then this function
00175            pass on the exception.
00176 
00177            Note that dest does not get parsed to see if it's a
00178            URL. Instead it goes directly to the
00179            Serializer. This distinction is important for
00180            Serializers which treat filenames and streams
00181            differently (e.g., mysql_serializer and
00182            sqlite3_serializer). If you want to get the
00183            built-in URL support for your filename strings, use
00184            s11n::io::get_ostream(). Likewise, for loading, use
00185            s11n::io::get_istream().
00186         */
00187         bool save( const serializable_type & src, const std::string & dest ) const
00188         {
00189             s11n::mutex_sentry lock(this->m_mutex);
00190             node_type n;
00191             std::auto_ptr<serializer_interface> sap( this->prepare_save( n, src ) );
00192             return sap.get() ? sap->serialize( n, dest ) : false;
00193         }
00194 
00195         /** Overload taking an ostream. */
00196         bool save( const serializable_type & src, std::ostream & dest ) const
00197         {
00198             s11n::mutex_sentry lock(this->m_mutex);
00199             node_type n;
00200             std::auto_ptr<serializer_interface> sap( this->prepare_save( n, src ) );
00201             return sap.get() ? sap->serialize( n, dest ) : false;
00202         }
00203 
00204         /**
00205            Loads a serializable_type from src, returning 0 on
00206            failure and a valid pointer on success (which the
00207            caller owns). If the underlying call(s) to
00208            serialize throw then this function passes on the
00209            exception. In that case the object which was allocated
00210            for the process (if any) is destroyed, cleaned up
00211            by the s11n_traits::cleanup_functor mechanism, which is
00212            believed to be relatively safe from memory leaks.
00213         */
00214         serializable_type * load( const std::string & src ) const
00215         {
00216             return ::s11nlite::load_serializable<serializable_type>( src );
00217         }
00218     
00219         /**
00220            An overload which takes an istream instead of a string.
00221         */
00222         serializable_type * load( std::istream & src ) const
00223         {
00224             return ::s11nlite::load_serializable<serializable_type>( src );
00225         }
00226 
00227         /**
00228            Loads a Serializable from the buffer() content, if any.
00229            The caller owns the returned pointer, which may be 0.
00230         */
00231         serializable_type * load_buffer() const
00232         {
00233             s11n::mutex_sentry lock(this->m_mutex);
00234             if( this->m_buffer.empty() ) return 0;
00235             std::istringstream is( this->m_buffer );
00236             return ::s11nlite::load_serializable<serializable_type>( is );
00237         }
00238         
00239 
00240     };
00241 
00242 
00243 } // namespace s11nlite
00244 
00245 
00246 #endif // s11nlite_MICROAPI_HPP_INCLUDED

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