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 }

Generated on Mon Apr 5 20:59:50 2010 for QuickFIX by doxygen 1.6.1 written by Dimitri van Heesch, © 1997-2001