package de.is24.infrastructure.gridfs.http.repos; import de.is24.infrastructure.gridfs.http.domain.RepoEntry; import de.is24.infrastructure.gridfs.http.domain.RepoType; import de.is24.infrastructure.gridfs.http.exception.BadRequestException; import de.is24.infrastructure.gridfs.http.exception.RepositoryNotFoundException; import de.is24.infrastructure.gridfs.http.metadata.RepoEntriesRepository; import org.apache.commons.lang.ArrayUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jmx.export.annotation.ManagedOperation; import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.stereotype.Service; import java.net.MalformedURLException; import java.net.URL; import java.util.Date; import static de.is24.infrastructure.gridfs.http.domain.RepoType.SCHEDULED; import static de.is24.infrastructure.gridfs.http.domain.RepoType.STATIC; import static de.is24.infrastructure.gridfs.http.domain.RepoType.VIRTUAL; import static de.is24.infrastructure.gridfs.http.repos.RepositoryNameValidator.validateRepoName; import static org.apache.commons.lang.ArrayUtils.contains; import static org.apache.commons.lang.StringUtils.substringAfter; @ManagedResource @Service public class RepoService { private static final Logger LOG = LoggerFactory.getLogger(RepoService.class); private static final long ONE_SEC_IN_MS = 1000; public static final String STATIC_PREFIX = "static/"; public static final String VIRTUAL_PREFIX = "virtual/"; private final RepoEntriesRepository entriesRepository; @Autowired public RepoService(RepoEntriesRepository entriesRepository) { this.entriesRepository = entriesRepository; } public void createOrUpdate(String reponame) { RepoEntry repoEntry = ensureEntry(reponame, STATIC, SCHEDULED); repoEntry.setLastModified(new Date()); entriesRepository.save(repoEntry); } public void delete(String reponame) { RepoEntry repoEntry = entriesRepository.findFirstByName(reponame); if (repoEntry != null) { entriesRepository.delete(repoEntry); LOG.info("Deleted {} repository {}.", repoEntry.getType(), reponame); } } public void deleteVirtual(String reponame) { RepoEntry repoEntry = entriesRepository.findFirstByName(reponame); if (repoEntry != null) { if (VIRTUAL != repoEntry.getType()) { throw new BadRequestException("Repository " + reponame + " is not a VIRTUAL repository."); } entriesRepository.delete(repoEntry); LOG.info("Deleted {} repository {}.", repoEntry.getType(), reponame); } } public void updateLastMetadataGeneration(String reponame, Date date, String newHashOfEntries) { RepoEntry repoEntry = ensureEntry(reponame, STATIC, SCHEDULED); repoEntry.setLastMetadataGeneration(date); repoEntry.setHashOfEntries(newHashOfEntries); if (repoEntry.getLastModified() == null) { repoEntry.setLastModified(new Date(date.getTime() - ONE_SEC_IN_MS)); } entriesRepository.save(repoEntry); } public boolean needsMetadataUpdate(String reponame) { RepoEntry repoEntry = entriesRepository.findFirstByName(reponame); return (repoEntry == null) || (repoEntry.getLastModified() == null) || (repoEntry.getLastMetadataGeneration() == null) || repoEntry.getLastModified().after(repoEntry.getLastMetadataGeneration()); } public boolean isRepoScheduled(String reponame) { RepoEntry entry = entriesRepository.findFirstByName(reponame); return (null != entry) && SCHEDULED.equals(entry.getType()); } public boolean staticRepoExists(String repoName) { RepoEntry repoEntry = entriesRepository.findFirstByName(repoName); return (repoEntry != null) && !(repoEntry.getType() == RepoType.VIRTUAL); } @ManagedOperation public void activateSchedulingForRepo(String reponame) { RepoEntry entry = ensureEntry(reponame, STATIC, SCHEDULED); entry.setType(SCHEDULED); entriesRepository.save(entry); } public RepoEntry ensureEntry(String reponame, RepoType... types) { RepoEntry repoEntry = entriesRepository.findFirstByName(reponame); boolean nullChecksOk = (repoEntry != null) && (types != null) && ((types.length > 0) && (types[0] != null)); if (nullChecksOk && !contains(types, repoEntry.getType())) { String repoMsg = "Repository " + reponame + " found"; String typeMsg = "but has type: " + repoEntry.getType() + ". Expected: " + ArrayUtils.toString(types); throw new IllegalArgumentException(repoMsg + ", " + typeMsg); } if (repoEntry == null) { repoEntry = fillRepoEntry(reponame, types); } return repoEntry; } private static RepoEntry fillRepoEntry(final String reponame, final RepoType[] types) { validateRepoName(reponame); RepoEntry repoEntry = new RepoEntry(); repoEntry.setName(reponame); if ((types == null) || ((types.length > 0) && (types[0] == null))) { repoEntry.setType(STATIC); } else { repoEntry.setType(types[0]); } return repoEntry; } @ManagedOperation public void setRepoType(String reponame, RepoType repoType) { RepoEntry repoEntry = ensureEntry(reponame, STATIC, SCHEDULED); if (repoType != null) { LOG.info("Set type of repository {} to {}", reponame, repoType); repoEntry.setType(repoType); entriesRepository.save(repoEntry); } } @ManagedOperation public void setMaxKeepRpms(String reponame, int maxKeepRpms) { if (maxKeepRpms < 0) { throw new BadRequestException("You cannot keep a negative amount of RPMs"); } RepoEntry repoEntry = ensureEntry(reponame, STATIC, SCHEDULED); repoEntry.setMaxKeepRpms(maxKeepRpms); entriesRepository.save(repoEntry); LOG.info("Set maxKeepRpms of repository {} to {}", reponame, maxKeepRpms); } @ManagedOperation public void setMaxDaysRpms(String reponame, int maxDaysRpms) { if (maxDaysRpms < 0) { throw new BadRequestException("You cannot keep RPMs for a negative amount of days"); } RepoEntry repoEntry = ensureEntry(reponame, STATIC, SCHEDULED); repoEntry.setMaxDaysRpms(maxDaysRpms); entriesRepository.save(repoEntry); LOG.info("Set maxDaysRpms of repository {} to {}", reponame, maxDaysRpms); } @ManagedOperation public void createVirtualRepo(String reponame, String destination) { validateRepoName(reponame); RepoEntry virtualEntry = ensureEntry(reponame, VIRTUAL); if (destination.startsWith(STATIC_PREFIX)) { setLinkToStatic(virtualEntry, destination); } else if (destination.startsWith(VIRTUAL_PREFIX)) { setLinkToVirtual(virtualEntry, destination); } else { setLinkToExternal(virtualEntry, destination); } entriesRepository.save(virtualEntry); LOG.info("Saved virtual repo '{}' linked to '{}'.", reponame, destination); } public RepoEntry getRepo(String reponame, RepoType type) { RepoEntry entry = entriesRepository.findFirstByNameAndType(reponame, type); if (entry == null) { throw new RepositoryNotFoundException("Could not find repository with type " + type, reponame); } return entry; } private void setLinkToExternal(RepoEntry repoEntry, String destination) { try { new URL(destination); } catch (MalformedURLException e) { throw new BadRequestException("Invalid destination repo: " + destination, e); } repoEntry.setExternal(true); repoEntry.setTarget(destination); } private void setLinkToVirtual(RepoEntry virtualEntry, String destination) { String virtualRepo = substringAfter(destination, VIRTUAL_PREFIX); RepoEntry repoEntry = entriesRepository.findFirstByNameAndType(virtualRepo, VIRTUAL); if (repoEntry == null) { throw new BadRequestException("Virtual repository '" + virtualRepo + "' not found."); } virtualEntry.setExternal(repoEntry.isExternal()); virtualEntry.setTarget(repoEntry.getTarget()); } private void setLinkToStatic(RepoEntry virtualEntry, String destination) { virtualEntry.setExternal(false); virtualEntry.setTarget(substringAfter(destination, STATIC_PREFIX)); RepoEntry repoEntry = entriesRepository.findFirstByName(virtualEntry.getTarget()); if ((repoEntry == null) || ((repoEntry.getType() != STATIC) && (repoEntry.getType() != SCHEDULED))) { throw new BadRequestException("Static repository '" + virtualEntry.getTarget() + "' not found."); } } }