public ClientSessionFactory createSessionFactory() throws HornetQException {
    assertOpen();

    initialise();

    if (initialConnectors == null && discoveryGroup != null) {
      // Wait for an initial broadcast to give us at least one node in the cluster
      long timeout =
          clusterConnection ? 0 : discoveryGroupConfiguration.getDiscoveryInitialWaitTimeout();
      boolean ok = discoveryGroup.waitForBroadcast(timeout);

      if (!ok) {
        throw HornetQMessageBundle.BUNDLE.connectionTimedOutInInitialBroadcast();
      }
    }

    ClientSessionFactoryInternal factory = null;

    synchronized (this) {
      boolean retry;
      int attempts = 0;
      do {
        retry = false;

        TransportConfiguration tc = selectConnector();
        if (tc == null) {
          throw HornetQMessageBundle.BUNDLE.noTCForSessionFactory();
        }

        // try each factory in the list until we find one which works

        try {
          factory =
              new ClientSessionFactoryImpl(
                  this,
                  tc,
                  callTimeout,
                  callFailoverTimeout,
                  clientFailureCheckPeriod,
                  connectionTTL,
                  retryInterval,
                  retryIntervalMultiplier,
                  maxRetryInterval,
                  reconnectAttempts,
                  threadPool,
                  scheduledThreadPool,
                  interceptors);
          try {
            addToConnecting(factory);
            factory.connect(initialConnectAttempts, failoverOnInitialConnection);
          } finally {
            removeFromConnecting(factory);
          }
        } catch (HornetQException e) {
          factory.close();
          factory = null;
          if (e.getType() == HornetQExceptionType.NOT_CONNECTED) {
            attempts++;

            if (topologyArray != null && attempts == topologyArray.length) {
              throw HornetQMessageBundle.BUNDLE.cannotConnectToServers();
            }
            if (topologyArray == null
                && initialConnectors != null
                && attempts == initialConnectors.length) {
              throw HornetQMessageBundle.BUNDLE.cannotConnectToServers();
            }
            retry = true;
          } else {
            throw e;
          }
        }
      } while (retry);

      if (ha || clusterConnection) {
        final long timeout = System.currentTimeMillis() + 30000;
        while (!isClosed() && !receivedTopology && timeout > System.currentTimeMillis()) {
          // Now wait for the topology

          try {
            wait(1000);
          } catch (InterruptedException ignore) {
          }
        }

        if (System.currentTimeMillis() > timeout && !receivedTopology) {
          throw HornetQMessageBundle.BUNDLE.connectionTimedOutOnReceiveTopology(discoveryGroup);
        }
      }

      addFactory(factory);

      return factory;
    }
  }