/**
   * Sets up the portal mappings. May be called at context init or at any other time.
   *
   * <p>Notice that this isn't thread safe. The main problem is reading the prefix2portalid and
   * isPortalPickingActive by the doFilter() method while setupPortalMappings() is being run. This
   * could be solved by making doFilter synchronized but then only one thread could be in doFilter
   * at a time and that might be a performance issue.
   *
   * <p>Since setupPortalMappings is synchronized we cannot get an inconsistent state after it
   * returns. There will be a short time when it is running when the prefix2portalid and
   * isPortalPickingActive might be inconsistent. If a different thread calls doFilter at that time
   * and gets a bad result we should be able to live with it.
   */
  public static synchronized void setupPortalMappings(Collection<Portal> portals) {
    if (portals == null || portals.size() < 1) {
      log.debug("No portal mappings found in db. Filtering for portals will be inactive");
      prefix2portalid = new HashMap<String, Integer>();
      isPortalPickingActive = false;
      return;
    }

    int mappingCount = 0;
    boolean prefixCollision = false;
    HashMap<String, Integer> newPrefixMap = new HashMap<String, Integer>();
    HashMap<Integer, String> newPortalIdMap = new HashMap<Integer, String>();
    for (Portal portal : portals) {
      if (portal == null) continue;
      String urlprefix = portal.getUrlprefix();

      if (urlprefix == null
          || urlprefix.trim().length() == 0
          || "&nbsp;".equalsIgnoreCase(urlprefix)) {
        log.debug(
            "no url prefix mapping for portal "
                + portal.getAppName()
                + " id "
                + portal.getPortalId());
        continue;
      }
      urlprefix = urlprefix.trim();
      if (protectedPrefixes.contains(urlprefix)) {
        log.error(
            "the prefix "
                + urlprefix
                + " is a directory that is in the webapp"
                + " and may not be used as a prefix for portal "
                + portal.getPortalId());
        continue;
      }

      if (newPrefixMap.containsKey(urlprefix)) {
        Integer i = newPrefixMap.get(urlprefix);
        log.debug(
            "multiple portals have the url prefix "
                + urlprefix
                + ", both portals id:"
                + i.toString()
                + " and id:"
                + portal.getPortalId());
        newPrefixMap.remove(urlprefix);
        newPortalIdMap.remove(i);
        prefixCollision = true;
      }

      log.debug("urlprefix:'" + urlprefix + "' -> \t\tportalid: " + portal.getPortalId());
      newPrefixMap.put(urlprefix, new Integer(portal.getPortalId()));
      newPortalIdMap.put(new Integer(portal.getPortalId()), urlprefix);

      mappingCount++;
    }

    if (mappingCount > 0) {
      prefix2portalid = newPrefixMap;
      portalid2prefix = newPortalIdMap;
      isPortalPickingActive = true;
    } else {
      prefix2portalid = new HashMap<String, Integer>();
      portalid2prefix = new HashMap<Integer, String>();
      isPortalPickingActive = false;
    }

    log.info("final mappings:");
    for (String key : prefix2portalid.keySet()) {
      Integer id = prefix2portalid.get(key);
      log.info("portalid: " + id + "\turlprefix:'" + key + "'");
    }
    if (prefixCollision) log.info("there were at least two portals that had the same prefix.");
  }