builder.h

Go to the documentation of this file.
00001 ///
00002 /// \file       builder.h
00003 ///             Virtual protocol packet builder wrapper
00004 ///
00005 
00006 /*
00007     Copyright (C) 2005-2012, Net Direct Inc. (http://www.netdirect.ca/)
00008 
00009     This program is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     This program is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018     See the GNU General Public License in the COPYING file at the
00019     root directory of this project for more details.
00020 */
00021 
00022 #ifndef __BARRY_BUILDER_H__
00023 #define __BARRY_BUILDER_H__
00024 
00025 #include "dll.h"
00026 #include "data.h"
00027 #include <stdint.h>
00028 #include <string>
00029 
00030 //
00031 // This macro can be used to automatically generate code for all known
00032 // record types.  Just #undef HANDLE_BUILDER, then #define it to whatever
00033 // you need, then use ALL_KNOWN_BUILDER_TYPES.  See parser.cc for
00034 // various examples.
00035 //
00036 // These are sorted so their GetDBName()'s will display in alphabetical order.
00037 //
00038 #define ALL_KNOWN_BUILDER_TYPES \
00039         HANDLE_BUILDER(Contact) \
00040         HANDLE_BUILDER(Calendar) \
00041         HANDLE_BUILDER(CalendarAll) \
00042         HANDLE_BUILDER(ContentStore) \
00043         HANDLE_BUILDER(Memo) \
00044         HANDLE_BUILDER(Task) \
00045 
00046 namespace Barry {
00047 
00048 // forward declarations
00049 class IConverter;
00050 
00051 //
00052 // Builder class
00053 //
00054 /// Base class for the builder functor hierarchy.
00055 ///
00056 /// This defines the API used by the Controller and Packet classes
00057 /// for building a raw device record to write to the device.
00058 ///
00059 class BXEXPORT Builder
00060 {
00061 public:
00062         Builder() {}
00063         virtual ~Builder() {}
00064 
00065         /// Called to build the record field data.  Store the raw data
00066         /// in data, using offset to know where to write.  Be sure to
00067         /// update offset, and be sure to adjust the size of the data
00068         /// packet (possibly with Data::ReleaseBuffer()).
00069         ///
00070         /// Returns true if successful, and false if at the end of
00071         /// the series.  Note that if EndOfFile() is false after
00072         /// this function returns false, then there may be another
00073         /// series available, which the next call to BuildRecord()
00074         /// will determine.
00075         ///
00076         virtual bool BuildRecord(DBData &data, size_t &offset,
00077                 const IConverter *ic) = 0;
00078 
00079         /// Same as BuildRecord, but does not care about any offsets.
00080         /// The caller should call DBData::GetOffset() afterward
00081         /// to discover if there is an offset to the result.
00082         ///
00083         /// This is usually the fastest of the two functions, since
00084         /// extra copying may be required if a specific offset is
00085         /// given.  When building records from Record classes, both
00086         /// functions are the same speed.  But when building records
00087         /// from the device, the device decides the offset, so FetchRecord()
00088         /// is faster, since BuildRecord requires a copy to adjust
00089         /// to the right offset.
00090         ///
00091         /// The caller should use the function that results in the least
00092         /// amount of copying for the caller.  If the caller doesn't
00093         /// care about where the resulting record is in data, use
00094         /// FetchRecord().
00095         ///
00096         virtual bool FetchRecord(DBData &data, const IConverter *ic) = 0;
00097 
00098         /// Sometimes a builder can have multiple databases stored
00099         /// in it, so when Build/Fetch returns false, check if there
00100         /// is more data with this function.  This function is
00101         /// not used by database-oriented functions, but by pipe-
00102         /// oriented functions.
00103         virtual bool EndOfFile() const = 0;
00104 };
00105 
00106 
00107 //
00108 // DBDataBuilder
00109 //
00110 /// Wrapper class around a DBData object, to make it easy to pass a DBData
00111 /// object into a function or API that requires a builder.  The main
00112 /// advantage to this is that the Builder API allows for movement of
00113 /// data, depending on the required offsets.
00114 ///
00115 class BXEXPORT DBDataBuilder : public Builder
00116 {
00117         const DBData &m_orig;
00118 
00119 public:
00120         explicit DBDataBuilder(const DBData &orig);
00121         virtual ~DBDataBuilder();
00122 
00123         virtual bool BuildRecord(DBData &data, size_t &offset,
00124                 const IConverter *ic);
00125         virtual bool FetchRecord(DBData &data, const IConverter *ic);
00126         virtual bool EndOfFile() const;
00127 };
00128 
00129 //
00130 // SetDBData
00131 //
00132 /// Contains the proper way to convert a record object into a DBData object.
00133 ///
00134 template <class RecordT>
00135 void SetDBData(const RecordT &rec, DBData &data, size_t &offset,
00136                 const IConverter *ic)
00137 {
00138         // Make sure record is valid before building it.
00139         // This can throw Barry::ValidationError
00140         rec.Validate();
00141 
00142         // Build the DBData object
00143         data.SetVersion(DBData::REC_VERSION_1);
00144         data.SetOffset(offset);
00145         data.SetDBName(RecordT::GetDBName());
00146         data.SetIds(rec.GetRecType(), rec.GetUniqueId());
00147         rec.BuildHeader(data.UseData(), offset);
00148         rec.BuildFields(data.UseData(), offset, ic);
00149 }
00150 
00151 //
00152 // RecordBuilder template class
00153 //
00154 /// Template class for easy creation of specific protocol packet builder
00155 /// objects.  This template takes the following template arguments:
00156 ///
00157 ///     - RecordT: One of the record classes in record.h
00158 ///     - StorageT: A custom storage functor class.  An object of this type
00159 ///             will be called as a function with empty Record as an
00160 ///             argument.  The storage class is expected to fill the
00161 ///             record object in preparation for building the packet
00162 ///             out of that data.  These calls happen on the fly as the data
00163 ///             is sent to the device over USB, so it should not block forever.
00164 ///
00165 /// Example SaveDatabase() call:
00166 ///
00167 /// <pre>
00168 /// FIXME
00169 /// </pre>
00170 ///
00171 template <class RecordT, class StorageT>
00172 class RecordBuilder : public Builder
00173 {
00174         StorageT *m_storage;
00175         bool m_owned;
00176         bool m_record_loaded;
00177         bool m_end_of_file;
00178         RecordT m_rec;
00179 
00180 public:
00181         /// Constructor that references an externally managed storage object.
00182         RecordBuilder(StorageT &storage)
00183                 : m_storage(&storage)
00184                 , m_owned(false)
00185                 , m_record_loaded(false)
00186                 , m_end_of_file(false)
00187         {
00188         }
00189 
00190         /// Constructor that references a locally managed storage object.
00191         /// The pointer passed in will be stored, and freed when this class
00192         /// is destroyed.  It is safe to call this constructor with
00193         /// a 'new'ly created storage object.
00194         RecordBuilder(StorageT *storage)
00195                 : m_storage(storage)
00196                 , m_owned(true)
00197                 , m_record_loaded(false)
00198                 , m_end_of_file(false)
00199         {
00200         }
00201 
00202         ~RecordBuilder()
00203         {
00204                 if( this->m_owned )
00205                         delete m_storage;
00206         }
00207 
00208         virtual bool BuildRecord(DBData &data, size_t &offset,
00209                                 const IConverter *ic)
00210         {
00211                 if( m_end_of_file )
00212                         return false;
00213 
00214                 if( !(*m_storage)(m_rec, *this) ) {
00215                         m_end_of_file = true;
00216                         return false;
00217                 }
00218 
00219                 SetDBData(m_rec, data, offset, ic);
00220                 return true;
00221         }
00222 
00223         virtual bool FetchRecord(DBData &data, const IConverter *ic)
00224         {
00225                 size_t offset = 0;
00226                 return BuildRecord(data, offset, ic);
00227         }
00228 
00229         virtual bool EndOfFile() const
00230         {
00231                 return m_end_of_file;
00232         }
00233 };
00234 
00235 
00236 //
00237 // RecordFetch template class
00238 //
00239 /// Generic record fetch class, to help with using records without
00240 /// builder classes.
00241 ///
00242 template <class RecordT>
00243 class RecordFetch
00244 {
00245         const RecordT &m_rec;
00246         mutable bool m_done;
00247 
00248 public:
00249         RecordFetch(const RecordT &rec) : m_rec(rec), m_done(false) {}
00250         bool operator()(RecordT &rec, Builder &) const
00251         {
00252                 if( m_done )
00253                         return false;
00254                 rec = m_rec;
00255                 m_done = true;
00256                 return true;
00257         }
00258 };
00259 
00260 
00261 } // namespace Barry
00262 
00263 #endif
00264