/**
   * Load saved server configuration.
   *
   * <p>Currently when MyVLe object is initialized the ServerInfoRegistry will be loaded.
   */
  protected void load() throws VrsException {
    logger.debugPrintf(">>> load() <<<\n");

    //
    // use serverInfo as mutex !
    //
    synchronized (this.serverInfos) {
      // Use new Configuration Manager
      ConfigManager confMan = this.context.getConfigManager();
      VRL loc = confMan.getServerRegistryLocation();

      // is synchronized will return consistant list of configs

      ArrayList<AttributeSet> sets = this.getInfoAttrSets();
      // No Context!
      ResourceLoader loader = new ResourceLoader();

      XMLData xmlifier = new XMLData();
      xmlifier.setVAttributeElementName("vlet:ServerInfoProperty");
      xmlifier.setVAttributeSetElementName("vlet:ServerInfo");

      InputStream inps;
      try {
        inps = loader.createInputStream(loc.toURL());
      } catch (IOException e) {
        throw new NestedIOException(e);
      } catch (Exception e) {
        throw new VRLSyntaxException(e);
      }

      sets = xmlifier.parseVAttributeSets(inps, XML_SERVER_CONFIG_HEADER_TAG);
      // for (VAttributeSet set:sets)
      // {
      // logger.debugPrintln(this,"Adding ServerInfo Set:"+set);
      // }

      // ===
      // Do not clear: just merge current with save ones !
      // serverInfos.clear();
      // ===
      for (AttributeSet set : sets) {
        ServerInfo info = new ServerInfo(context, set);
        logger.debugPrintf("Adding Server Config:%s\n", info);
        // actual store method:
        put(info);
      }

      this.isLoaded = true;
    }
  }
  public void removeAll() {
    synchronized (this.serverInfos) {
      this.isSaved = false;
      this.isLoaded = false;

      logger.debugPrintf(">>> ServerInfos.clear() ! <<<\n");
      serverInfos.clear();
    }
  }
  /**
   * Main method to search for a Server Info object. When a search field is null it means "don't
   * care". Use port number less then 0 for a don't care. Use port number EQUAL to 0 for default
   * port ! Returns multiple matching ServerInfo descriptions or NULL when it can't find any
   * matching server descriptions.
   *
   * @param scheme if NULL then don't care (match any)
   * @param hostname if NULL then don't care (match any)
   * @param port if port==-1 => don't care, if port==0 => default and if port>0 match explicit port
   *     number
   * @param userInfo if NULL then don't care (match any)
   */
  public ServerInfo[] getServerInfos(String scheme, String host, int port, String optUserInfo) {

    logger.debugPrintf(
        ">>> find {scheme,host,port,user}=%s,%s,%s,%s\n", scheme, host, port, optUserInfo);
    // if (scheme.compareTo("srb")==0)
    // {
    // logger.debugPrintln(this,"SRB"); // breakpoint
    // }
    ServerInfo infoArr[] = new ServerInfo[serverInfos.size()];
    infoArr = this.serverInfos.values().toArray(infoArr);

    Vector<ServerInfo> result = new Vector<ServerInfo>();

    for (ServerInfo info : infoArr) {
      logger.debugPrintf(" - comparing:%s", info);

      if (info.matches(scheme, host, port, optUserInfo)) {
        logger.debugPrintf(" - adding:%s\n", info);
        // =========================
        // Add Duplicate !
        // ==========================
        result.add(info.duplicate());
      }
    }

    if (result.size() <= 0) {
      logger.debugPrintf("<<< Returning NULL ServerInfos\n");
      return null;
    }

    ServerInfo arr[] = new ServerInfo[result.size()];
    arr = result.toArray(arr);
    logger.debugPrintf("<<< Returning #%d ServerInfos\n", arr.length);

    return arr;
  }
  /** Stored new ServerInfo and writes to file (if persistant) Returnes updated serverInfo */
  public ServerInfo store(ServerInfo info) {
    logger.debugPrintf("store(): attrs=%s\n", info.getAttributeSet());

    synchronized (this.serverInfos) {
      // ===
      // Before adding new Info: check whether persistant database is
      // loaded !
      // ===
      checkIsLoaded();
      // remove before put!
      remove(info);
      // synchronized put: UPDATES SERVERINFO KEY!
      put(info);
      // enters mutex again
      save();

      // do NOT return reference to object into ServerRegistry
      return info.duplicate();
    }
  }
  /** Put ServerInfo into registry */
  private void put(ServerInfo info) {
    synchronized (serverInfos) {
      // store private copy !
      info = info.duplicate();

      updateServerInfoID(info);

      logger.debugPrintf("+++ Storing info:%s\n", info);

      ServerInfo prev = this.serverInfos.get(info.getID());

      if (prev == info) logger.infoPrintf(">>> updating ServerInfo:%s\n", info);
      else if (prev != null)
        logger.infoPrintf(">>> WARNING: Overwriting previous object with:%s\n", info);
      else logger.infoPrintf(">>> storing new ServerInfo:%s\n", info);

      this.serverInfos.put(info.getID(), info);
      // mark dirty:
      this.isSaved = false;
    }
  }