Package org.sonatype.nexus.yum.internal

Source Code of org.sonatype.nexus.yum.internal.YumHostedImpl$DelayedDirectoryDeletionTask

/*
* 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.yum.internal;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;

import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Named;

import org.sonatype.nexus.proxy.ResourceStoreRequest;
import org.sonatype.nexus.proxy.repository.HostedRepository;
import org.sonatype.nexus.proxy.repository.Repository;
import org.sonatype.nexus.scheduling.NexusScheduler;
import org.sonatype.nexus.yum.YumHosted;
import org.sonatype.nexus.yum.YumRepository;
import org.sonatype.nexus.yum.internal.task.GenerateMetadataTask;
import org.sonatype.nexus.yum.internal.task.TaskAlreadyScheduledException;
import org.sonatype.scheduling.ScheduledTask;

import com.google.common.collect.Maps;
import com.google.inject.assistedinject.Assisted;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.google.common.base.Preconditions.checkNotNull;
import static java.io.File.pathSeparator;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.apache.commons.lang.StringUtils.isBlank;
import static org.apache.commons.lang.StringUtils.isNotBlank;
import static org.sonatype.nexus.yum.internal.task.GenerateMetadataTask.ID;

/**
* @since yum 3.0
*/
@Named
public class YumHostedImpl
    implements YumHosted
{

  private final static Logger LOG = LoggerFactory.getLogger(YumHostedImpl.class);

  private static final int MAX_EXECUTION_COUNT = 100;

  private final NexusScheduler nexusScheduler;

  private final ScheduledThreadPoolExecutor executor;

  private final HostedRepository repository;

  private final File temporaryDirectory;

  private boolean processDeletes;

  private long deleteProcessingDelay;

  private String yumGroupsDefinitionFile;

  private final File baseDir;

  private final Map<String, String> aliases;

  private final Map<ScheduledFuture<?>, DelayedDirectoryDeletionTask> taskMap =
      new HashMap<ScheduledFuture<?>, DelayedDirectoryDeletionTask>();

  private final Map<DelayedDirectoryDeletionTask, ScheduledFuture<?>> reverseTaskMap =
      new HashMap<DelayedDirectoryDeletionTask, ScheduledFuture<?>>();

  @Inject
  public YumHostedImpl(final NexusScheduler nexusScheduler,
                       final ScheduledThreadPoolExecutor executor,
                       final BlockSqliteDatabasesRequestStrategy blockSqliteDatabasesRequestStrategy,
                       final @Assisted HostedRepository repository,
                       final @Assisted File temporaryDirectory)
      throws MalformedURLException, URISyntaxException

  {
    this.nexusScheduler = checkNotNull(nexusScheduler);
    this.executor = checkNotNull(executor);
    this.repository = checkNotNull(repository);
    this.temporaryDirectory = checkNotNull(temporaryDirectory);

    this.processDeletes = true;
    this.deleteProcessingDelay = DEFAULT_DELETE_PROCESSING_DELAY;

    this.aliases = Maps.newHashMap();

    this.baseDir = RepositoryUtils.getBaseDir(repository);

    this.yumGroupsDefinitionFile = null;

    repository.registerRequestStrategy(
        BlockSqliteDatabasesRequestStrategy.class.getName(), checkNotNull(blockSqliteDatabasesRequestStrategy)
    );
  }

  private final YumRepositoryCache cache = new YumRepositoryCache();

  @Override
  public YumHosted setProcessDeletes(final boolean processDeletes) {
    this.processDeletes = processDeletes;
    return this;
  }

  @Override
  public YumHosted setDeleteProcessingDelay(final long numberOfSeconds) {
    this.deleteProcessingDelay = numberOfSeconds;
    return this;
  }

  @Override
  public YumHosted setYumGroupsDefinitionFile(final String yumGroupsDefinitionFile) {
    this.yumGroupsDefinitionFile = yumGroupsDefinitionFile;
    return this;
  }

  @Override
  public boolean shouldProcessDeletes() {
    return processDeletes;
  }

  @Override
  public long deleteProcessingDelay() {
    return deleteProcessingDelay;
  }

  @Override
  public String getYumGroupsDefinitionFile() {
    return yumGroupsDefinitionFile;
  }

  @Override
  public File getBaseDir() {
    return baseDir;
  }

  @Override
  public YumHosted addAlias(final String alias, final String version) {
    aliases.put(alias, version);
    return this;
  }

  @Override
  public YumHosted removeAlias(final String alias) {
    aliases.remove(alias);
    return this;
  }

  @Override
  public YumHosted setAliases(final Map<String, String> aliases) {
    this.aliases.clear();
    this.aliases.putAll(aliases);

    return this;
  }

  @Override
  public String getVersion(final String alias) {
    return aliases.get(alias);
  }

  @Override
  public Repository getNexusRepository() {
    return repository;
  }

  @Override
  public YumRepository getYumRepository() throws Exception {
    return getYumRepository(null);
  }

  ScheduledTask<YumRepository> createYumRepository(final String version,
                                                   final File yumRepoBaseDir)
  {
    try {
      File rpmBaseDir = RepositoryUtils.getBaseDir(repository);
      GenerateMetadataTask task = createTask();
      task.setRpmDir(rpmBaseDir.getAbsolutePath());
      task.setRepoDir(yumRepoBaseDir);
      task.setRepositoryId(repository.getId());
      task.setVersion(version);
      task.setYumGroupsDefinitionFile(getYumGroupsDefinitionFile());
      return submitTask(task);
    }
    catch (Exception e) {
      throw new RuntimeException("Unable to create repository", e);
    }
  }

  @Override
  public YumRepository getYumRepository(final String version)
      throws Exception
  {
    YumRepositoryImpl yumRepository = cache.lookup(repository.getId(), version);
    if ((yumRepository == null) || yumRepository.isDirty()) {
      final ScheduledTask<YumRepository> future = createYumRepository(
          version, createRepositoryTempDir(repository, version)
      );
      yumRepository = (YumRepositoryImpl) future.get();
      cache.cache(yumRepository);
    }
    return yumRepository;
  }

  private ScheduledTask<YumRepository> submitTask(GenerateMetadataTask task) {
    try {
      return nexusScheduler.submit(ID, task);
    }
    catch (TaskAlreadyScheduledException e) {
      return mergeAddedFiles(e.getOriginal(), task);
    }
  }

  @Override
  public ScheduledTask<YumRepository> regenerate() {
    return addRpmAndRegenerate(null);
  }

  @Override
  public void markDirty(final String version) {
    cache.markDirty(repository.getId(), version);
  }

  @Override
  public ScheduledTask<YumRepository> addRpmAndRegenerate(@Nullable String filePath) {
    try {
      LOG.debug("Processing added rpm {}:{}", repository.getId(), filePath);
      final File rpmBaseDir = RepositoryUtils.getBaseDir(repository);
      final GenerateMetadataTask task = createTask();
      task.setRpmDir(rpmBaseDir.getAbsolutePath());
      task.setRepositoryId(repository.getId());
      task.setAddedFiles(filePath);
      task.setYumGroupsDefinitionFile(getYumGroupsDefinitionFile());
      return submitTask(task);
    }
    catch (Exception e) {
      throw new RuntimeException("Unable to create repository", e);
    }
  }

  @SuppressWarnings("unchecked")
  private ScheduledTask<YumRepository> mergeAddedFiles(ScheduledTask<?> existingScheduledTask,
                                                       GenerateMetadataTask taskToMerge)
  {
    if (isNotBlank(taskToMerge.getAddedFiles())) {
      final GenerateMetadataTask existingTask = (GenerateMetadataTask) existingScheduledTask.getTask();
      if (isBlank(existingTask.getAddedFiles())) {
        existingTask.setAddedFiles(taskToMerge.getAddedFiles());
      }
      else {
        existingTask.setAddedFiles(
            existingTask.getAddedFiles() + pathSeparator + taskToMerge.getAddedFiles());
      }
    }
    return (ScheduledTask<YumRepository>) existingScheduledTask;
  }

  private GenerateMetadataTask createTask() {
    final GenerateMetadataTask task = nexusScheduler.createTaskInstance(GenerateMetadataTask.class);
    if (task == null) {
      throw new IllegalStateException(
          "Could not create a task fo type " + GenerateMetadataTask.class.getName()
      );
    }
    return task;
  }

  private File createRepositoryTempDir(Repository repository, String version) {
    return new File(temporaryDirectory, repository.getId() + File.separator + version);
  }

  @Override
  public void regenerateWhenPathIsRemoved(String path) {
    if (shouldProcessDeletes()) {
      LOG.debug("Processing deleted rpm {}:{}", repository.getId(), path);
      if (findDelayedParentDirectory(path) == null) {
        regenerate();
      }
    }
  }

  @Override
  public void regenerateWhenDirectoryIsRemoved(String path) {
    if (shouldProcessDeletes()) {
      LOG.debug("Processing deleted dir {}:{}", repository.getId(), path);
      if (findDelayedParentDirectory(path) == null) {
        schedule(new DelayedDirectoryDeletionTask(path));
      }
    }
  }

  private void schedule(DelayedDirectoryDeletionTask task) {
    final ScheduledFuture<?> future = executor.schedule(task, deleteProcessingDelay(), SECONDS);
    taskMap.put(future, task);
    reverseTaskMap.put(task, future);
  }

  private DelayedDirectoryDeletionTask findDelayedParentDirectory(final String path) {
    for (final Runnable runnable : executor.getQueue()) {
      DelayedDirectoryDeletionTask dirTask = taskMap.get(runnable);
      if (dirTask != null && path.startsWith(dirTask.path)) {
        return dirTask;
      }
    }
    return null;
  }

  private boolean isDeleted(String path) {
    try {
      repository.retrieveItem(new ResourceStoreRequest(path));
      return false;
    }
    catch (Exception e) {
      return true;
    }
  }

  private class DelayedDirectoryDeletionTask
      implements Runnable
  {

    private final String path;

    private int executionCount = 0;

    private DelayedDirectoryDeletionTask(final String path) {
      this.path = path;
    }

    @Override
    public void run() {
      executionCount++;
      final ScheduledFuture<?> future = reverseTaskMap.remove(this);
      if (future != null) {
        taskMap.remove(future);
      }
      if (isDeleted(path)) {
        LOG.debug(
            "Recreate yum repository {} because of removed path {}", getNexusRepository().getId(), path
        );
        regenerate();
      }
      else if (executionCount < MAX_EXECUTION_COUNT) {
        LOG.debug(
            "Rescheduling creation of yum repository {} because path {} not deleted.",
            getNexusRepository().getId(), path
        );
        schedule(this);
      }
      else {
        LOG.warn(
            "Deleting path {} in repository {} took too long - retried {} times.",
            path, getNexusRepository().getId(), MAX_EXECUTION_COUNT
        );
      }
    }
  }

}
TOP

Related Classes of org.sonatype.nexus.yum.internal.YumHostedImpl$DelayedDirectoryDeletionTask

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.