class DefaultSessionFactory implements SessionFactory {

    public Session create(SessionID sessionID, SessionSettings settings) throws ConfigError {
        try {
            String connectionType = null;

            final boolean rejectGarbledMessage = getSetting(settings, sessionID,
                    Session.SETTING_REJECT_GARBLED_MESSAGE, false);

            final boolean validateChecksum = getSetting(settings, sessionID,
                    Session.SETTING_VALIDATE_CHECKSUM, true);

            if (rejectGarbledMessage && !validateChecksum) {
                throw new ConfigError("Not possible to reject garbled message and process " +
                        "messages with invalid checksum at the same time.");
            }

            final boolean rejectInvalidMessage = getSetting(settings, sessionID,
                    Session.SETTING_REJECT_INVALID_MESSAGE, true);

            final boolean rejectMessageOnUnhandledException = getSetting(settings, sessionID,
                    Session.SETTING_REJECT_MESSAGE_ON_UNHANDLED_EXCEPTION, false);

            final boolean requiresOrigSendingTime = getSetting(settings, sessionID,
                    Session.SETTING_REQUIRES_ORIG_SENDING_TIME, true);

            if (settings.isSetting(sessionID, SessionFactory.SETTING_CONNECTION_TYPE)) {
                connectionType = settings.getString(sessionID,
                        SessionFactory.SETTING_CONNECTION_TYPE);
            }

            if (connectionType == null) {
                throw new ConfigError("Missing ConnectionType");
            }

            if (!connectionType.equals(SessionFactory.ACCEPTOR_CONNECTION_TYPE)
                    && !connectionType.equals(SessionFactory.INITIATOR_CONNECTION_TYPE)) {
                throw new ConfigError("Invalid ConnectionType");
            }

            if (connectionType.equals(SessionFactory.ACCEPTOR_CONNECTION_TYPE)
                    && settings.isSetting(sessionID, SessionSettings.SESSION_QUALIFIER)) {
                throw new ConfigError("SessionQualifier cannot be used with acceptor.");
            }

            if (connectionType.equals(SessionFactory.INITIATOR_CONNECTION_TYPE)
                    && settings.isSetting(sessionID, Session.SETTING_ALLOWED_REMOTE_ADDRESSES)) {
                throw new ConfigError("AllowedRemoteAddresses cannot be used with initiator");
            }

            DefaultApplVerID senderDefaultApplVerID = null;

            if (sessionID.isFIXT()) {
                if (!settings.isSetting(sessionID, Session.SETTING_DEFAULT_APPL_VER_ID)) {
                    throw new ConfigError(Session.SETTING_DEFAULT_APPL_VER_ID
                            + " is required for FIXT transport");
                }
                senderDefaultApplVerID = new DefaultApplVerID(toApplVerID(
                        settings.getString(sessionID, Session.SETTING_DEFAULT_APPL_VER_ID))
                        .getValue());
            }

            boolean useDataDictionary = true;
            if (settings.isSetting(sessionID, Session.SETTING_USE_DATA_DICTIONARY)) {
                useDataDictionary = settings
                        .getBool(sessionID, Session.SETTING_USE_DATA_DICTIONARY);
            }

            DefaultDataDictionaryProvider dataDictionaryProvider = null;
            if (useDataDictionary) {
                dataDictionaryProvider = new DefaultDataDictionaryProvider();
                if (sessionID.isFIXT()) {
                    processFixtDataDictionaries(sessionID, settings, dataDictionaryProvider);
                } else {
                    processPreFixtDataDictionary(sessionID, settings, dataDictionaryProvider);
                }
            }

            int heartbeatInterval = 0;
            if (connectionType.equals(SessionFactory.INITIATOR_CONNECTION_TYPE)) {
                heartbeatInterval = (int) settings.getLong(sessionID, Session.SETTING_HEARTBTINT);
                if (heartbeatInterval <= 0) {
                    throw new ConfigError("Heartbeat must be greater than zero");
                }
            }

            final boolean checkLatency = getSetting(settings, sessionID, Session.SETTING_CHECK_LATENCY,
                    true);
            final int maxLatency = getSetting(settings, sessionID, Session.SETTING_MAX_LATENCY,
                    Session.DEFAULT_MAX_LATENCY);
            final double testRequestDelayMultiplier = getSetting(settings, sessionID,
                    Session.SETTING_TEST_REQUEST_DELAY_MULTIPLIER,
                    Session.DEFAULT_TEST_REQUEST_DELAY_MULTIPLIER);
            final double heartBeatTimeoutMultiplier = getSetting(settings, sessionID,
                    Session.SETTING_HEARTBEAT_TIMEOUT_MULTIPLIER,
                    Session.DEFAULT_HEARTBEAT_TIMEOUT_MULTIPLIER);

            final UtcTimestampPrecision timestampPrecision = getTimestampPrecision(settings, sessionID,
                    UtcTimestampPrecision.MILLIS);

            final boolean resetOnLogout = getSetting(settings, sessionID,
                    Session.SETTING_RESET_ON_LOGOUT, false);

            final boolean resetOnDisconnect = getSetting(settings, sessionID,
                    Session.SETTING_RESET_ON_DISCONNECT, false);

            final boolean resetOnLogon = getSetting(settings, sessionID, Session.SETTING_RESET_ON_LOGON,
                    false);

            final boolean refreshOnLogon = getSetting(settings, sessionID,
                    Session.SETTING_REFRESH_ON_LOGON, false);

            final boolean checkCompID = getSetting(settings, sessionID, Session.SETTING_CHECK_COMP_ID,
                    true);

            final boolean redundantResentRequestAllowed = getSetting(settings, sessionID,
                    Session.SETTING_SEND_REDUNDANT_RESEND_REQUEST, false);

            final boolean persistMessages = getSetting(settings, sessionID,
                    Session.SETTING_PERSIST_MESSAGES, true);

            final boolean useClosedIntervalForResend = getSetting(settings, sessionID,
                    Session.SETTING_USE_CLOSED_RESEND_INTERVAL, false);

            final int logonTimeout = getSetting(settings, sessionID, Session.SETTING_LOGON_TIMEOUT, 10);
            final int logoutTimeout = getSetting(settings, sessionID, Session.SETTING_LOGOUT_TIMEOUT, 2);

            final boolean validateSequenceNumbers = getSetting(settings, sessionID, Session.SETTING_VALIDATE_SEQUENCE_NUMBERS, true);
            final boolean validateIncomingMessage = getSetting(settings, sessionID, Session.SETTING_VALIDATE_INCOMING_MESSAGE, true);
            final boolean resetOnError = getSetting(settings, sessionID, Session.SETTING_RESET_ON_ERROR, false);
            final boolean disconnectOnError = getSetting(settings, sessionID, Session.SETTING_DISCONNECT_ON_ERROR, false);
            final boolean disableHeartBeatCheck = getSetting(settings, sessionID, Session.SETTING_DISABLE_HEART_BEAT_CHECK, false);
            final boolean forceResendWhenCorruptedStore = getSetting(settings, sessionID, Session.SETTING_FORCE_RESEND_WHEN_CORRUPTED_STORE, false);
            final boolean enableNextExpectedMsgSeqNum = getSetting(settings, sessionID, Session.SETTING_ENABLE_NEXT_EXPECTED_MSG_SEQ_NUM, false);
            final boolean enableLastMsgSeqNumProcessed = getSetting(settings, sessionID, Session.SETTING_ENABLE_LAST_MSG_SEQ_NUM_PROCESSED, false);
            final int resendRequestChunkSize = getSetting(settings, sessionID, Session.SETTING_RESEND_REQUEST_CHUNK_SIZE, Session.DEFAULT_RESEND_RANGE_CHUNK_SIZE);

            final int[] logonIntervals = getLogonIntervalsInSeconds(settings, sessionID);
            final Set<InetAddress> allowedRemoteAddresses = getInetAddresses(settings, sessionID);

            final SessionSchedule sessionSchedule = sessionScheduleFactory.create(sessionID, settings);

            final List<StringField> logonTags = getLogonTags(settings, sessionID);

            final Session session = new Session(application, messageStoreFactory, sessionID,
                    dataDictionaryProvider, sessionSchedule, logFactory,
                    messageFactory, heartbeatInterval, checkLatency, maxLatency, timestampPrecision,
                    resetOnLogon, resetOnLogout, resetOnDisconnect, refreshOnLogon, checkCompID,
                    redundantResentRequestAllowed, persistMessages, useClosedIntervalForResend,
                    testRequestDelayMultiplier, senderDefaultApplVerID, validateSequenceNumbers,
                    logonIntervals, resetOnError, disconnectOnError, disableHeartBeatCheck, rejectGarbledMessage,
                    rejectInvalidMessage, rejectMessageOnUnhandledException, requiresOrigSendingTime,
                    forceResendWhenCorruptedStore, allowedRemoteAddresses, validateIncomingMessage,
                    resendRequestChunkSize, enableNextExpectedMsgSeqNum, enableLastMsgSeqNumProcessed,
                    validateChecksum, logonTags, heartBeatTimeoutMultiplier);

            session.setLogonTimeout(logonTimeout);
            session.setLogoutTimeout(logoutTimeout);

            final int maxScheduledWriteRequests = getSetting(settings, sessionID, Session.SETTING_MAX_SCHEDULED_WRITE_REQUESTS, 0);
            session.setMaxScheduledWriteRequests(maxScheduledWriteRequests);

            //
            // Session registration and creation callback is done here instead of in
            // session constructor to eliminate the possibility of other threads
            // accessing the session before it's fully constructed.
            //

            application.onCreate(sessionID);

            return session;
        } catch (final FieldConvertError e) {
            throw new ConfigError(e.getMessage());
        }
    }

    public  DefaultSessionFactory(Application application, MessageStoreFactory messageStoreFactory,
            LogFactory logFactory);
    public  DefaultSessionFactory(Application application, MessageStoreFactory messageStoreFactory,
            LogFactory logFactory, MessageFactory messageFactory);
    public  DefaultSessionFactory(Application application, MessageStoreFactory messageStoreFactory,
                                 LogFactory logFactory, MessageFactory messageFactory,
                                 SessionScheduleFactory sessionScheduleFactory);

}