/**
   * Mirror an absolute plugin, stored on an absolute url, regardless of remote filename, will
   * change local filename to be normalized
   *
   * @param pluginRef
   * @param site
   * @param request
   * @param mirrored
   * @return
   */
  private boolean mirrorAbsolutePlugin(
      PluginRef pluginRef, UpdateSite site, ResourceStoreRequest request, Set<String> mirrored) {
    try {
      // here we need to check the <archive> tags in the site, to find proper absoluteUrl
      Map<String, String> archives = site.getArchives();

      String absoluteUrl = archives.get(request.getRequestPath());

      if (absoluteUrl == null) {
        getLogger().warn("archive url not set for plugin " + request.getRequestPath());
        return false;
      }

      if (!new URI(absoluteUrl).isAbsolute()) {
        getLogger()
            .warn(
                "archive url ("
                    + absoluteUrl
                    + ") is not absolute for plugin "
                    + request.getRequestPath());
        return false;
      }

      mirrorAbsoluteItem(
          absoluteUrl.substring(0, absoluteUrl.lastIndexOf("/")),
          request,
          DEFAULT_PLUGINS_DIR,
          createResourceStoreRequest(pluginRef),
          mirrored);

      return true;
    } catch (URISyntaxException e) {
      getLogger().warn("archive url has illegal syntax for plugin " + request.getRequestPath(), e);
    } catch (StorageException e) {
      getLogger().warn("storage problem for plugin " + request.getRequestPath(), e);
    } catch (ItemNotFoundException e) {
      getLogger().warn("item not found for plugin " + request.getRequestPath(), e);
    }

    return false;
  }
  private void mirrorUpdateSite(boolean force)
      throws StorageException, IllegalOperationException, UnsupportedStorageOperationException {
    UpdateSite site;
    try {
      RepositoryItemUid siteUID = createUid(P2Constants.SITE_XML);
      String oldSha1 = null;

      ResourceStoreRequest request = new ResourceStoreRequest(siteUID.getPath());

      try {
        oldSha1 =
            getLocalStorage()
                .retrieveItem(this, request)
                .getAttributes()
                .get(DigestCalculatingInspector.DIGEST_SHA1_KEY);
      } catch (ItemNotFoundException e) {
        // it's okay
      }

      StorageFileItem siteItem = (StorageFileItem) doRetrieveRemoteItem(request);

      if (!force
          && oldSha1 != null
          && oldSha1.equals(
              siteItem.getAttributes().get(DigestCalculatingInspector.DIGEST_SHA1_KEY))) {
        return;
      }
      site = UpdateSite.read(siteItem.getInputStream());
    } catch (Exception e) {
      throw new StorageException("Could not read site.xml", e);
    }

    List<FeatureRef> features = site.getFeatures();

    getLogger().info("Mirroring " + features.size() + " features from update site " + getName());

    final Set<String> mirrored = new HashSet<String>();

    for (IFeatureRef feature : features) {
      mirrorFeature(site, feature, mirrored);
    }

    ResourceStoreRequest root = new ResourceStoreRequest(RepositoryItemUid.PATH_ROOT);

    DefaultWalkerContext ctx = new DefaultWalkerContext(this, root, filter);
    ctx.getContext().put("mirrored", mirrored);
    ctx.getProcessors()
        .add(
            new AbstractWalkerProcessor() {
              @SuppressWarnings("unchecked")
              @Override
              public void processItem(WalkerContext context, StorageItem item) throws Exception {
                Set<String> mirrored = (Set<String>) context.getContext().get("mirrored");

                if (item.getRepositoryItemUid().getBooleanAttributeValue(IsHiddenAttribute.class)) {
                  return;
                }

                if (item instanceof StorageFileItem
                    && !mirrored.contains(item.getPath().substring(1))) {
                  doDeleteItem(new ResourceStoreRequest(item.getPath()));
                }
              }
            });
    getWalker().walk(ctx);

    getLogger().debug("Generating P2 metadata for Eclipse Update Site " + getName());

    File baseDir = getLocalStorage().getBaseDir(this, root);
    File metadataDir = new File(baseDir, ".p2");

    try {
      FileUtils.deleteDirectory(metadataDir);
    } catch (IOException e) {
      getLogger().warn("Unexpected IOException", e);
    }

    p2.generateSiteMetadata(baseDir, metadataDir, getName());

    try {
      importFile(metadataDir, P2Constants.ARTIFACTS_PATH);
      importFile(metadataDir, P2Constants.CONTENT_PATH);
      FileUtils.deleteDirectory(metadataDir);
    } catch (IOException e) {
      // TODO this can actually happen on Windows
      getLogger().warn("Unexpected IOException", e);
    }
  }