/* * RHQ Management Platform * Copyright (C) 2009 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, as * published by the Free Software Foundation, and/or the GNU Lesser * General Public License, version 2.1, also as published by the Free * Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License and the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.rhq.enterprise.server.plugin.pc.content.sync; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.rhq.core.domain.auth.Subject; import org.rhq.core.domain.content.ContentSource; import org.rhq.core.domain.content.DownloadMode; import org.rhq.core.domain.content.PackageVersion; import org.rhq.core.domain.content.PackageVersionContentSource; import org.rhq.core.domain.content.PackageVersionContentSourcePK; import org.rhq.core.domain.content.Repo; import org.rhq.core.domain.content.RepoSyncResults; import org.rhq.core.domain.resource.ResourceType; import org.rhq.core.domain.util.PageControl; import org.rhq.enterprise.server.auth.SubjectManagerLocal; import org.rhq.enterprise.server.content.ContentSourceManagerLocal; import org.rhq.enterprise.server.content.RepoManagerLocal; import org.rhq.enterprise.server.plugin.pc.content.ContentProvider; import org.rhq.enterprise.server.plugin.pc.content.ContentProviderPackageDetails; import org.rhq.enterprise.server.plugin.pc.content.ContentProviderPackageDetailsKey; import org.rhq.enterprise.server.plugin.pc.content.PackageSource; import org.rhq.enterprise.server.plugin.pc.content.PackageSyncReport; import org.rhq.enterprise.server.plugin.pc.content.SyncException; import org.rhq.enterprise.server.plugin.pc.content.SyncProgressWeight; import org.rhq.enterprise.server.plugin.pc.content.SyncTracker; import org.rhq.enterprise.server.util.LookupUtil; /** * Holds the methods necessary to interact with a plugin and execute its package related * synchronization tasks. * * @author Jason Dobies */ public class PackageSourceSynchronizer { private final Log log = LogFactory.getLog(this.getClass()); private ContentSourceManagerLocal contentSourceManager; private RepoManagerLocal repoManager; private SubjectManagerLocal subjectManager; private Repo repo; private ContentSource source; private ContentProvider provider; public PackageSourceSynchronizer(Repo repo, ContentSource source, ContentProvider provider) { this.repo = repo; this.source = source; this.provider = provider; contentSourceManager = LookupUtil.getContentSourceManager(); subjectManager = LookupUtil.getSubjectManager(); repoManager = LookupUtil.getRepoManagerLocal(); } public SyncTracker synchronizePackageMetadata(SyncTracker tracker) throws SyncException, InterruptedException { if (!(provider instanceof PackageSource)) { // Nothing to do. return tracker; } PackageSource packageSource = (PackageSource) provider; // Load packages to send to package source // -------------------------------------------- long start = System.currentTimeMillis(); List<PackageVersionContentSource> existingPVCS; // already know about this source Set<ContentProviderPackageDetails> allDetails; // send to plugin Map<ContentProviderPackageDetailsKey, PackageVersionContentSource> keyPVCSMap; Subject overlord = subjectManager.getOverlord(); existingPVCS = contentSourceManager.getPackageVersionsFromContentSourceForRepo(overlord, source.getId(), repo .getId()); int existingCount = existingPVCS.size(); keyPVCSMap = new HashMap<ContentProviderPackageDetailsKey, PackageVersionContentSource>(existingCount); allDetails = new HashSet<ContentProviderPackageDetails>(existingCount); translateDomainToDto(existingPVCS, allDetails, keyPVCSMap); log.info("Synchronize Packages: [" + source.getName() + "]: loaded existing list of size=[" + existingCount + "] (" + (System.currentTimeMillis() - start) + ")ms"); // Ask source to do the sync // -------------------------------------------- start = System.currentTimeMillis(); PackageSyncReport report = new PackageSyncReport(); packageSource.synchronizePackages(repo.getName(), report, allDetails); tracker.setPackageSyncCount(report.getNewPackages().size() + report.getUpdatedPackages().size()); log.info("Synchronize Packages: [" + source.getName() + "]: got sync report from adapter=[" + report + "] (" + (System.currentTimeMillis() - start) + ")ms. Have: " + tracker.getPackageSyncCount() + " packages to sync"); // Merge in the results of the synchronization // -------------------------------------------- start = System.currentTimeMillis(); RepoSyncResults syncResults = contentSourceManager.mergePackageSyncReport(source, repo, report, keyPVCSMap, tracker.getRepoSyncResults()); tracker.setRepoSyncResults(syncResults); log.info("Synchronize Packages: [" + source.getName() + "]: merged sync report=(" + (System.currentTimeMillis() - start) + ")ms"); return tracker; } public SyncTracker synchronizePackageBits(SyncTracker tracker, ContentProvider provider) throws InterruptedException, SyncException { SyncProgressWeight sw = provider.getSyncProgressWeight(); // Determine if the sync even needs to take place if (!(provider instanceof PackageSource)) { return tracker; } if (source.getDownloadMode() == DownloadMode.NEVER) { String msg = "Download mode of NEVER for source [" + source.getName() + "], skipping " + "package bits sync for repo [" + repo.getName() + "]"; log.info(msg); tracker.getRepoSyncResults().appendResults(msg); tracker.setRepoSyncResults(repoManager.mergeRepoSyncResults(tracker.getRepoSyncResults())); tracker.getProgressWatcher().finishWork(sw.getPackageBitsWeight() * tracker.getPackageSyncCount()); return tracker; } if (source.isLazyLoad()) { String msg = "Lazy load enabled for source [" + source.getName() + "], skipping " + "package bits sync for repo [" + repo.getName() + "]"; log.info(msg); tracker.getRepoSyncResults().appendResults(msg); tracker.setRepoSyncResults(repoManager.mergeRepoSyncResults(tracker.getRepoSyncResults())); tracker.getProgressWatcher().finishWork(sw.getPackageBitsWeight() * tracker.getPackageSyncCount()); return tracker; } long start; // Determine which packages need bit synccing /* If there become performance issues here, consider paging. So we have to load them all in at once or can we do them in chunks? */ start = System.currentTimeMillis(); PageControl pc = PageControl.getUnlimitedInstance(); Subject overlord = subjectManager.getOverlord(); List<PackageVersionContentSource> packageVersionContentSources = contentSourceManager .getUnloadedPackageVersionsFromContentSourceInRepo(overlord, source.getId(), repo.getId(), pc); String msg = "Synchronize Package Bits: [" + source.getName() + "], repo [" + repo.getName() + "]: loaded package list for sync (" + (System.currentTimeMillis() - start) + ")ms"; log.info(msg); tracker.getRepoSyncResults().appendResults(msg); tracker.setRepoSyncResults(repoManager.mergeRepoSyncResults(tracker.getRepoSyncResults())); // Download the bits for each unloaded package version. Abort the entire download if we // fail getting just one package. // Note: This can potentially take a very long time. for (PackageVersionContentSource item : packageVersionContentSources) { PackageVersionContentSourcePK pk = item.getPackageVersionContentSourcePK(); try { log.info("Downloading package version [" + pk.getPackageVersion() + "] located at [" + item.getLocation() + "]" + "] from [" + pk.getContentSource() + "]..."); tracker.getRepoSyncResults().appendResults( "Downloading package version [" + pk.getPackageVersion() + "] located at [" + item.getLocation() + "]"); tracker.setRepoSyncResults(repoManager.mergeRepoSyncResults(tracker.getRepoSyncResults())); overlord = subjectManager.getOverlord(); contentSourceManager.downloadPackageBits(overlord, item); // Tick off each package as completed work tracker.getProgressWatcher().finishWork(sw.getPackageBitsWeight() * 1); tracker.getRepoSyncResults().setPercentComplete( new Long(tracker.getProgressWatcher().getPercentComplete())); tracker.setRepoSyncResults(repoManager.mergeRepoSyncResults(tracker.getRepoSyncResults())); } catch (Exception e) { String errorMsg = "Failed to load package bits for package version [" + pk.getPackageVersion() + "] from content source [" + pk.getContentSource() + "] at location [" + item.getLocation() + "]." + "No more packages will be downloaded for this content source."; throw new SyncException(errorMsg, e); } } log.info("All package bits for content source [" + source.getName() + "] have been downloaded." + "The downloads started at [" + new Date(start) + "] and ended at [" + new Date() + "]"); return tracker; } /** * Translates the domain representation of a list of packages into DTOs used in the plugin APIs. * During the translation the two collections (allDetails and keyPVCSMap) will be populated with * different views into the data. * * @param existingPVCS list of packages in the form of the wrapper object linking them to * the content source * @param allDetails set of all translated package DTOs * @param keyPVCSMap mapping of package version key to package domain object */ private void translateDomainToDto(List<PackageVersionContentSource> existingPVCS, Set<ContentProviderPackageDetails> allDetails, Map<ContentProviderPackageDetailsKey, PackageVersionContentSource> keyPVCSMap) { for (PackageVersionContentSource pvcs : existingPVCS) { PackageVersion pv = pvcs.getPackageVersionContentSourcePK().getPackageVersion(); org.rhq.core.domain.content.Package p = pv.getGeneralPackage(); ResourceType rt = p.getPackageType().getResourceType(); String resourceTypeName = rt != null ? rt.getName() : null; String resourceTypePlugin = rt != null ? rt.getPlugin() : null; ContentProviderPackageDetailsKey key; key = new ContentProviderPackageDetailsKey(p.getName(), pv.getVersion(), p.getPackageType().getName(), pv .getArchitecture().getName(), resourceTypeName, resourceTypePlugin); ContentProviderPackageDetails details = new ContentProviderPackageDetails(key); details.setClassification(pv.getGeneralPackage().getClassification()); details.setDisplayName(pv.getDisplayName()); details.setDisplayVersion(pv.getDisplayVersion()); details.setExtraProperties(pv.getExtraProperties()); details.setFileCreatedDate(pv.getFileCreatedDate()); details.setFileName(pv.getFileName()); details.setFileSize(pv.getFileSize()); details.setLicenseName(pv.getLicenseName()); details.setLicenseVersion(pv.getLicenseVersion()); details.setLocation(pvcs.getLocation()); details.setLongDescription(pv.getLongDescription()); details.setMD5(pv.getMD5()); details.setMetadata(pv.getMetadata()); details.setSHA256(pv.getSHA256()); details.setShortDescription(pv.getShortDescription()); allDetails.add(details); keyPVCSMap.put(key, pvcs); } } }