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

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

Generated on Mon Jul 24 19:36:29 2006 for QuickFIX by doxygen 1.3.6-20040222 written by Dimitri van Heesch, © 1997-2001