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

Generated on Mon Jun 23 2014 23:49:38 for QuickFIX by doxygen 1.7.6.1 written by Dimitri van Heesch, © 1997-2001