Package org.sonatype.nexus.proxy.router

Source Code of org.sonatype.nexus.proxy.router.DefaultRepositoryRouter

/*
* Sonatype Nexus (TM) Open Source Version
* Copyright (c) 2007-2014 Sonatype, Inc.
* All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
*
* This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
* which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
*
* Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
* of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
* Eclipse Foundation. All other trademarks are the property of their respective owners.
*/
package org.sonatype.nexus.proxy.router;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

import org.sonatype.configuration.ConfigurationException;
import org.sonatype.nexus.configuration.AbstractLastingConfigurable;
import org.sonatype.nexus.configuration.CoreConfiguration;
import org.sonatype.nexus.configuration.application.ApplicationConfiguration;
import org.sonatype.nexus.configuration.model.CRouting;
import org.sonatype.nexus.configuration.model.CRoutingCoreConfiguration;
import org.sonatype.nexus.proxy.AccessDeniedException;
import org.sonatype.nexus.proxy.IllegalOperationException;
import org.sonatype.nexus.proxy.IllegalRequestException;
import org.sonatype.nexus.proxy.ItemNotFoundException;
import org.sonatype.nexus.proxy.LocalStorageException;
import org.sonatype.nexus.proxy.NoSuchRepositoryException;
import org.sonatype.nexus.proxy.ResourceStoreRequest;
import org.sonatype.nexus.proxy.StorageException;
import org.sonatype.nexus.proxy.access.Action;
import org.sonatype.nexus.proxy.access.NexusItemAuthorizer;
import org.sonatype.nexus.proxy.item.AbstractStorageItem;
import org.sonatype.nexus.proxy.item.DefaultStorageCollectionItem;
import org.sonatype.nexus.proxy.item.RepositoryItemUid;
import org.sonatype.nexus.proxy.item.StorageCollectionItem;
import org.sonatype.nexus.proxy.item.StorageFileItem;
import org.sonatype.nexus.proxy.item.StorageItem;
import org.sonatype.nexus.proxy.item.StorageLinkItem;
import org.sonatype.nexus.proxy.registry.RepositoryRegistry;
import org.sonatype.nexus.proxy.registry.RepositoryTypeDescriptor;
import org.sonatype.nexus.proxy.registry.RepositoryTypeRegistry;
import org.sonatype.nexus.proxy.repository.Repository;
import org.sonatype.nexus.proxy.storage.UnsupportedStorageOperationException;
import org.sonatype.nexus.proxy.targets.TargetSet;
import org.sonatype.nexus.proxy.utils.RepositoryStringUtils;
import org.sonatype.nexus.util.PathUtils;
import org.sonatype.sisu.goodies.eventbus.EventBus;

import org.codehaus.plexus.util.StringUtils;

import static org.sonatype.nexus.proxy.ItemNotFoundException.reasonFor;

