Exemplo n.º 1
0
  /**
   * Rescans the associated paths to recompute the available resources.
   *
   * @param logger status and error details are written here
   */
  public void refresh(TreeLogger logger) {
    PerfLogger.start("ResourceOracleImpl.refresh");
    TreeLogger refreshBranch = Messages.REFRESHING_RESOURCES.branch(logger, null);

    /*
     * Allocate fresh data structures in anticipation of needing to honor the
     * "new identity for the collections if anything changes" guarantee. Use a
     * LinkedHashMap because we do not want the order to change.
     */
    Map<String, ResourceData> newInternalMap = new LinkedHashMap<String, ResourceData>();

    /*
     * Walk across path roots (i.e. classpath entries) in priority order. This
     * is a "reverse painter's algorithm", relying on being careful never to add
     * a resource that has already been added to the new map under construction
     * to create the effect that resources founder earlier on the classpath take
     * precedence.
     *
     * Exceptions: super has priority over non-super; and if there are two super
     * resources with the same path, the one with the higher-priority path
     * prefix wins.
     */
    for (ClassPathEntry pathRoot : classPath) {
      TreeLogger branchForClassPathEntry =
          Messages.EXAMINING_PATH_ROOT.branch(refreshBranch, pathRoot.getLocation(), null);

      Map<AbstractResource, PathPrefix> resourceToPrefixMap =
          pathRoot.findApplicableResources(branchForClassPathEntry, pathPrefixSet);
      for (Entry<AbstractResource, PathPrefix> entry : resourceToPrefixMap.entrySet()) {
        ResourceData newCpeData = new ResourceData(entry.getKey(), entry.getValue());
        String resourcePath = newCpeData.resource.getPath();
        ResourceData oldCpeData = newInternalMap.get(resourcePath);
        // Old wins unless the new resource has higher priority.
        if (oldCpeData == null || oldCpeData.compareTo(newCpeData) < 0) {
          newInternalMap.put(resourcePath, newCpeData);
        } else {
          Messages.IGNORING_SHADOWED_RESOURCE.log(branchForClassPathEntry, resourcePath, null);
        }
      }
    }

    /*
     * Update the newInternalMap to preserve identity for any resources that
     * have not changed; also record whether or not there are ANY changes.
     *
     * There's definitely a change if the sizes don't match; even if the sizes
     * do match, every new resource must match an old resource for there to be
     * no changes.
     */
    boolean didChange = internalMap.size() != newInternalMap.size();
    for (Map.Entry<String, ResourceData> entry : newInternalMap.entrySet()) {
      String resourcePath = entry.getKey();
      ResourceData newData = entry.getValue();
      ResourceData oldData = internalMap.get(resourcePath);
      if (shouldUseNewResource(logger, oldData, newData)) {
        didChange = true;
      } else {
        if (oldData.resource != newData.resource) {
          newInternalMap.put(resourcePath, oldData);
        }
      }
    }

    if (!didChange) {
      // Nothing to do, keep the same identities.
      PerfLogger.end();
      return;
    }

    internalMap = newInternalMap;

    Map<String, Resource> externalMap = new HashMap<String, Resource>();
    Set<Resource> externalSet = new HashSet<Resource>();
    for (Entry<String, ResourceData> entry : internalMap.entrySet()) {
      String path = entry.getKey();
      ResourceData data = entry.getValue();
      externalMap.put(path, data.resource);
      externalSet.add(data.resource);
    }

    // Update exposed collections with new (unmodifiable) data structures.
    exposedResources = Collections.unmodifiableSet(externalSet);
    exposedResourceMap = Collections.unmodifiableMap(externalMap);
    exposedPathNames = Collections.unmodifiableSet(externalMap.keySet());
    PerfLogger.end();
  }