@Override
  protected ServerLocator internalNewObject(URI uri, Map<String, String> query, String name)
      throws Exception {
    ConnectionOptions options = newConnectionOptions(uri, query);

    DiscoveryGroupConfiguration dgc =
        getDiscoveryGroupConfiguration(uri, query, getHost(uri), getPort(uri), name);

    if (options.isHa()) {
      return ActiveMQClient.createServerLocatorWithHA(dgc);
    } else {
      return ActiveMQClient.createServerLocatorWithoutHA(dgc);
    }
  }
 /**
  * Update the options on a running socket manager. Parameters in the I2PSocketOptions interface
  * may be changed directly with the setters; no need to use this method for those. This does NOT
  * update the underlying I2CP or tunnel options; use getSession().updateOptions() for that.
  *
  * <p>TODO There is no way to update the options on a subsession.
  *
  * @param options as created from a call to buildOptions(properties), non-null
  */
 public void setDefaultOptions(I2PSocketOptions options) {
   if (!(options instanceof ConnectionOptions)) throw new IllegalArgumentException();
   if (_log.shouldLog(Log.WARN))
     _log.warn("Changing options from:\n " + _defaultOptions + "\nto:\n " + options);
   _defaultOptions.updateAll((ConnectionOptions) options);
   _connectionManager.updateOptions();
 }
 /**
  * @return a new subsession, non-null
  * @param privateKeyStream null for transient, if non-null must have same encryption keys as
  *     primary session and different signing keys
  * @param opts subsession options if any, may be null
  * @since 0.9.21
  */
 public I2PSession addSubsession(InputStream privateKeyStream, Properties opts)
     throws I2PSessionException {
   if (privateKeyStream == null) {
     // We don't actually need the same pubkey in the dest, just in the LS.
     // The dest one is unused. But this is how we find the LS keys
     // to reuse in RequestLeaseSetMessageHandler.
     ByteArrayOutputStream keyStream = new ByteArrayOutputStream(1024);
     try {
       SigType type = getSigType(opts);
       if (type != SigType.DSA_SHA1) {
         // hassle, have to set up the padding and cert, see I2PClientImpl
         throw new I2PSessionException("type " + type + " unsupported");
       }
       PublicKey pub = _session.getMyDestination().getPublicKey();
       PrivateKey priv = _session.getDecryptionKey();
       SimpleDataStructure[] keys = _context.keyGenerator().generateSigningKeys(type);
       pub.writeBytes(keyStream);
       keys[0].writeBytes(keyStream); // signing pub
       Certificate.NULL_CERT.writeBytes(keyStream);
       priv.writeBytes(keyStream);
       keys[1].writeBytes(keyStream); // signing priv
     } catch (Exception e) {
       throw new I2PSessionException("Error creating keys", e);
     }
     privateKeyStream = new ByteArrayInputStream(keyStream.toByteArray());
   }
   I2PSession rv = _session.addSubsession(privateKeyStream, opts);
   boolean added = _subsessions.add(rv);
   if (!added) {
     // shouldn't happen
     _session.removeSubsession(rv);
     throw new I2PSessionException("dup");
   }
   ConnectionOptions defaultOptions = new ConnectionOptions(opts);
   int protocol =
       defaultOptions.getEnforceProtocol() ? I2PSession.PROTO_STREAMING : I2PSession.PROTO_ANY;
   rv.addMuxedSessionListener(
       _connectionManager.getMessageHandler(), protocol, defaultOptions.getLocalPort());
   if (_log.shouldLog(Log.WARN)) _log.warn("Added subsession " + rv);
   return rv;
 }
 protected BaseOverthereConnection(
     final String protocol,
     final ConnectionOptions options,
     final AddressPortMapper mapper,
     final boolean canStartProcess) {
   this.protocol = checkNotNull(protocol, "Cannot create OverthereConnection with null protocol");
   this.os = options.getEnum(OPERATING_SYSTEM, OperatingSystemFamily.class);
   this.connectionTimeoutMillis =
       options.getInteger(CONNECTION_TIMEOUT_MILLIS, DEFAULT_CONNECTION_TIMEOUT_MILLIS);
   this.temporaryDirectoryPath =
       options.get(TEMPORARY_DIRECTORY_PATH, os.getDefaultTemporaryDirectoryPath());
   this.deleteTemporaryDirectoryOnDisconnect =
       options.getBoolean(
           TEMPORARY_DIRECTORY_DELETE_ON_DISCONNECT,
           DEFAULT_TEMPORARY_DIRECTORY_DELETE_ON_DISCONNECT);
   this.temporaryFileCreationRetries =
       options.getInteger(
           TEMPORARY_FILE_CREATION_RETRIES, DEFAULT_TEMPORARY_FILE_CREATION_RETRIES);
   this.canStartProcess = canStartProcess;
   this.mapper =
       checkNotNull(mapper, "Cannot create OverthereConnection with null addres-port mapper");
   this.options = options;
 }
  /**
   * Create a new connected socket. Blocks until the socket is created, unless the connectDelay
   * option (i2p.streaming.connectDelay) is set and greater than zero. If so this will return
   * immediately, and the client may quickly write initial data to the socket and this data will be
   * bundled in the SYN packet.
   *
   * @param peer Destination to connect to
   * @param options I2P socket options to be used for connecting, may be null
   * @return I2PSocket if successful
   * @throws NoRouteToHostException if the peer is not found or not reachable
   * @throws I2PException if there is some other I2P-related problem
   */
  public I2PSocket connect(Destination peer, I2PSocketOptions options)
      throws I2PException, NoRouteToHostException {
    if (options == null) options = _defaultOptions;
    ConnectionOptions opts = null;
    if (options instanceof ConnectionOptions)
      opts = new ConnectionOptions((ConnectionOptions) options);
    else opts = new ConnectionOptions(options);

    if (_log.shouldLog(Log.INFO))
      _log.info(
          "Connecting to "
              + peer.calculateHash().toBase64().substring(0, 6)
              + " with options: "
              + opts);
    // pick the subsession here
    I2PSession session = _session;
    if (!_subsessions.isEmpty()) {
      updateUserDsaList();
      Hash h = peer.calculateHash();
      if (_dsaOnly.contains(h) || (!_userDsaOnly.isEmpty() && _userDsaOnly.contains(h))) {
        // FIXME just taking the first one for now
        for (I2PSession sess : _subsessions) {
          if (sess.getMyDestination().getSigType() == SigType.DSA_SHA1) {
            session = sess;
            break;
          }
        }
      }
    }
    verifySession(session);
    // the following blocks unless connect delay > 0
    Connection con = _connectionManager.connect(peer, opts, session);
    if (con == null)
      throw new TooManyStreamsException("Too many streams, max " + _defaultOptions.getMaxConns());
    I2PSocketFull socket = new I2PSocketFull(con, _context);
    con.setSocket(socket);
    if (con.getConnectionError() != null) {
      con.disconnect(false);
      throw new NoRouteToHostException(con.getConnectionError());
    }
    return socket;
  }
 /**
  * Like connect() but returns a real Socket, and throws only IOE, for easier porting of apps.
  *
  * @param timeout ms if > 0, forces blocking (disables connectDelay)
  * @since 0.8.4
  */
 public Socket connectToSocket(Destination peer, int timeout) throws IOException {
   ConnectionOptions opts = new ConnectionOptions(_defaultOptions);
   opts.setConnectTimeout(timeout);
   if (timeout > 0) opts.setConnectDelay(-1);
   return connectToSocket(peer, opts);
 }
 /**
  * Ping the specified peer, returning true if they replied to the ping within the timeout
  * specified, false otherwise. This call blocks.
  *
  * <p>Uses the ports from the default options.
  *
  * <p>TODO There is no way to ping on a subsession.
  *
  * @param peer
  * @param timeoutMs timeout in ms, greater than zero
  * @return true on success, false on failure
  * @throws IllegalArgumentException
  */
 public boolean ping(Destination peer, long timeoutMs) {
   if (timeoutMs <= 0) throw new IllegalArgumentException("bad timeout");
   return _connectionManager.ping(
       peer, _defaultOptions.getLocalPort(), _defaultOptions.getPort(), timeoutMs);
 }
 /**
  * Create a modified copy of the current options, to be used in a setDefaultOptions() call.
  *
  * <p>As of 0.9.19, defaults in opts are honored.
  *
  * @param opts The new options, may be null
  */
 public I2PSocketOptions buildOptions(Properties opts) {
   ConnectionOptions curOpts = new ConnectionOptions(_defaultOptions);
   curOpts.setProperties(opts);
   return curOpts;
 }