protected void checkRepositoryMaxInstanceCountForCreation(CRepository repositoryModel)
      throws ConfigurationException {
    RepositoryTypeDescriptor rtd =
        repositoryTypeRegistry.getRepositoryTypeDescriptor(
            repositoryModel.getProviderRole(), repositoryModel.getProviderHint());

    int maxCount;

    if (null == rtd) {
      // no check done
      String msg =
          String.format(
              "Repository \"%s\" (repoId=%s) corresponding type is not registered in Core, hence it's maxInstace check cannot be performed: Repository type %s:%s is unknown to Nexus Core. It is probably contributed by an old Nexus plugin. Please contact plugin developers to upgrade the plugin, and register the new repository type(s) properly!",
              repositoryModel.getName(),
              repositoryModel.getId(),
              repositoryModel.getProviderRole(),
              repositoryModel.getProviderHint());

      getLogger().warn(msg);

      return;
    }

    if (rtd.getRepositoryMaxInstanceCount() != RepositoryType.UNLIMITED_INSTANCES) {
      maxCount = rtd.getRepositoryMaxInstanceCount();
    } else {
      maxCount = getRepositoryMaxInstanceCount(rtd);
    }

    if (rtd.getInstanceCount() >= maxCount) {
      String msg =
          "Repository \""
              + repositoryModel.getName()
              + "\" (id="
              + repositoryModel.getId()
              + ") cannot be created. It's repository type "
              + rtd.toString()
              + " is limited to "
              + maxCount
              + " instances, and it already has "
              + String.valueOf(rtd.getInstanceCount())
              + " of them.";

      getLogger().warn(msg);

      throw new ConfigurationException(msg);
    }
  }
  protected Collection<StorageItem> listVirtualPath(
      ResourceStoreRequest request, RequestRoute route) throws ItemNotFoundException {
    if (route.getRequestDepth() == 0) {
      // 1st level
      ArrayList<StorageItem> result = new ArrayList<StorageItem>();

      for (RepositoryTypeDescriptor rtd :
          repositoryTypeRegistry.getRegisteredRepositoryTypeDescriptors()) {
        // check is there any repo registered
        if (!repositoryRegistry.getRepositoriesWithFacet(rtd.getRole()).isEmpty()) {
          ResourceStoreRequest req =
              new ResourceStoreRequest(
                  ItemPathUtils.concatPaths(request.getRequestPath(), rtd.getPrefix()));

          DefaultStorageCollectionItem repositories =
              new DefaultStorageCollectionItem(this, req, true, false);

          repositories.getItemContext().putAll(request.getRequestContext());

          result.add(repositories);
        }
      }

      return result;
    } else if (route.getRequestDepth() == 1) {
      // 2nd level
      List<? extends Repository> repositories = null;

      Class<? extends Repository> kind = null;

      for (RepositoryTypeDescriptor rtd :
          repositoryTypeRegistry.getRegisteredRepositoryTypeDescriptors()) {
        if (route.getStrippedPrefix().startsWith("/" + rtd.getPrefix())) {
          kind = rtd.getRole();

          repositories = repositoryRegistry.getRepositoriesWithFacet(kind);

          break;
        }
      }

      // if no prefix matched, Item not found
      if (repositories == null || repositories.isEmpty()) {
        throw new ItemNotFoundException(request);
      }

      // filter access to the repositories
      // NOTE: do this AFTER the null/empty check so we return an empty list vs. an ItemNotFound
      repositories = filterAccessToRepositories(repositories);

      ArrayList<StorageItem> result = new ArrayList<StorageItem>(repositories.size());

      for (Repository repository : repositories) {
        if (repository.isExposed() && repository.isBrowseable()) {
          DefaultStorageCollectionItem repoItem = null;

          ResourceStoreRequest req = null;

          if (Repository.class.equals(kind)) {
            req =
                new ResourceStoreRequest(
                    ItemPathUtils.concatPaths(request.getRequestPath(), repository.getId()));
          } else {
            req =
                new ResourceStoreRequest(
                    ItemPathUtils.concatPaths(
                        request.getRequestPath(), repository.getPathPrefix()));
          }

          repoItem = new DefaultStorageCollectionItem(this, req, true, false);

          repoItem.getItemContext().putAll(request.getRequestContext());

          result.add(repoItem);
        }
      }

      return result;
    } else {
      throw new ItemNotFoundException(request);
    }
  }
  // XXX: a todo here is to make the "aliases" ("groups" for GroupRepository.class) dynamic,
  // and even think about new layout: every kind should have it's own "folder", you don't want to
  // see
  // maven2 and P2 repositories along each other...
  public RequestRoute getRequestRouteForRequest(ResourceStoreRequest request)
      throws ItemNotFoundException {
    RequestRoute result = new RequestRoute();

    result.setOriginalRequestPath(request.getRequestPath());

    result.setResourceStoreRequest(request);

    String correctedPath =
        request.getRequestPath().startsWith(RepositoryItemUid.PATH_SEPARATOR)
            ? request.getRequestPath().substring(1, request.getRequestPath().length())
            : request.getRequestPath();

    String[] explodedPath = null;

    if (StringUtils.isEmpty(correctedPath)) {
      explodedPath = new String[0];
    } else {
      explodedPath = correctedPath.split(RepositoryItemUid.PATH_SEPARATOR);
    }

    Class<? extends Repository> kind = null;

    result.setRequestDepth(explodedPath.length);

    if (explodedPath.length >= 1) {
      // we have kind information ("repositories" vs "groups" etc)
      for (RepositoryTypeDescriptor rtd :
          repositoryTypeRegistry.getRegisteredRepositoryTypeDescriptors()) {
        if (rtd.getPrefix().equals(explodedPath[0])) {
          kind = rtd.getRole();

          break;
        }
      }

      if (kind == null) {
        // unknown explodedPath[0]
        throw new ItemNotFoundException(request);
      }

      result.setStrippedPrefix(ItemPathUtils.concatPaths(explodedPath[0]));
    }

    if (explodedPath.length >= 2) {
      // we have repoId information in path
      Repository repository = null;

      try {
        repository = getRepositoryForPathPrefixOrId(explodedPath[1], kind);
        // explodedPath[1] is not _always_ ID anymore! It is PathPrefix _or_ ID! NEXUS-1710
        // repository = repositoryRegistry.getRepositoryWithFacet( explodedPath[1], kind );

        if (!repository.isExposed()) {
          // this is not the main facet or the repo is not exposed
          throw new ItemNotFoundException(request);
        }
      } catch (NoSuchRepositoryException e) {
        // obviously, the repoId (explodedPath[1]) points to some nonexistent repoID
        throw new ItemNotFoundException(request, e);
      }

      result.setStrippedPrefix(ItemPathUtils.concatPaths(explodedPath[0], explodedPath[1]));

      result.setTargetedRepository(repository);

      String repoPath = "";

      for (int i = 2; i < explodedPath.length; i++) {
        repoPath = ItemPathUtils.concatPaths(repoPath, explodedPath[i]);
      }

      if (result.getOriginalRequestPath().endsWith(RepositoryItemUid.PATH_SEPARATOR)) {
        repoPath = repoPath + RepositoryItemUid.PATH_SEPARATOR;
      }

      result.setRepositoryPath(repoPath);
    }

    return result;
  }