00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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 "Utility.h"
00028 #include "Values.h"
00029 #include "DataDictionaryProvider.h"
00030 #include "SessionFactory.h"
00031 #include "SessionSettings.h"
00032 #include "Session.h"
00033
00034 namespace FIX
00035 {
00036 SessionFactory::~SessionFactory()
00037 { QF_STACK_IGNORE_BEGIN
00038 Dictionaries::iterator i = m_dictionaries.begin();
00039 for ( ; i != m_dictionaries.end(); ++i )
00040 delete i->second;
00041 QF_STACK_IGNORE_END
00042 }
00043
00044 Session* SessionFactory::create( const SessionID& sessionID,
00045 const Dictionary& settings ) throw( ConfigError )
00046 { QF_STACK_PUSH(SessionFactory::create)
00047
00048 std::string connectionType = settings.getString( CONNECTION_TYPE );
00049 if ( connectionType != "acceptor" && connectionType != "initiator" )
00050 throw ConfigError( "Invalid ConnectionType" );
00051
00052 if( connectionType == "acceptor" && settings.has(SESSION_QUALIFIER) )
00053 throw ConfigError( "SessionQualifier cannot be used with acceptor." );
00054
00055 bool useDataDictionary = true;
00056 if ( settings.has( USE_DATA_DICTIONARY ) )
00057 useDataDictionary = settings.getBool( USE_DATA_DICTIONARY );
00058
00059 std::string defaultApplVerID;
00060 if( sessionID.isFIXT() )
00061 {
00062 if( !settings.has(DEFAULT_APPLVERID) )
00063 {
00064 throw ConfigError("ApplVerID is required for FIXT transport");
00065 }
00066 defaultApplVerID = Message::toApplVerID( settings.getString(DEFAULT_APPLVERID) );
00067 }
00068
00069 DataDictionaryProvider dataDictionaryProvider;
00070 if( useDataDictionary )
00071 {
00072 if( sessionID.isFIXT() )
00073 {
00074 processFixtDataDictionaries(sessionID, settings, dataDictionaryProvider);
00075 }
00076 else
00077 {
00078 processFixDataDictionary(sessionID, settings, dataDictionaryProvider);
00079 }
00080 }
00081
00082 bool useLocalTime = false;
00083 if( settings.has(USE_LOCAL_TIME) )
00084 useLocalTime = settings.getBool( USE_LOCAL_TIME );
00085
00086 int startDay = -1;
00087 int endDay = -1;
00088 try
00089 {
00090 startDay = settings.getDay( START_DAY );
00091 endDay = settings.getDay( END_DAY );
00092 }
00093 catch( ConfigError & ) {}
00094 catch( FieldConvertError & e ) { throw ConfigError( e.what() ); }
00095
00096 UtcTimeOnly startTime;
00097 UtcTimeOnly endTime;
00098 try
00099 {
00100 startTime = UtcTimeOnlyConvertor::convert
00101 ( settings.getString( START_TIME ) );
00102 endTime = UtcTimeOnlyConvertor::convert
00103 ( settings.getString( END_TIME ) );
00104 }
00105 catch ( FieldConvertError & e ) { throw ConfigError( e.what() ); }
00106
00107 TimeRange utcSessionTime
00108 ( startTime, endTime, startDay, endDay );
00109 TimeRange localSessionTime
00110 ( LocalTimeOnly(startTime.getHour(), startTime.getMinute(), startTime.getSecond()),
00111 LocalTimeOnly(endTime.getHour(), endTime.getMinute(), endTime.getSecond()),
00112 startDay, endDay );
00113 TimeRange sessionTimeRange = useLocalTime ? localSessionTime : utcSessionTime;
00114
00115 if( startDay >= 0 && endDay < 0 )
00116 throw ConfigError( "StartDay used without EndDay" );
00117 if( endDay >= 0 && startDay < 0 )
00118 throw ConfigError( "EndDay used without StartDay" );
00119
00120 HeartBtInt heartBtInt( 0 );
00121 if ( connectionType == "initiator" )
00122 {
00123 heartBtInt = HeartBtInt( settings.getLong( HEARTBTINT ) );
00124 if ( heartBtInt <= 0 ) throw ConfigError( "Heartbeat must be greater than zero" );
00125 }
00126
00127 Session* pSession = 0;
00128 pSession = new Session( m_application, m_messageStoreFactory,
00129 sessionID, dataDictionaryProvider, sessionTimeRange,
00130 heartBtInt, m_pLogFactory );
00131
00132 pSession->setSenderDefaultApplVerID(defaultApplVerID);
00133
00134 int logonDay = startDay;
00135 int logoutDay = endDay;
00136 try
00137 {
00138 logonDay = settings.getDay( LOGON_DAY );
00139 logoutDay = settings.getDay( LOGOUT_DAY );
00140 }
00141 catch( ConfigError & ) {}
00142 catch( FieldConvertError & e ) { throw ConfigError( e.what() ); }
00143
00144 UtcTimeOnly logonTime( startTime );
00145 UtcTimeOnly logoutTime( endTime );
00146 try
00147 {
00148 logonTime = UtcTimeOnlyConvertor::convert
00149 ( settings.getString( LOGON_TIME ) );
00150 }
00151 catch( ConfigError & ) {}
00152 catch( FieldConvertError & e ) { throw ConfigError( e.what() ); }
00153 try
00154 {
00155 logoutTime = UtcTimeOnlyConvertor::convert
00156 ( settings.getString( LOGOUT_TIME ) );
00157 }
00158 catch( ConfigError & ) {}
00159 catch( FieldConvertError & e ) { throw ConfigError( e.what() ); }
00160
00161 TimeRange utcLogonTime
00162 ( logonTime, logoutTime, logonDay, logoutDay );
00163 TimeRange localLogonTime
00164 ( LocalTimeOnly(logonTime.getHour(), logonTime.getMinute(), logonTime.getSecond()),
00165 LocalTimeOnly(logoutTime.getHour(), logoutTime.getMinute(), logoutTime.getSecond()),
00166 logonDay, logoutDay );
00167 TimeRange logonTimeRange = useLocalTime ? localLogonTime : utcLogonTime;
00168
00169 if( !sessionTimeRange.isInRange(logonTime) )
00170 throw ConfigError( "LogonTime must be between StartTime and EndTime" );
00171 if( !sessionTimeRange.isInRange(logoutTime) )
00172 throw ConfigError( "LogoutTime must be between StartTime and EndTime" );
00173 pSession->setLogonTime( logonTimeRange );
00174
00175 if ( settings.has( SEND_REDUNDANT_RESENDREQUESTS ) )
00176 pSession->setSendRedundantResendRequests( settings.getBool( SEND_REDUNDANT_RESENDREQUESTS ) );
00177 if ( settings.has( CHECK_COMPID ) )
00178 pSession->setCheckCompId( settings.getBool( CHECK_COMPID ) );
00179 if ( settings.has( CHECK_LATENCY ) )
00180 pSession->setCheckLatency( settings.getBool( CHECK_LATENCY ) );
00181 if ( settings.has( MAX_LATENCY ) )
00182 pSession->setMaxLatency( settings.getLong( MAX_LATENCY ) );
00183 if ( settings.has( LOGON_TIMEOUT ) )
00184 pSession->setLogonTimeout( settings.getLong( LOGON_TIMEOUT ) );
00185 if ( settings.has( LOGOUT_TIMEOUT ) )
00186 pSession->setLogoutTimeout( settings.getLong( LOGOUT_TIMEOUT ) );
00187 if ( settings.has( RESET_ON_LOGON ) )
00188 pSession->setResetOnLogon( settings.getBool( RESET_ON_LOGON ) );
00189 if ( settings.has( RESET_ON_LOGOUT ) )
00190 pSession->setResetOnLogout( settings.getBool( RESET_ON_LOGOUT ) );
00191 if ( settings.has( RESET_ON_DISCONNECT ) )
00192 pSession->setResetOnDisconnect( settings.getBool( RESET_ON_DISCONNECT ) );
00193 if ( settings.has( REFRESH_ON_LOGON ) )
00194 pSession->setRefreshOnLogon( settings.getBool( REFRESH_ON_LOGON ) );
00195 if ( settings.has( MILLISECONDS_IN_TIMESTAMP ) )
00196 pSession->setMillisecondsInTimeStamp( settings.getBool( MILLISECONDS_IN_TIMESTAMP ) );
00197 if ( settings.has( PERSIST_MESSAGES ) )
00198 pSession->setPersistMessages( settings.getBool( PERSIST_MESSAGES ) );
00199
00200 return pSession;
00201
00202 QF_STACK_POP
00203 }
00204
00205 DataDictionary SessionFactory::createDataDictionary(const SessionID& sessionID,
00206 const Dictionary& settings,
00207 const std::string& settingsKey) throw(ConfigError)
00208 { QF_STACK_PUSH(SessionFactory::createDataDictionary)
00209
00210 DataDictionary dataDictionary;
00211 std::string path = settings.getString( settingsKey );
00212 Dictionaries::iterator i = m_dictionaries.find( path );
00213 if ( i != m_dictionaries.end() )
00214 dataDictionary = *i->second;
00215 else
00216 {
00217 DataDictionary* p = new DataDictionary( path );
00218 dataDictionary = *p;
00219 m_dictionaries[ path ] = p;
00220 }
00221
00222 if( settings.has( VALIDATE_FIELDS_OUT_OF_ORDER ) )
00223 {
00224 dataDictionary.checkFieldsOutOfOrder
00225 ( settings.getBool( VALIDATE_FIELDS_OUT_OF_ORDER ) );
00226 }
00227 if( settings.has( VALIDATE_FIELDS_HAVE_VALUES ) )
00228 {
00229 dataDictionary.checkFieldsHaveValues
00230 ( settings.getBool( VALIDATE_FIELDS_HAVE_VALUES ) );
00231 }
00232 if( settings.has( VALIDATE_USER_DEFINED_FIELDS ) )
00233 {
00234 dataDictionary.checkUserDefinedFields
00235 ( settings.getBool( VALIDATE_USER_DEFINED_FIELDS ) );
00236 }
00237
00238 return dataDictionary;
00239
00240 QF_STACK_POP
00241 }
00242
00243 void SessionFactory::processFixtDataDictionaries(const SessionID& sessionID,
00244 const Dictionary& settings,
00245 DataDictionaryProvider& provider) throw(ConfigError)
00246 { QF_STACK_PUSH(SessionFactory::processFixtDataDictionaries)
00247
00248 DataDictionary dataDictionary = createDataDictionary(sessionID, settings, TRANSPORT_DATA_DICTIONARY);
00249 provider.addTransportDataDictionary(sessionID.getBeginString(), dataDictionary);
00250
00251 for(Dictionary::const_iterator data = settings.begin(); data != settings.end(); ++data)
00252 {
00253 const std::string& key = data->first;
00254 const std::string frontKey = key.substr(0, strlen(APP_DATA_DICTIONARY));
00255 if( frontKey == string_toUpper(APP_DATA_DICTIONARY) )
00256 {
00257 if( key == string_toUpper(APP_DATA_DICTIONARY) )
00258 {
00259 DataDictionary dataDictionary = createDataDictionary(sessionID, settings, APP_DATA_DICTIONARY);
00260 provider.addApplicationDataDictionary(Message::toApplVerID(settings.getString(DEFAULT_APPLVERID)), dataDictionary);
00261 }
00262 else
00263 {
00264 std::string::size_type offset = key.find('.');
00265 if( offset == std::string::npos )
00266 throw ConfigError(std::string("Malformed ") + APP_DATA_DICTIONARY + ": " + key);
00267 std::string beginStringQualifier = key.substr(offset+1);
00268 DataDictionary dataDictionary = createDataDictionary(sessionID, settings, key);
00269 provider.addApplicationDataDictionary(Message::toApplVerID(beginStringQualifier), dataDictionary);
00270 }
00271 }
00272 }
00273
00274 QF_STACK_POP
00275 }
00276
00277 void SessionFactory::processFixDataDictionary(const SessionID& sessionID,
00278 const Dictionary& settings,
00279 DataDictionaryProvider& provider) throw(ConfigError)
00280 { QF_STACK_PUSH(SessionFactory::processFixDataDictionary)
00281
00282 DataDictionary dataDictionary = createDataDictionary(sessionID, settings, DATA_DICTIONARY);
00283 provider.addTransportDataDictionary(sessionID.getBeginString(), dataDictionary);
00284 provider.addApplicationDataDictionary(Message::toApplVerID(sessionID.getBeginString()), dataDictionary);
00285
00286 QF_STACK_POP
00287 }
00288 }