Index Source Files Annotated Class List Alphabetical Class List Class Hierarchy Graphical Class Hierarchy

# Message.h

Go to the documentation of this file.

    00001 /* -*- C++ -*- */
    00002
    00003 /****************************************************************************
    00004 ** Copyright (c) quickfixengine.org  All rights reserved.
    00005 **
    00006 ** This file is part of the QuickFIX FIX Engine
    00007 **
    00008 ** This file may be distributed under the terms of the quickfixengine.org
    00009 ** license as defined by quickfixengine.org and appearing in the file
    00010 ** LICENSE included in the packaging of this file.
    00011 **
    00012 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
    00013 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    00014 **
    00015 ** See http://www.quickfixengine.org/LICENSE for licensing information.
    00016 **
    00017 ** Contact ask@quickfixengine.org if any conditions of this licensing are
    00018 ** not clear to you.
    00019 **
    00020 ****************************************************************************/
    00021
    00022 #ifndef FIX_MESSAGE
    00023 #define FIX_MESSAGE
    00024
    00025 #ifdef _MSC_VER
    00026 #pragma warning( disable: 4786 )
    00027 #endif
    00028
    00029 #include "FieldMap.h"
    00030 #include "Fields.h"
    00031 #include "Group.h"
    00032 #include "SessionID.h"
    00033 #include "DataDictionary.h"
    00034 #include "CallStack.h"
    00035 #include "Values.h"
    00036 #include <vector>
    00037 #include <memory>
    00038
    00039 namespace FIX
    00040 {
    00041 typedef FieldMap Header;
    00042 typedef FieldMap Trailer;
    00043
    00044 static int const headerOrder[] =
    00045   {
    00046     FIELD::BeginString,
    00047     FIELD::BodyLength,
    00048     FIELD::MsgType
    00049   };
    00050
    00057 class Message : public FieldMap
    00058 {
    00059   friend class DataDictionary;
    00060   friend class Session;
    00061
    00062   enum field_type { header, body, trailer };
    00063
    00064 public:
    00065   Message();
    00066
    00068   Message( const std::string& string, bool validate = true )
    00069   throw( InvalidMessage );
    00070
    00072   Message( const std::string& string, const FIX::DataDictionary& dataDictionary,
    00073            bool validate = true )
    00074   throw( InvalidMessage );
    00075
    00077   Message( const std::string& string, const FIX::DataDictionary& sessionDataDictionary,
    00078            const FIX::DataDictionary& applicationDataDictionary, bool validate = true )
    00079   throw( InvalidMessage );
    00080
    00081   Message( const Message& copy )
    00082   : FieldMap( copy ),
    00083     m_header( message_order( message_order::header ) ),
    00084     m_trailer( message_order( message_order::trailer ) )
    00085   {
    00086     m_header = copy.m_header;
    00087     m_trailer = copy.m_trailer;
    00088     m_validStructure = copy.m_validStructure;
    00089     m_field = copy.m_field;
    00090   }
    00091
    00093   static bool InitializeXML( const std::string& string );
    00094
    00095   void addGroup( FIX::Group& group )
    00096   { FieldMap::addGroup( group.field(), group ); }
    00097
    00098   void replaceGroup( unsigned num, FIX::Group& group )
    00099   { FieldMap::replaceGroup( num, group.field(), group ); }
    00100
    00101   Group& getGroup( unsigned num, FIX::Group& group ) const throw( FieldNotFound )
    00102   { group.clear();
    00103     return static_cast < Group& >
    00104       ( FieldMap::getGroup( num, group.field(), group ) );
    00105   }
    00106
    00107   void removeGroup( unsigned num, FIX::Group& group )
    00108   { FieldMap::removeGroup( num, group.field() ); }
    00109   void removeGroup( FIX::Group& group )
    00110   { FieldMap::removeGroup( group.field() ); }
    00111
    00112   bool hasGroup( const FIX::Group& group ) const
    00113   { return FieldMap::hasGroup( group.field() ); }
    00114   bool hasGroup( unsigned num, FIX::Group& group ) const
    00115   { return FieldMap::hasGroup( num, group.field() ); }
    00116
    00117 protected:
    00118   // Constructor for derived classes
    00119   Message( const BeginString& beginString, const MsgType& msgType )
    00120   : m_header( message_order( message_order::header ) ),
    00121   m_trailer( message_order( message_order::trailer ) ),
    00122   m_validStructure( true )
    00123   {
    00124     m_header.setField( beginString );
    00125     m_header.setField( msgType );
    00126   }
    00127
    00128 public:
    00130   std::string toString( int beginStringField = FIELD::BeginString,
    00131                         int bodyLengthField = FIELD::BodyLength,
    00132                         int checkSumField = FIELD::CheckSum ) const;
    00134   std::string& toString( std::string&,
    00135                          int beginStringField = FIELD::BeginString,
    00136                          int bodyLengthField = FIELD::BodyLength,
    00137                          int checkSumField = FIELD::CheckSum ) const;
    00139   std::string toXML() const;
    00141   std::string& toXML( std::string& ) const;
    00142
    00148   void reverseRoute( const Header& );
    00149
    00156   void setString( const std::string& string )
    00157   { setString(string, true); }
    00158   void setString( const std::string& string, bool validate )
    00159   { setString(string, validate, 0); }
    00160   void setString( const std::string& string,
    00161                   bool validate,
    00162                   const FIX::DataDictionary* pDataDictionary )
    00163   throw( InvalidMessage )
    00164   { setString(string, validate, pDataDictionary, pDataDictionary); }
    00165
    00166   void setString( const std::string& string,
    00167                   bool validate,
    00168                   const FIX::DataDictionary* pSessionDataDictionary,
    00169                   const FIX::DataDictionary* pApplicationDataDictionary )
    00170   throw( InvalidMessage );
    00171
    00172   void setGroup( const std::string& msg, const FieldBase& field,
    00173                  const std::string& string, std::string::size_type& pos,
    00174                  FieldMap& map, const DataDictionary& dataDictionary );
    00175
    00181   bool setStringHeader( const std::string& string );
    00182
    00184   const Header& getHeader() const { return m_header; }
    00186   Header& getHeader() { return m_header; }
    00188   const Header& getTrailer() const { return m_trailer; }
    00190   Trailer& getTrailer() { return m_trailer; }
    00191
    00192   bool hasValidStructure(int& field) const
    00193   { field = m_field;
    00194     return m_validStructure;
    00195   }
    00196
    00197   int bodyLength( int beginStringField = FIELD::BeginString,
    00198                   int bodyLengthField = FIELD::BodyLength,
    00199                   int checkSumField = FIELD::CheckSum ) const
    00200   { return m_header.calculateLength(beginStringField, bodyLengthField, checkSumField)
    00201            + calculateLength(beginStringField, bodyLengthField, checkSumField)
    00202            + m_trailer.calculateLength(beginStringField, bodyLengthField, checkSumField);
    00203   }
    00204
    00205   int checkSum( int checkSumField = FIELD::CheckSum ) const
    00206   { return ( m_header.calculateTotal(checkSumField)
    00207              + calculateTotal(checkSumField)
    00208              + m_trailer.calculateTotal(checkSumField) ) % 256;
    00209   }
    00210
    00211   bool isAdmin() const
    00212   {
    00213     if( m_header.isSetField(FIELD::MsgType) )
    00214     {
    00215       const MsgType& msgType = FIELD_GET_REF( m_header, MsgType );
    00216       return isAdminMsgType( msgType );
    00217     }
    00218     return false;
    00219   }
    00220
    00221   bool isApp() const
    00222   {
    00223     if( m_header.isSetField(FIELD::MsgType) )
    00224     {
    00225       const MsgType& msgType = FIELD_GET_REF( m_header, MsgType );
    00226       return !isAdminMsgType( msgType );
    00227     }
    00228     return false;
    00229   }
    00230
    00231   bool isEmpty()
    00232   { return m_header.isEmpty() && FieldMap::isEmpty() && m_trailer.isEmpty(); }
    00233
    00234   void clear()
    00235   {
    00236     m_field = 0;
    00237     m_header.clear();
    00238     FieldMap::clear();
    00239     m_trailer.clear();
    00240   }
    00241
    00242   static bool isAdminMsgType( const MsgType& msgType )
    00243   { if ( msgType.getValue().length() != 1 ) return false;
    00244     return strchr
    00245            ( "0A12345",
    00246              msgType.getValue().c_str() [ 0 ] ) != 0;
    00247   }
    00248
    00249   static ApplVerID toApplVerID(const BeginString& value)
    00250   { QF_STACK_PUSH(SessionFactory::toApplVerID)
    00251
    00252     if( value == BeginString_FIX40 )
    00253       return ApplVerID(ApplVerID_FIX40);
    00254     if( value == BeginString_FIX41 )
    00255       return ApplVerID(ApplVerID_FIX41);
    00256     if( value == BeginString_FIX42 )
    00257       return ApplVerID(ApplVerID_FIX42);
    00258     if( value == BeginString_FIX43 )
    00259       return ApplVerID(ApplVerID_FIX43);
    00260     if( value == BeginString_FIX44 )
    00261       return ApplVerID(ApplVerID_FIX44);
    00262     if( value == BeginString_FIX50 )
    00263       return ApplVerID(ApplVerID_FIX50);
    00264     if( value == "FIX.5.0SP1" )
    00265       return ApplVerID(ApplVerID_FIX50SP1);
    00266     if( value == "FIX.5.0SP2" )
    00267       return ApplVerID(ApplVerID_FIX50SP2);
    00268     return ApplVerID(ApplVerID(value));
    00269
    00270     QF_STACK_POP
    00271   }
    00272
    00273   static BeginString toBeginString( const ApplVerID& applVerID )
    00274   {
    00275     if( applVerID == ApplVerID_FIX40 )
    00276       return BeginString(BeginString_FIX40);
    00277     else if( applVerID == ApplVerID_FIX41 )
    00278       return BeginString(BeginString_FIX41);
    00279     else if( applVerID == ApplVerID_FIX42 )
    00280       return BeginString(BeginString_FIX42);
    00281     else if( applVerID == ApplVerID_FIX43 )
    00282       return BeginString(BeginString_FIX43);
    00283     else if( applVerID == ApplVerID_FIX44 )
    00284       return BeginString(BeginString_FIX44);
    00285     else if( applVerID == ApplVerID_FIX50 )
    00286       return BeginString(BeginString_FIX50);
    00287     else if( applVerID == ApplVerID_FIX50SP1 )
    00288       return BeginString(BeginString_FIX50);
    00289     else if( applVerID == ApplVerID_FIX50SP2 )
    00290       return BeginString(BeginString_FIX50);
    00291     else
    00292       return BeginString("");
    00293   }
    00294
    00295   static bool isHeaderField( int field );
    00296   static bool isHeaderField( const FieldBase& field,
    00297                              const DataDictionary* pD = 0 );
    00298
    00299   static bool isTrailerField( int field );
    00300   static bool isTrailerField( const FieldBase& field,
    00301                               const DataDictionary* pD = 0 );
    00302
    00304   SessionID getSessionID( const std::string& qualifier = "" ) const
    00305   throw( FieldNotFound );
    00307   void setSessionID( const SessionID& sessionID );
    00308
    00309 private:
    00310   FieldBase extractField
    00311   ( const std::string& string, std::string::size_type& pos,
    00312     const DataDictionary* pSessionDD = 0, const DataDictionary* pAppDD = 0,
    00313     const Group* pGroup = 0)
    00314   { QF_STACK_PUSH(extractField)
    00315
    00316     std::string::size_type equalSign
    00317       = string.find_first_of( '=', pos );
    00318     if( equalSign == std::string::npos )
    00319       throw InvalidMessage("Equal sign not found in field");
    00320
    00321     char* pEnd = 0;
    00322     int field = strtol( string.c_str() + pos, &pEnd, 0 );
    00323
    00324     std::string::size_type soh =
    00325       string.find_first_of( '\001', equalSign + 1 );
    00326     if ( soh == std::string::npos )
    00327       throw InvalidMessage("SOH not found at end of field");
    00328
    00329     if ( (pSessionDD && pSessionDD->isDataField(field)) || (pAppDD && pAppDD->isDataField(field)) )
    00330     {
    00331       std::string fieldLength;
    00332       // Assume length field is 1 less.
    00333       int lenField = field - 1;
    00334       // Special case for Signature which violates above assumption.
    00335       if ( field == 89 ) lenField = 93;
    00336
    00337       if ( pGroup && pGroup->isSetField( lenField ) )
    00338       {
    00339         fieldLength = pGroup->getField( lenField );
    00340         soh = equalSign + 1 + atol( fieldLength.c_str() );
    00341       }
    00342       else if ( isSetField( lenField ) )
    00343       {
    00344         fieldLength = getField( lenField );
    00345         soh = equalSign + 1 + atol( fieldLength.c_str() );
    00346       }
    00347     }
    00348
    00349     pos = soh + 1;
    00350     return FieldBase (
    00351       field,
    00352       string.substr( equalSign + 1, soh - ( equalSign + 1 ) ) );
    00353
    00354     QF_STACK_POP
    00355   }
    00356
    00357   void validate();
    00358   std::string toXMLFields(const FieldMap& fields, int space) const;
    00359
    00360 protected:
    00361   mutable FieldMap m_header;
    00362   mutable FieldMap m_trailer;
    00363   bool m_validStructure;
    00364   int m_field;
    00365   static std::auto_ptr<DataDictionary> s_dataDictionary;
    00366 };
    00369 inline std::ostream& operator <<
    00370 ( std::ostream& stream, const Message& message )
    00371 {
    00372   std::string str;
    00373   stream << message.toString( str );
    00374   return stream;
    00375 }
    00376
    00378 inline MsgType identifyType( const std::string& message )
    00379 throw( MessageParseError )
    00380 {
    00381   std::string::size_type pos = message.find( "\00135=" );
    00382   if ( pos == std::string::npos ) throw MessageParseError();
    00383
    00384   std::string::size_type startValue = pos + 4;
    00385   std::string::size_type soh = message.find_first_of( '\001', startValue );
    00386   if ( soh == std::string::npos ) throw MessageParseError();
    00387
    00388   std::string value = message.substr( startValue, soh - startValue );
    00389   return MsgType( value );
    00390 }
    00391 }
    00392
    00393 #endif //FIX_MESSAGE