1 /****************************************************************************
2 ** Copyright (c) 2001-2014
3 **
4 ** This file is part of the QuickFIX FIX Engine
5 **
6 ** This file may be distributed under the terms of the quickfixengine.org
7 ** license as defined by quickfixengine.org and appearing in the file
8 ** LICENSE included in the packaging of this file.
9 **
10 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
11 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12 **
13 ** See http://www.quickfixengine.org/LICENSE for licensing information.
14 **
15 ** Contact ask@quickfixengine.org if any conditions of this licensing are
16 ** not clear to you.
17 **
18 ****************************************************************************/
19
20 #ifdef _MSC_VER
21 #include "stdafx.h"
22 #else
23 #include "config.h"
24 #endif
25
26 #include "Utility.h"
27 #include "Values.h"
28 #include "DataDictionaryProvider.h"
29 #include "SessionFactory.h"
30 #include "SessionSettings.h"
31 #include "Session.h"
32
33 #include <memory>
34
35 namespace FIX
36 {
~SessionFactory()37 SessionFactory::~SessionFactory()
38 {
39 }
40
create(const SessionID & sessionID,const Dictionary & settings)41 Session* SessionFactory::create( const SessionID& sessionID,
42 const Dictionary& settings ) throw( ConfigError )
43 {
44 std::string connectionType = settings.getString( CONNECTION_TYPE );
45 if ( connectionType != "acceptor" && connectionType != "initiator" )
46 throw ConfigError( "Invalid ConnectionType" );
47
48 if( connectionType == "acceptor" && settings.has(SESSION_QUALIFIER) )
49 throw ConfigError( "SessionQualifier cannot be used with acceptor." );
50
51 bool useDataDictionary = true;
52 if ( settings.has( USE_DATA_DICTIONARY ) )
53 useDataDictionary = settings.getBool( USE_DATA_DICTIONARY );
54
55 std::string defaultApplVerID;
56 if( sessionID.isFIXT() )
57 {
58 if( !settings.has(DEFAULT_APPLVERID) )
59 {
60 throw ConfigError("ApplVerID is required for FIXT transport");
61 }
62 defaultApplVerID = Message::toApplVerID( settings.getString(DEFAULT_APPLVERID) );
63 }
64
65 DataDictionaryProvider dataDictionaryProvider;
66 if( useDataDictionary )
67 {
68 if( sessionID.isFIXT() )
69 {
70 processFixtDataDictionaries(sessionID, settings, dataDictionaryProvider);
71 }
72 else
73 {
74 processFixDataDictionary(sessionID, settings, dataDictionaryProvider);
75 }
76 }
77
78 bool useLocalTime = false;
79 if( settings.has(USE_LOCAL_TIME) )
80 useLocalTime = settings.getBool( USE_LOCAL_TIME );
81
82 int startDay = -1;
83 int endDay = -1;
84 try
85 {
86 startDay = settings.getDay( START_DAY );
87 endDay = settings.getDay( END_DAY );
88 }
89 catch( ConfigError & ) {}
90 catch( FieldConvertError & e ) { throw ConfigError( e.what() ); }
91
92 UtcTimeOnly startTime;
93 UtcTimeOnly endTime;
94 try
95 {
96 startTime = UtcTimeOnlyConvertor::convert
97 ( settings.getString( START_TIME ) );
98 endTime = UtcTimeOnlyConvertor::convert
99 ( settings.getString( END_TIME ) );
100 }
101 catch ( FieldConvertError & e ) { throw ConfigError( e.what() ); }
102
103 TimeRange utcSessionTime
104 ( startTime, endTime, startDay, endDay );
105 TimeRange localSessionTime
106 ( LocalTimeOnly(startTime.getHour(), startTime.getMinute(), startTime.getSecond()),
107 LocalTimeOnly(endTime.getHour(), endTime.getMinute(), endTime.getSecond()),
108 startDay, endDay );
109 TimeRange sessionTimeRange = useLocalTime ? localSessionTime : utcSessionTime;
110
111 if( startDay >= 0 && endDay < 0 )
112 throw ConfigError( "StartDay used without EndDay" );
113 if( endDay >= 0 && startDay < 0 )
114 throw ConfigError( "EndDay used without StartDay" );
115
116 HeartBtInt heartBtInt( 0 );
117 if ( connectionType == "initiator" )
118 {
119 heartBtInt = HeartBtInt( settings.getInt( HEARTBTINT ) );
120 if ( heartBtInt <= 0 ) throw ConfigError( "Heartbeat must be greater than zero" );
121 }
122
123 SmartPtr<Session> pSession;
124 pSession.reset( new Session( m_application, m_messageStoreFactory,
125 sessionID, dataDictionaryProvider, sessionTimeRange,
126 heartBtInt, m_pLogFactory ) );
127
128 pSession->setSenderDefaultApplVerID(defaultApplVerID);
129
130 int logonDay = startDay;
131 int logoutDay = endDay;
132 try
133 {
134 logonDay = settings.getDay( LOGON_DAY );
135 logoutDay = settings.getDay( LOGOUT_DAY );
136 }
137 catch( ConfigError & ) {}
138 catch( FieldConvertError & e ) { throw ConfigError( e.what() ); }
139
140 UtcTimeOnly logonTime( startTime );
141 UtcTimeOnly logoutTime( endTime );
142 try
143 {
144 logonTime = UtcTimeOnlyConvertor::convert
145 ( settings.getString( LOGON_TIME ) );
146 }
147 catch( ConfigError & ) {}
148 catch( FieldConvertError & e ) { throw ConfigError( e.what() ); }
149 try
150 {
151 logoutTime = UtcTimeOnlyConvertor::convert
152 ( settings.getString( LOGOUT_TIME ) );
153 }
154 catch( ConfigError & ) {}
155 catch( FieldConvertError & e ) { throw ConfigError( e.what() ); }
156
157 TimeRange utcLogonTime
158 ( logonTime, logoutTime, logonDay, logoutDay );
159 TimeRange localLogonTime
160 ( LocalTimeOnly(logonTime.getHour(), logonTime.getMinute(), logonTime.getSecond()),
161 LocalTimeOnly(logoutTime.getHour(), logoutTime.getMinute(), logoutTime.getSecond()),
162 logonDay, logoutDay );
163 TimeRange logonTimeRange = useLocalTime ? localLogonTime : utcLogonTime;
164
165 if( !sessionTimeRange.isInRange(logonTime, logonDay) )
166 throw ConfigError( "LogonTime must be between StartTime and EndTime" );
167 if( !sessionTimeRange.isInRange(logoutTime, logoutDay) )
168 throw ConfigError( "LogoutTime must be between StartTime and EndTime" );
169 pSession->setLogonTime( logonTimeRange );
170
171 if ( settings.has( SEND_REDUNDANT_RESENDREQUESTS ) )
172 pSession->setSendRedundantResendRequests( settings.getBool( SEND_REDUNDANT_RESENDREQUESTS ) );
173 if ( settings.has( CHECK_COMPID ) )
174 pSession->setCheckCompId( settings.getBool( CHECK_COMPID ) );
175 if ( settings.has( CHECK_LATENCY ) )
176 pSession->setCheckLatency( settings.getBool( CHECK_LATENCY ) );
177 if ( settings.has( MAX_LATENCY ) )
178 pSession->setMaxLatency( settings.getInt( MAX_LATENCY ) );
179 if ( settings.has( LOGON_TIMEOUT ) )
180 pSession->setLogonTimeout( settings.getInt( LOGON_TIMEOUT ) );
181 if ( settings.has( LOGOUT_TIMEOUT ) )
182 pSession->setLogoutTimeout( settings.getInt( LOGOUT_TIMEOUT ) );
183 if ( settings.has( RESET_ON_LOGON ) )
184 pSession->setResetOnLogon( settings.getBool( RESET_ON_LOGON ) );
185 if ( settings.has( RESET_ON_LOGOUT ) )
186 pSession->setResetOnLogout( settings.getBool( RESET_ON_LOGOUT ) );
187 if ( settings.has( RESET_ON_DISCONNECT ) )
188 pSession->setResetOnDisconnect( settings.getBool( RESET_ON_DISCONNECT ) );
189 if ( settings.has( REFRESH_ON_LOGON ) )
190 pSession->setRefreshOnLogon( settings.getBool( REFRESH_ON_LOGON ) );
191 if ( settings.has( MILLISECONDS_IN_TIMESTAMP ) )
192 pSession->setTimestampPrecision(3);
193 if ( settings.has( TIMESTAMP_PRECISION ) )
194 pSession->setTimestampPrecision(settings.getInt( TIMESTAMP_PRECISION ) );
195 if ( settings.has( PERSIST_MESSAGES ) )
196 pSession->setPersistMessages( settings.getBool( PERSIST_MESSAGES ) );
197 if ( settings.has( VALIDATE_LENGTH_AND_CHECKSUM ) )
198 pSession->setValidateLengthAndChecksum( settings.getBool( VALIDATE_LENGTH_AND_CHECKSUM ) );
199
200 return pSession.release();
201 }
202
destroy(Session * pSession)203 void SessionFactory::destroy( Session* pSession )
204 {
205 delete pSession;
206 }
207
createDataDictionary(const SessionID & sessionID,const Dictionary & settings,const std::string & settingsKey)208 ptr::shared_ptr<DataDictionary> SessionFactory::createDataDictionary(const SessionID& sessionID,
209 const Dictionary& settings,
210 const std::string& settingsKey) throw(ConfigError)
211 {
212 ptr::shared_ptr<DataDictionary> pDD;
213 std::string path = settings.getString( settingsKey );
214 Dictionaries::iterator i = m_dictionaries.find( path );
215 if ( i != m_dictionaries.end() )
216 {
217 pDD = i->second;
218 }
219 else
220 {
221 bool preserveMsgFldsOrder = false;
222 if( settings.has( PRESERVE_MESSAGE_FIELDS_ORDER ) )
223 preserveMsgFldsOrder = settings.getBool( PRESERVE_MESSAGE_FIELDS_ORDER );
224 pDD = ptr::shared_ptr<DataDictionary>(new DataDictionary( path, preserveMsgFldsOrder ));
225 m_dictionaries[ path ] = pDD;
226 }
227
228 ptr::shared_ptr<DataDictionary> pCopyOfDD = ptr::shared_ptr<DataDictionary>(new DataDictionary(*pDD));
229
230 if( settings.has( VALIDATE_FIELDS_OUT_OF_ORDER ) )
231 pCopyOfDD->checkFieldsOutOfOrder( settings.getBool( VALIDATE_FIELDS_OUT_OF_ORDER ) );
232 if( settings.has( VALIDATE_FIELDS_HAVE_VALUES ) )
233 pCopyOfDD->checkFieldsHaveValues( settings.getBool( VALIDATE_FIELDS_HAVE_VALUES ) );
234 if( settings.has( VALIDATE_USER_DEFINED_FIELDS ) )
235 pCopyOfDD->checkUserDefinedFields( settings.getBool( VALIDATE_USER_DEFINED_FIELDS ) );
236 if( settings.has( ALLOW_UNKNOWN_MSG_FIELDS ) )
237 pCopyOfDD->allowUnknownMsgFields( settings.getBool( ALLOW_UNKNOWN_MSG_FIELDS ) );
238
239 return pCopyOfDD;
240 }
241
processFixtDataDictionaries(const SessionID & sessionID,const Dictionary & settings,DataDictionaryProvider & provider)242 void SessionFactory::processFixtDataDictionaries(const SessionID& sessionID,
243 const Dictionary& settings,
244 DataDictionaryProvider& provider) throw(ConfigError)
245 {
246 ptr::shared_ptr<DataDictionary> pDataDictionary = createDataDictionary(sessionID, settings, TRANSPORT_DATA_DICTIONARY);
247 provider.addTransportDataDictionary(sessionID.getBeginString(), pDataDictionary);
248
249 for(Dictionary::const_iterator data = settings.begin(); data != settings.end(); ++data)
250 {
251 const std::string& key = data->first;
252 const std::string frontKey = key.substr(0, strlen(APP_DATA_DICTIONARY));
253 if( frontKey == string_toUpper(APP_DATA_DICTIONARY) )
254 {
255 if( key == string_toUpper(APP_DATA_DICTIONARY) )
256 {
257 provider.addApplicationDataDictionary(Message::toApplVerID(settings.getString(DEFAULT_APPLVERID)),
258 createDataDictionary(sessionID, settings, APP_DATA_DICTIONARY));
259 }
260 else
261 {
262 std::string::size_type offset = key.find('.');
263 if( offset == std::string::npos )
264 throw ConfigError(std::string("Malformed ") + APP_DATA_DICTIONARY + ": " + key);
265 std::string beginStringQualifier = key.substr(offset+1);
266 provider.addApplicationDataDictionary(Message::toApplVerID(beginStringQualifier),
267 createDataDictionary(sessionID, settings, key));
268 }
269 }
270 }
271 }
272
processFixDataDictionary(const SessionID & sessionID,const Dictionary & settings,DataDictionaryProvider & provider)273 void SessionFactory::processFixDataDictionary(const SessionID& sessionID,
274 const Dictionary& settings,
275 DataDictionaryProvider& provider) throw(ConfigError)
276 {
277 ptr::shared_ptr<DataDictionary> pDataDictionary = createDataDictionary(sessionID, settings, DATA_DICTIONARY);
278 provider.addTransportDataDictionary(sessionID.getBeginString(), pDataDictionary);
279 provider.addApplicationDataDictionary(Message::toApplVerID(sessionID.getBeginString()), pDataDictionary);
280 }
281 }
282