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

# Message.cpp

Go to the documentation of this file.

    00001 /****************************************************************************
    00002 ** Copyright (c) quickfixengine.org  All rights reserved.
    00003 **
    00004 ** This file is part of the QuickFIX FIX Engine
    00005 **
    00006 ** This file may be distributed under the terms of the quickfixengine.org
    00007 ** license as defined by quickfixengine.org and appearing in the file
    00008 ** LICENSE included in the packaging of this file.
    00009 **
    00010 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
    00011 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    00012 **
    00013 ** See http://www.quickfixengine.org/LICENSE for licensing information.
    00014 **
    00015 ** Contact ask@quickfixengine.org if any conditions of this licensing are
    00016 ** not clear to you.
    00017 **
    00018 ****************************************************************************/
    00019
    00020 #ifdef _MSC_VER
    00021 #include "stdafx.h"
    00022 #else
    00023 #include "config.h"
    00024 #endif
    00025 #include "CallStack.h"
    00026
    00027 #include "Message.h"
    00028 #include "Utility.h"
    00029 #include "Values.h"
    00030 #include <iomanip>
    00031
    00032 namespace FIX
    00033 {
    00034 std::auto_ptr<DataDictionary> Message::s_dataDictionary;
    00035
    00036 Message::Message()
    00037 : m_header( message_order( message_order::header ) ),
    00038   m_trailer( message_order( message_order::trailer ) ),
    00039   m_validStructure( true ) {}
    00040
    00041 Message::Message( const std::string& string, bool validate )
    00042 throw( InvalidMessage )
    00043 : m_header( message_order( message_order::header ) ),
    00044   m_trailer( message_order( message_order::trailer ) ),
    00045   m_validStructure( true )
    00046 {
    00047   setString( string, validate );
    00048 }
    00049
    00050 Message::Message( const std::string& string,
    00051                   const DataDictionary& dataDictionary,
    00052                   bool validate )
    00053 throw( InvalidMessage )
    00054 : m_header( message_order( message_order::header ) ),
    00055   m_trailer( message_order( message_order::trailer ) ),
    00056   m_validStructure( true )
    00057 {
    00058   setString( string, validate, &dataDictionary, &dataDictionary );
    00059 }
    00060
    00061 Message::Message( const std::string& string,
    00062                   const DataDictionary& sessionDataDictionary,
    00063                   const DataDictionary& applicationDataDictionary,
    00064                   bool validate )
    00065 throw( InvalidMessage )
    00066 : m_header( message_order( message_order::header ) ),
    00067   m_trailer( message_order( message_order::trailer ) ),
    00068   m_validStructure( true )
    00069 {
    00070   setStringHeader( string );
    00071   if( isAdmin() )
    00072     setString( string, validate, &sessionDataDictionary, &sessionDataDictionary );
    00073   else
    00074     setString( string, validate, &sessionDataDictionary, &applicationDataDictionary );
    00075 }
    00076
    00077 bool Message::InitializeXML( const std::string& url )
    00078 { QF_STACK_PUSH(Message::InitializeXML)
    00079
    00080   try
    00081   {
    00082     std::auto_ptr<DataDictionary> p =
    00083       std::auto_ptr<DataDictionary>(new DataDictionary(url));
    00084     s_dataDictionary = p;
    00085     return true;
    00086   }
    00087   catch( ConfigError& )
    00088   { return false; }
    00089
    00090   QF_STACK_POP
    00091 }
    00092
    00093 void Message::reverseRoute( const Header& header )
    00094 { QF_STACK_PUSH(Message::reverseRoute)
    00095
    00096   // required routing tags
    00097   BeginString beginString;
    00098   SenderCompID senderCompID;
    00099   TargetCompID targetCompID;
    00100
    00101   m_header.removeField( beginString.getField() );
    00102   m_header.removeField( senderCompID.getField() );
    00103   m_header.removeField( targetCompID.getField() );
    00104
    00105   if( header.isSetField( beginString ) )
    00106   {
    00107     header.getField( beginString );
    00108     if( beginString.getValue().size() )
    00109       m_header.setField( beginString );
    00110
    00111     OnBehalfOfLocationID onBehalfOfLocationID;
    00112     DeliverToLocationID deliverToLocationID;
    00113
    00114     m_header.removeField( onBehalfOfLocationID.getField() );
    00115     m_header.removeField( deliverToLocationID.getField() );
    00116
    00117     if( beginString >= BeginString_FIX41 )
    00118     {
    00119       if( header.isSetField( onBehalfOfLocationID ) )
    00120       {
    00121         header.getField( onBehalfOfLocationID );
    00122         if( onBehalfOfLocationID.getValue().size() )
    00123           m_header.setField( DeliverToLocationID( onBehalfOfLocationID ) );
    00124       }
    00125
    00126       if( header.isSetField( deliverToLocationID ) )
    00127       {
    00128         header.getField( deliverToLocationID );
    00129         if( deliverToLocationID.getValue().size() )
    00130           m_header.setField( OnBehalfOfLocationID( deliverToLocationID ) );
    00131       }
    00132     }
    00133   }
    00134
    00135   if( header.isSetField( senderCompID ) )
    00136   {
    00137     header.getField( senderCompID );
    00138     if( senderCompID.getValue().size() )
    00139       m_header.setField( TargetCompID( senderCompID ) );
    00140   }
    00141
    00142   if( header.isSetField( targetCompID ) )
    00143   {
    00144     header.getField( targetCompID );
    00145     if( targetCompID.getValue().size() )
    00146       m_header.setField( SenderCompID( targetCompID ) );
    00147   }
    00148
    00149   // optional routing tags
    00150   OnBehalfOfCompID onBehalfOfCompID;
    00151   OnBehalfOfSubID onBehalfOfSubID;
    00152   DeliverToCompID deliverToCompID;
    00153   DeliverToSubID deliverToSubID;
    00154
    00155   m_header.removeField( onBehalfOfCompID.getField() );
    00156   m_header.removeField( onBehalfOfSubID.getField() );
    00157   m_header.removeField( deliverToCompID.getField() );
    00158   m_header.removeField( deliverToSubID.getField() );
    00159
    00160   if( header.isSetField( onBehalfOfCompID ) )
    00161   {
    00162     header.getField( onBehalfOfCompID );
    00163     if( onBehalfOfCompID.getValue().size() )
    00164       m_header.setField( DeliverToCompID( onBehalfOfCompID ) );
    00165   }
    00166
    00167   if( header.isSetField( onBehalfOfSubID ) )
    00168   {
    00169     header.getField( onBehalfOfSubID );
    00170     if( onBehalfOfSubID.getValue().size() )
    00171       m_header.setField( DeliverToSubID( onBehalfOfSubID ) );
    00172   }
    00173
    00174   if( header.isSetField( deliverToCompID ) )
    00175   {
    00176     header.getField( deliverToCompID );
    00177     if( deliverToCompID.getValue().size() )
    00178       m_header.setField( OnBehalfOfCompID( deliverToCompID ) );
    00179   }
    00180
    00181   if( header.isSetField( deliverToSubID ) )
    00182   {
    00183     header.getField( deliverToSubID );
    00184     if( deliverToSubID.getValue().size() )
    00185       m_header.setField( OnBehalfOfSubID( deliverToSubID ) );
    00186   }
    00187
    00188   QF_STACK_POP
    00189 }
    00190
    00191 std::string Message::toString( int beginStringField,
    00192                                int bodyLengthField,
    00193                                int checkSumField ) const
    00194 { QF_STACK_PUSH(Message::toString)
    00195
    00196   std::string str;
    00197   return toString( str, beginStringField, bodyLengthField, checkSumField );
    00198
    00199   QF_STACK_POP
    00200 }
    00201
    00202 std::string& Message::toString( std::string& str,
    00203                                 int beginStringField,
    00204                                 int bodyLengthField,
    00205                                 int checkSumField ) const
    00206 { QF_STACK_PUSH(Message::toString)
    00207
    00208   int length = bodyLength( beginStringField, bodyLengthField, checkSumField );
    00209   m_header.setField( IntField(bodyLengthField, length) );
    00210   m_trailer.setField( CheckSumField(checkSumField, checkSum(checkSumField)) );
    00211
    00212   m_header.calculateString( str, true );
    00213   FieldMap::calculateString( str, false );
    00214   m_trailer.calculateString( str, false );
    00215
    00216   return str;
    00217
    00218   QF_STACK_POP
    00219 }
    00220
    00221 std::string Message::toXML() const
    00222 { QF_STACK_PUSH(Message::toXML)
    00223
    00224   std::string str;
    00225   return toXML( str );
    00226
    00227   QF_STACK_POP
    00228 }
    00229
    00230 std::string& Message::toXML( std::string& str ) const
    00231 { QF_STACK_PUSH(Message::toXML)
    00232
    00233   std::stringstream stream;
    00234   stream << "<message>"                         << std::endl
    00235          << std::setw(2) << " " << "<header>"   << std::endl
    00236          << toXMLFields(getHeader(), 4)
    00237          << std::setw(2) << " " << "</header>"  << std::endl
    00238          << std::setw(2) << " " << "<body>"     << std::endl
    00239          << toXMLFields(*this, 4)
    00240          << std::setw(2) << " " << "</body>"    << std::endl
    00241          << std::setw(2) << " " << "<trailer>"  << std::endl
    00242          << toXMLFields(getTrailer(), 4)
    00243          << std::setw(2) << " " << "</trailer>" << std::endl
    00244          << "</message>";
    00245
    00246   return str = stream.str();
    00247
    00248   QF_STACK_POP
    00249 }
    00250
    00251 std::string Message::toXMLFields(const FieldMap& fields, int space) const
    00252 { QF_STACK_PUSH(Message::toXMLFields)
    00253
    00254   std::stringstream stream;
    00255   FieldMap::iterator i;
    00256   std::string name;
    00257   for(i = fields.begin(); i != fields.end(); ++i)
    00258   {
    00259     int field = i->first;
    00260     std::string value = i->second.getString();
    00261
    00262     stream << std::setw(space) << " " << "<field ";
    00263     if(s_dataDictionary.get() && s_dataDictionary->getFieldName(field, name))
    00264     {
    00265       stream << "name=\"" << name << "\" ";
    00266     }
    00267     stream << "number=\"" << field << "\"";
    00268     if(s_dataDictionary.get()
    00269        && s_dataDictionary->getValueName(field, value, name))
    00270     {
    00271       stream << " enum=\"" << name << "\"";
    00272     }
    00273     stream << ">";
    00274     stream << "<![CDATA[" << value << "]]>";
    00275     stream << "</field>" << std::endl;
    00276   }
    00277
    00278   FieldMap::g_iterator j;
    00279   for(j = fields.g_begin(); j != fields.g_end(); ++j)
    00280   {
    00281     std::vector<FieldMap*>::const_iterator k;
    00282     for(k = j->second.begin(); k != j->second.end(); ++k)
    00283     {
    00284       stream << std::setw(space) << " " << "<group>" << std::endl
    00285              << toXMLFields(*(*k), space+2)
    00286              << std::setw(space) << " " << "</group>" << std::endl;
    00287     }
    00288   }
    00289
    00290   return stream.str();
    00291
    00292   QF_STACK_POP
    00293 }
    00294
    00295 void Message::setString( const std::string& string,
    00296                          bool doValidation,
    00297                          const DataDictionary* pSessionDataDictionary,
    00298                          const DataDictionary* pApplicationDataDictionary )
    00299 throw( InvalidMessage )
    00300 { QF_STACK_PUSH(Message::setString)
    00301
    00302   clear();
    00303
    00304   std::string::size_type pos = 0;
    00305   int count = 0;
    00306   std::string msg;
    00307
    00308   static int const headerOrder[] =
    00309   {
    00310     FIELD::BeginString,
    00311     FIELD::BodyLength,
    00312     FIELD::MsgType
    00313   };
    00314
    00315   field_type type = header;
    00316
    00317   while ( pos < string.size() )
    00318   {
    00319     FieldBase field = extractField( string, pos, pSessionDataDictionary, pApplicationDataDictionary );
    00320     if ( count < 3 && headerOrder[ count++ ] != field.getField() )
    00321       if ( doValidation ) throw InvalidMessage("Header fields out of order");
    00322
    00323     if ( isHeaderField( field, pSessionDataDictionary ) )
    00324     {
    00325       if ( type != header )
    00326       {
    00327         if(m_field == 0) m_field = field.getField();
    00328         m_validStructure = false;
    00329       }
    00330
    00331       if ( field.getField() == FIELD::MsgType )
    00332         msg = field.getString();
    00333
    00334       m_header.setField( field, false );
    00335
    00336       if ( pSessionDataDictionary )
    00337         setGroup( "_header_", field, string, pos, getHeader(), *pSessionDataDictionary );
    00338     }
    00339     else if ( isTrailerField( field, pSessionDataDictionary ) )
    00340     {
    00341       type = trailer;
    00342       m_trailer.setField( field, false );
    00343
    00344       if ( pSessionDataDictionary )
    00345         setGroup( "_trailer_", field, string, pos, getTrailer(), *pSessionDataDictionary );
    00346     }
    00347     else
    00348     {
    00349       if ( type == trailer )
    00350       {
    00351         if(m_field == 0) m_field = field.getField();
    00352         m_validStructure = false;
    00353       }
    00354
    00355       type = body;
    00356       setField( field, false );
    00357
    00358       if ( pApplicationDataDictionary )
    00359         setGroup( msg, field, string, pos, *this, *pApplicationDataDictionary );
    00360     }
    00361   }
    00362
    00363   if ( doValidation )
    00364     validate();
    00365
    00366   QF_STACK_POP
    00367 }
    00368
    00369 void Message::setGroup( const std::string& msg, const FieldBase& field,
    00370                         const std::string& string,
    00371                         std::string::size_type& pos, FieldMap& map,
    00372                         const DataDictionary& dataDictionary )
    00373 { QF_STACK_PUSH(Message::setGroup)
    00374
    00375   int group = field.getField();
    00376   int delim;
    00377   const DataDictionary* pDD = 0;
    00378   if ( !dataDictionary.getGroup( msg, group, delim, pDD ) ) return ;
    00379   Group* pGroup = 0;
    00380
    00381   while ( pos < string.size() )
    00382   {
    00383     std::string::size_type oldPos = pos;
    00384     FieldBase field = extractField( string, pos, &dataDictionary, &dataDictionary, pGroup );
    00385     if ( (field.getField() == delim)
    00386         || (pGroup == 0 && pDD->isField(field.getField())) )
    00387     {
    00388       if ( pGroup )
    00389       {
    00390         map.addGroup( group, *pGroup, false );
    00391         delete pGroup; pGroup = 0;
    00392       }
    00393       pGroup = new Group( field.getField(), delim, pDD->getOrderedFields()  );
    00394     }
    00395     else if ( !pDD->isField( field.getField() ) )
    00396     {
    00397       if ( pGroup )
    00398       {
    00399         map.addGroup( group, *pGroup, false );
    00400         delete pGroup; pGroup = 0;
    00401       }
    00402       pos = oldPos;
    00403       return ;
    00404     }
    00405
    00406     if ( !pGroup ) return ;
    00407     pGroup->setField( field, false );
    00408     setGroup( msg, field, string, pos, *pGroup, *pDD );
    00409   }
    00410
    00411   QF_STACK_POP
    00412 }
    00413
    00414 bool Message::setStringHeader( const std::string& string )
    00415 { QF_STACK_PUSH(Message::setStringHeader)
    00416
    00417   clear();
    00418
    00419   std::string::size_type pos = 0;
    00420   int count = 0;
    00421
    00422   while ( pos < string.size() )
    00423   {
    00424     FieldBase field = extractField( string, pos );
    00425     if ( count < 3 && headerOrder[ count++ ] != field.getField() )
    00426       return false;
    00427
    00428     if ( isHeaderField( field ) )
    00429       m_header.setField( field, false );
    00430     else break;
    00431   }
    00432   return true;
    00433
    00434   QF_STACK_POP
    00435 }
    00436
    00437 bool Message::isHeaderField( int field )
    00438 { QF_STACK_PUSH(Message::isHeaderField)
    00439
    00440   switch ( field )
    00441   {
    00442     case FIELD::BeginString:
    00443     case FIELD::BodyLength:
    00444     case FIELD::MsgType:
    00445     case FIELD::SenderCompID:
    00446     case FIELD::TargetCompID:
    00447     case FIELD::OnBehalfOfCompID:
    00448     case FIELD::DeliverToCompID:
    00449     case FIELD::SecureDataLen:
    00450     case FIELD::MsgSeqNum:
    00451     case FIELD::SenderSubID:
    00452     case FIELD::SenderLocationID:
    00453     case FIELD::TargetSubID:
    00454     case FIELD::TargetLocationID:
    00455     case FIELD::OnBehalfOfSubID:
    00456     case FIELD::OnBehalfOfLocationID:
    00457     case FIELD::DeliverToSubID:
    00458     case FIELD::DeliverToLocationID:
    00459     case FIELD::PossDupFlag:
    00460     case FIELD::PossResend:
    00461     case FIELD::SendingTime:
    00462     case FIELD::OrigSendingTime:
    00463     case FIELD::XmlDataLen:
    00464     case FIELD::XmlData:
    00465     case FIELD::MessageEncoding:
    00466     case FIELD::LastMsgSeqNumProcessed:
    00467     case FIELD::OnBehalfOfSendingTime:
    00468     case FIELD::ApplVerID:
    00469     case FIELD::CstmApplVerID:
    00470     case FIELD::NoHops:
    00471     return true;
    00472     default:
    00473     return false;
    00474   };
    00475
    00476   QF_STACK_POP
    00477 }
    00478
    00479 bool Message::isHeaderField( const FieldBase& field,
    00480                              const DataDictionary* pD )
    00481 { QF_STACK_PUSH(Message::isHeaderField)
    00482
    00483   if ( isHeaderField( field.getField() ) ) return true;
    00484   if ( pD ) return pD->isHeaderField( field.getField() );
    00485   return false;
    00486
    00487   QF_STACK_POP
    00488 }
    00489
    00490 bool Message::isTrailerField( int field )
    00491 { QF_STACK_PUSH(Message::isTrailerField)
    00492
    00493   switch ( field )
    00494   {
    00495     case FIELD::SignatureLength:
    00496     case FIELD::Signature:
    00497     case FIELD::CheckSum:
    00498     return true;
    00499     default:
    00500     return false;
    00501   };
    00502
    00503   QF_STACK_POP
    00504 }
    00505
    00506 bool Message::isTrailerField( const FieldBase& field,
    00507                               const DataDictionary* pD )
    00508 { QF_STACK_PUSH(Message::isTrailerField)
    00509
    00510   if ( isTrailerField( field.getField() ) ) return true;
    00511   if ( pD ) return pD->isTrailerField( field.getField() );
    00512   return false;
    00513
    00514   QF_STACK_POP
    00515 }
    00516
    00517 SessionID Message::getSessionID( const std::string& qualifier ) const
    00518 throw( FieldNotFound )
    00519 { QF_STACK_PUSH(Message::getSessionID)
    00520
    00521   BeginString beginString;
    00522   SenderCompID senderCompID;
    00523   TargetCompID targetCompID;
    00524
    00525   getHeader().getField( beginString );
    00526   getHeader().getField( senderCompID );
    00527   getHeader().getField( targetCompID );
    00528
    00529   return SessionID( beginString, senderCompID, targetCompID, qualifier );
    00530
    00531   QF_STACK_POP
    00532 }
    00533
    00534 void Message::setSessionID( const SessionID& sessionID )
    00535 { QF_STACK_PUSH(Message::setSessionID)
    00536
    00537   getHeader().setField( sessionID.getBeginString() );
    00538   getHeader().setField( sessionID.getSenderCompID() );
    00539   getHeader().setField( sessionID.getTargetCompID() );
    00540
    00541   QF_STACK_POP
    00542 }
    00543
    00544 void Message::validate()
    00545 { QF_STACK_PUSH(Message::validate)
    00546
    00547   try
    00548   {
    00549     const BodyLength& aBodyLength = FIELD_GET_REF( m_header, BodyLength );
    00550
    00551     if ( aBodyLength != bodyLength() )
    00552     {
    00553       std::stringstream text;
    00554       text << "Expected BodyLength=" << bodyLength()
    00555            << ", Recieved BodyLength=" << (int)aBodyLength;
    00556       throw InvalidMessage(text.str());
    00557     }
    00558
    00559     const CheckSum& aCheckSum = FIELD_GET_REF( m_trailer, CheckSum );
    00560
    00561     if ( aCheckSum != checkSum() )
    00562     {
    00563       std::stringstream text;
    00564       text << "Expected CheckSum=" << checkSum()
    00565            << ", Recieved CheckSum=" << (int)aCheckSum;
    00566       throw InvalidMessage(text.str());
    00567     }
    00568   }
    00569   catch ( FieldNotFound& )
    00570   {
    00571     throw InvalidMessage("BodyLength or CheckSum missing");
    00572   }
    00573   catch ( IncorrectDataFormat& )
    00574   {
    00575     throw InvalidMessage("BodyLength or Checksum has wrong format");
    00576   }
    00577
    00578   QF_STACK_POP
    00579 }
    00580 }