/**
* The simplest re-implementation for RepositoryRouter that does only routing.
*
* @author cstamas
*/
@Singleton
@Named
public class DefaultRepositoryRouter
    extends AbstractLastingConfigurable<CRouting>
    implements RepositoryRouter
{
  private final RepositoryRegistry repositoryRegistry;

  private final RepositoryTypeRegistry repositoryTypeRegistry;

  private final NexusItemAuthorizer itemAuthorizer;

  @Inject
  public DefaultRepositoryRouter(EventBus eventBus, ApplicationConfiguration applicationConfiguration,
      RepositoryRegistry repositoryRegistry, RepositoryTypeRegistry repositoryTypeRegistry,
      NexusItemAuthorizer itemAuthorizer)
  {
    super("Repository Router", eventBus, applicationConfiguration);
    this.repositoryRegistry = repositoryRegistry;
    this.repositoryTypeRegistry = repositoryTypeRegistry;
    this.itemAuthorizer = itemAuthorizer;
  }

  public boolean isFollowLinks() {
    return getCurrentConfiguration(false).isResolveLinks();
  }

  public void setFollowLinks(boolean followLinks) {
    getCurrentConfiguration(true).setResolveLinks(followLinks);
  }

  // =

  protected void initializeConfiguration()
      throws ConfigurationException
  {
    if (getApplicationConfiguration().getConfigurationModel() != null) {
      configure(getApplicationConfiguration());
    }
  }

  @Override
  protected CoreConfiguration<CRouting> wrapConfiguration(Object configuration)
      throws ConfigurationException
  {
    if (configuration instanceof ApplicationConfiguration) {
      return new CRoutingCoreConfiguration((ApplicationConfiguration) configuration);
    }
    else {
      throw new ConfigurationException("The passed configuration object is of class \""
          + configuration.getClass().getName() + "\" and not the required \""
          + ApplicationConfiguration.class.getName() + "\"!");
    }
  }

  // =

  public StorageItem dereferenceLink(StorageLinkItem link)
      throws AccessDeniedException, ItemNotFoundException, IllegalOperationException, StorageException
  {
    return dereferenceLink(link, false, false);
  }

  public StorageItem dereferenceLink(StorageLinkItem link, boolean localOnly, boolean remoteOnly)
      throws AccessDeniedException, ItemNotFoundException, IllegalOperationException, StorageException
  {
    log.debug("Dereferencing link {}", link.getTarget());

    ResourceStoreRequest req = new ResourceStoreRequest(link.getTarget().getPath(), localOnly, remoteOnly);

    req.getRequestContext().setParentContext(link.getItemContext());

    return link.getTarget().getRepository().retrieveItem(req);
  }

  public StorageItem retrieveItem(ResourceStoreRequest request)
      throws ItemNotFoundException, IllegalOperationException, StorageException, AccessDeniedException
  {
    RequestRoute route = getRequestRouteForRequest(request);

    if (route.isRepositoryHit()) {
      // it hits a repository, mangle path and call it

      StorageItem item;
      request.pushRequestPath(route.getRepositoryPath());
      try {
        item = route.getTargetedRepository().retrieveItem(request);
      }
      finally {
        request.popRequestPath();
      }

      return mangle(false, request, route, item);
    }
    else {
      // this is "above" repositories
      return retrieveVirtualPath(request, route);
    }
  }

  public void storeItem(ResourceStoreRequest request, InputStream is, Map<String, String> userAttributes)
      throws UnsupportedStorageOperationException, ItemNotFoundException, IllegalOperationException,
             StorageException, AccessDeniedException
  {
    RequestRoute route = getRequestRouteForRequest(request);

    if (route.isRepositoryHit()) {
      // it hits a repository, mangle path and call it
      request.pushRequestPath(route.getRepositoryPath());
      try {
        route.getTargetedRepository().storeItem(request, is, userAttributes);
      }
      finally {
        request.popRequestPath();
      }
    }
    else {
      // this is "above" repositories
      throw new IllegalRequestException(request, "The path '" + request.getRequestPath()
          + "' does not points to any repository!");
    }
  }

  public void copyItem(ResourceStoreRequest from, ResourceStoreRequest to)
      throws UnsupportedStorageOperationException, ItemNotFoundException, IllegalOperationException,
             StorageException, AccessDeniedException
  {
    RequestRoute fromRoute = getRequestRouteForRequest(from);

    RequestRoute toRoute = getRequestRouteForRequest(to);

    if (fromRoute.isRepositoryHit() && toRoute.isRepositoryHit()) {
      // it hits a repository, mangle path and call it

      try {
        from.pushRequestPath(fromRoute.getRepositoryPath());
        to.pushRequestPath(toRoute.getRepositoryPath());

        if (fromRoute.getTargetedRepository() == toRoute.getTargetedRepository()) {
          fromRoute.getTargetedRepository().copyItem(from, to);
        }
        else {
          StorageItem item = fromRoute.getTargetedRepository().retrieveItem(from);

          if (item instanceof StorageFileItem) {
            try {
              toRoute.getTargetedRepository().storeItem(to, ((StorageFileItem) item).getInputStream(),
                  item.getRepositoryItemAttributes().asMap());
            }
            catch (IOException e) {
              // XXX: this is nonsense, to box IOException into subclass of IOException!
              throw new LocalStorageException(e);
            }
          }
          else if (item instanceof StorageCollectionItem) {
            toRoute.getTargetedRepository().createCollection(to,
                item.getRepositoryItemAttributes().asMap());
          }
          else {
            throw new IllegalRequestException(from, "Cannot copy item of class='"
                + item.getClass().getName() + "' over multiple repositories.");
          }

        }
      }
      finally {
        from.popRequestPath();
        to.popRequestPath();
      }
    }
    else {
      // this is "above" repositories
      if (!fromRoute.isRepositoryHit()) {
        throw new IllegalRequestException(from, "The path '" + from.getRequestPath()
            + "' does not points to any repository!");
      }
      else {
        throw new IllegalRequestException(to, "The path '" + to.getRequestPath()
            + "' does not points to any repository!");
      }
    }
  }

  public void moveItem(ResourceStoreRequest from, ResourceStoreRequest to)
      throws UnsupportedStorageOperationException, ItemNotFoundException, IllegalOperationException,
             StorageException, AccessDeniedException
  {
    copyItem(from, to);

    deleteItem(from);
  }

  public Collection<StorageItem> list(ResourceStoreRequest request)
      throws ItemNotFoundException, IllegalOperationException, StorageException, AccessDeniedException
  {
    RequestRoute route = getRequestRouteForRequest(request);

    if (route.isRepositoryHit()) {
      // it hits a repository, mangle path and call it

      Collection<StorageItem> items;

      request.pushRequestPath(route.getRepositoryPath());
      try {
        items = route.getTargetedRepository().list(request);
      }
      finally {
        request.popRequestPath();
      }

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

      for (StorageItem item : items) {
        result.add(mangle(true, request, route, item));
      }

      return result;
    }
    else {
      // this is "above" repositories
      return listVirtualPath(request, route);
    }
  }

  public void createCollection(ResourceStoreRequest request, Map<String, String> userAttributes)
      throws UnsupportedStorageOperationException, ItemNotFoundException, IllegalOperationException,
             StorageException, AccessDeniedException
  {
    RequestRoute route = getRequestRouteForRequest(request);

    if (route.isRepositoryHit()) {
      // it hits a repository, mangle path and call it

      request.pushRequestPath(route.getRepositoryPath());
      try {
        route.getTargetedRepository().createCollection(request, userAttributes);
      }
      finally {
        request.popRequestPath();
      }
    }
    else {
      // this is "above" repositories
      throw new IllegalRequestException(request, "The path '" + request.getRequestPath()
          + "' does not points to any repository!");
    }
  }

  public void deleteItem(ResourceStoreRequest request)
      throws UnsupportedStorageOperationException, ItemNotFoundException, IllegalOperationException,
             StorageException, AccessDeniedException
  {
    RequestRoute route = getRequestRouteForRequest(request);

    if (route.isRepositoryHit()) {
      // it hits a repository, mangle path and call it
      request.pushRequestPath(route.getRepositoryPath());
      try {
        route.getTargetedRepository().deleteItem(request);
      }
      finally {
        request.popRequestPath();
      }
    }
    else {
      // this is "above" repositories
      throw new IllegalRequestException(request, "The path '" + request.getRequestPath()
          + "' does not points to any repository!");
    }
  }

  public TargetSet getTargetsForRequest(ResourceStoreRequest request) {
    TargetSet result = new TargetSet();

    try {
      RequestRoute route = getRequestRouteForRequest(request);

      if (route.isRepositoryHit()) {
        // it hits a repository, mangle path and call it
        request.pushRequestPath(route.getRepositoryPath());
        try {
          result.addTargetSet(route.getTargetedRepository().getTargetsForRequest(request));
        }
        finally {
          request.popRequestPath();
        }
      }
    }
    catch (ItemNotFoundException e) {
      // nothing, empty set will be returned
    }

    return result;
  }

  // ===
  // Private
  // ===

  protected StorageItem mangle(boolean isList, ResourceStoreRequest request, RequestRoute route, StorageItem item)
      throws AccessDeniedException, ItemNotFoundException, IllegalOperationException, StorageException
  {
    if (isList) {
      ((AbstractStorageItem) item).setPath(PathUtils.concatPaths(route.getOriginalRequestPath(),
          item.getName()));
    }
    else {
      ((AbstractStorageItem) item).setPath(route.getOriginalRequestPath());
    }

    if (isFollowLinks() && item instanceof StorageLinkItem) {
      return dereferenceLink((StorageLinkItem) item);
    }
    else {
      return item;
    }
  }

  // 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(
            reasonFor(
                request,
                "Repository kind '" + explodedPath[0] + "' is unknown"));
      }

      result.setStrippedPrefix(PathUtils.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(reasonFor(request, "Repository %s exists but is not exposed.",
              RepositoryStringUtils.getHumanizedNameString(repository)));
        }
      }
      catch (NoSuchRepositoryException e) {
        // obviously, the repoId (explodedPath[1]) points to some nonexistent repoID
        throw new ItemNotFoundException(reasonFor(request, e.getMessage()), e);
      }

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

      result.setTargetedRepository(repository);

      String repoPath = "";

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

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

      result.setRepositoryPath(repoPath);
    }

    return result;
  }

  protected Repository getRepositoryForPathPrefixOrId(String pathPrefixOrId, Class<? extends Repository> kind)
      throws NoSuchRepositoryException
  {
    List<? extends Repository> repositories = repositoryRegistry.getRepositoriesWithFacet(kind);

    Repository idMatched = null;

    Repository pathPrefixMatched = null;

    for (Repository repository : repositories) {
      if (StringUtils.equals(repository.getId(), pathPrefixOrId)) {
        idMatched = repository;
      }

      if (StringUtils.equals(repository.getPathPrefix(), pathPrefixOrId)) {
        pathPrefixMatched = repository;
      }
    }

    if (idMatched != null) {
      // id wins
      return idMatched;
    }

    if (pathPrefixMatched != null) {
      // if no id found, prefix wins
      return pathPrefixMatched;
    }

    // nothing found
    throw new NoSuchRepositoryException(pathPrefixOrId);
  }

  protected StorageItem retrieveVirtualPath(ResourceStoreRequest request, RequestRoute route)
      throws ItemNotFoundException
  {
    final ResourceStoreRequest req = new ResourceStoreRequest(route.getOriginalRequestPath());
    req.getRequestContext().setParentContext(request.getRequestContext());
    return new DefaultStorageCollectionItem(this, req, true, false);
  }

  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(PathUtils.concatPaths(request.getRequestPath(), rtd.getPrefix()));
          req.getRequestContext().setParentContext(request.getRequestContext());
          DefaultStorageCollectionItem repositories =
              new DefaultStorageCollectionItem(this, req, true, false);
          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(reasonFor(request,
            "No repositories found for given %s prefix!", route.getStrippedPrefix()));
      }

      // 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()) {
          ResourceStoreRequest req = null;
          if (Repository.class.equals(kind)) {
            req =
                new ResourceStoreRequest(PathUtils.concatPaths(request.getRequestPath(),
                    repository.getId()));
          }
          else {
            req =
                new ResourceStoreRequest(PathUtils.concatPaths(request.getRequestPath(),
                    repository.getPathPrefix()));
          }
          req.getRequestContext().setParentContext(request.getRequestContext());
          DefaultStorageCollectionItem repoItem = new DefaultStorageCollectionItem(this, req, true, false);
          result.add(repoItem);
        }
      }

      return result;
    }
    else {
      throw new ItemNotFoundException(reasonFor(request,
          "BUG: request depth is bigger than 1, route=%s", route));
    }
  }

  private List<Repository> filterAccessToRepositories(Collection<? extends Repository> repositories) {
    if (repositories == null) {
      return null;
    }

    List<Repository> filteredRepositories = new ArrayList<Repository>();

    for (Repository repository : repositories) {
      if (this.itemAuthorizer.isViewable(NexusItemAuthorizer.VIEW_REPOSITORY_KEY, repository.getId())) {
        filteredRepositories.add(repository);
      }
    }

    return filteredRepositories;

  }

  @Override
  public boolean authorizePath(final ResourceStoreRequest request, final Action action) {
    try {
      final RequestRoute route = getRequestRouteForRequest(request);
      if (route.isRepositoryHit()) {
        request.pushRequestPath(route.getRepositoryPath());
        try {
          return itemAuthorizer.authorizePath(route.getTargetedRepository(), request, action);
        }
        finally {
          request.popRequestPath();
        }
      }
    }
    catch (ItemNotFoundException e) {
      // ignore this
    }
    // we did not hit any repository, so we are on virtual paths, allow access
    return true;
  }
}
TOP

Related Classes of org.sonatype.nexus.proxy.router.DefaultRepositoryRouter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.