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