/* * RHQ Management Platform * Copyright (C) 2005-2008 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 as published by * the Free Software Foundation version 2 of the License. * * 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 for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.enterprise.server.content; import java.io.OutputStream; import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; import javax.ejb.Local; import org.rhq.core.domain.auth.Subject; import org.rhq.core.domain.content.ContentSource; import org.rhq.core.domain.content.ContentSourceSyncResults; import org.rhq.core.domain.content.ContentSourceType; import org.rhq.core.domain.content.DistributionFile; import org.rhq.core.domain.content.DownloadMode; import org.rhq.core.domain.content.PackageBits; import org.rhq.core.domain.content.PackageDetailsKey; import org.rhq.core.domain.content.PackageVersion; import org.rhq.core.domain.content.PackageVersionContentSource; import org.rhq.core.domain.content.Repo; import org.rhq.core.domain.content.RepoSyncResults; import org.rhq.core.domain.content.composite.PackageVersionMetadataComposite; import org.rhq.core.domain.util.PageControl; import org.rhq.core.domain.util.PageList; import org.rhq.enterprise.server.plugin.pc.content.AdvisorySyncReport; 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.DistributionSyncReport; import org.rhq.enterprise.server.plugin.pc.content.PackageSyncReport; import org.rhq.enterprise.server.plugin.pc.content.RepoDetails; /** * Interface that provides access to the {@link ContentSource} objects deployed in the server, allowing the callers to * access data about and from remote content repositories. */ @Local public interface ContentSourceManagerLocal { /** * This will look for any {@link PackageVersion}s that are "orphaned" (that is, is not related to any existing * content source or repo and is not installed anywhere) and will remove any orphans that it finds. This means it * will delete orphaned {@link PackageVersion} definitions and (if loaded) their {@link PackageBits}. * * @param subject user requesting the purge */ void purgeOrphanedPackageVersions(Subject subject); /** * Deletes the identified content source. Any package versions that originated from this content source but are * still related to one or more repos will remain. * * @param subject An authenticated user making the request. * @param contentSourceId The id of the content source to be deleted. */ void deleteContentSource(Subject subject, int contentSourceId); /** * Returns all {@link ContentSourceType} objects that are configured in the system. * * @return all content source types */ Set<ContentSourceType> getAllContentSourceTypes(); /** * Returns all {@link ContentSource} objects that are configured in the system but not presently * associated with the repo identified by repoId * * @param subject user asking to perform this * @param repoId the identifier for the repo * @param pc pagination controls * * @return all content sources that are not presently associated with the repo identified by repoId */ PageList<ContentSource> getAvailableContentSourcesForRepo(Subject subject, Integer repoId, PageControl pc); /** * Returns all {@link ContentSource} objects that are configured in the system. * * @param subject user asking to perform this * @param pc pagination controls * * @return all content sources */ PageList<ContentSource> getAllContentSources(Subject subject, PageControl pc); /** * Get a {@link ContentSourceType} by name. <code>null</code> will be returned if there is no content source type by * that name. * * @param name the name of the {@link ContentSourceType} to be returned * * @return {@link ContentSourceType} found. <code>null</code> if none found */ ContentSourceType getContentSourceType(String name); /** * Returns the {@link ContentSource} from its ID. * * @param subject user asking to perform this * @param contentSourceId identifies the content source to return * * @return the content source object, <code>null</code> if the ID is invalid */ ContentSource getContentSource(Subject subject, int contentSourceId); /** * Get a {@link ContentSource} by name and {@link ContentSourceType} name. <code>null</code> will be returned if * there is no content source with the given criteria. * * @param subject user asking to perform this * @param name the name of the {@link ContentSource} to be returned * @param typeName the name of the {@link ContentSourceType} * * @return {@link ContentSource} found. <code>null</code> if none found */ ContentSource getContentSourceByNameAndType(Subject subject, String name, String typeName); /** * Gets the list of imported repos that are associated with a given content source. * * @param subject user asking to perform this * @param contentSourceId the id of a content source. * @param pc pagination controls * * @return list of associated repos */ PageList<Repo> getAssociatedRepos(Subject subject, int contentSourceId, PageControl pc); /** * Gets the list of candidate repos that are associated with a given content source. * * @param subject user asking to perform this * @param contentSourceId the id of a content source. * @param pc pagination controls * * @return list of candidate repos */ PageList<Repo> getCandidateRepos(Subject subject, int contentSourceId, PageControl pc); /** * Allows the caller to page through a list of historical sync results for a content source. * * @param subject user asking to perform this * @param contentSourceId The id of a content source. * @param pc pagination controls * * @return the list of results */ PageList<ContentSourceSyncResults> getContentSourceSyncResults(Subject subject, int contentSourceId, PageControl pc); /** * Allow a user to purge content source sync results. * * @param subject user asking to perform this * @param ids the IDs of the {@link ContentSourceSyncResults} to delete */ void deleteContentSourceSyncResults(Subject subject, int[] ids); /** * Create the specified content source. * * @param subject The user making the request. * * @param contentSource A content source to be created. * * @return The created content source. */ ContentSource createContentSource(Subject subject, ContentSource contentSource) throws ContentSourceException; /** * Update an existing {@link ContentSource} object and restarts its underlying adapter. This also forces the adapter * to immediately sync with the remote repository. Note that this will only update the content source's basic fields * like name, description, etc. as well as its configuration. Specifically, it will not update the other * relationships like its repos. Use {@link #addContentSourcesToRepo(Subject, int, int[])} for things like * that. * * @param subject wanting to update the ContentSource * @param contentSource to be updated * @param syncNow if you wish to resync the ContentSource after updating * * @return the ContentSource that was updated */ ContentSource updateContentSource(Subject subject, ContentSource contentSource, boolean syncNow) throws ContentSourceException; /** * Given a content source ID, this will test that the adapter responsible for pulling data from the content source's * remote repository can actually connect to that repository, and if not, throw an Exception. * * @param contentSourceId the id of the content source on which to test the connection * * @throws Exception if the test failed */ void testContentSourceConnection(int contentSourceId) throws Exception; /** * Requests that the identified content source be synchronized and if not lazy-loading to also download its * packages' bits. This ensures that the server maintains an accurate list of what is available on the content * source by seeing what was added, removed or updated since the last time the content source was synchronized. This * method is performed asynchronously - the calling thread will not block and will return immediately. * * @param subject the user asking to perform this * @param contentSourceId identifies the content source to synchronize * * @throws Exception if failed to kick off the synchronize job */ void synchronizeAndLoadContentSource(Subject subject, int contentSourceId); /** * Returns all the package versions that are served by the content source identified by the given ID. * * @param subject the user asking to perform this * @param contentSourceId The id of a content source. * @param pc pagination controls * * @return all package versions that the content source will be providing content for. The object returned also * contains the location where those package versions are located in the content source */ PageList<PackageVersionContentSource> getPackageVersionsFromContentSource(Subject subject, int contentSourceId, PageControl pc); /** * Returns all packages from the given repo. This call takes into account the content source to provide any * extra data on the package versions that exist for the particular mapping of content source and package, * such as the location attribute. * * @param subject user retrieving the data * @param contentSourceId content source from which the packages are retrieved * @param repoId repo from which the packages are retrieved * * @return all package versions that the content source will be providing content for. The object returned also * contains the location where those package versions are located in the content source */ List<PackageVersionContentSource> getPackageVersionsFromContentSourceForRepo(Subject subject, int contentSourceId, int repoId); /** * Returns count of PackageVersions associated with the given content source. * * @param subject caller requesting count * @param contentSourceId to lookup * * @return count if any */ long getPackageVersionCountFromContentSource(Subject subject, int contentSourceId); /** * Returns the length of the package version identified by its {@link PackageDetailsKey}. This method ensures that * the given resource is subscribed to a repo that contains the package version. * * @param resourceId * @param packageDetailsKey * * @return the length of the package version */ long getPackageBitsLength(int resourceId, PackageDetailsKey packageDetailsKey); ///////////////////////////////////////////////////////////////////// // The methods below should not be exposed to remote clients /** * Returns all the package versions that are served by all the content sources identified by the given IDs. * * @param subject the user asking to perform this * @param contentSourceIds * @param pc * * @return all package versions that the content sources will be providing content for. The object returned also * contains the location where those package versions are located in the content source */ PageList<PackageVersionContentSource> getPackageVersionsFromContentSources(Subject subject, int[] contentSourceIds, PageControl pc); /** * Returns all the package versions that are served by the content source identified by the given ID but whose * {@link PackageVersion#getPackageBits() package bits} have not been loaded yet. * * @param subject the user asking to perform this * @param contentSourceId * @param pc * * @return all unloaded package versions that the content source will be providing content for. The object returned * also contains the location where those package versions are located in the content source */ PageList<PackageVersionContentSource> getUnloadedPackageVersionsFromContentSourceInRepo(Subject subject, int contentSourceId, int repoId, PageControl pc); /** * This will download all the distribution bits associated with a specific content source. * * @param subject * @param contentSource */ void downloadDistributionBits(Subject subject, ContentSource contentSource); /** * This will download the actual package bits for that package version from that content source's remote repository. * * @param resourceId * @param packageDetailsKey * @param packageVersionId * @return */ boolean downloadPackageBits(int resourceId, PackageDetailsKey packageDetailsKey); /** * Given a {@link PackageVersionContentSource} which contains the ID of a content source, an ID of a package * version, and the location of that package version on the remote content source repo, this will download the * actual package bits for that package version from that content source's remote repository. * * <p>An exception will be thrown if the package bits could not be loaded.</p> * * <p>This method is potentially a long running operation. Its transaction timeout should be extended * appropriately.</p> * * <p>If the content source where the package version is found is flagged to {@link DownloadMode#NEVER NEVER} * download package bits, this will immediately return <code>null</code>.</p> * * @param subject the user asking to perform this * @param pvcs * * @return information about the package bits that were downloaded - note that this will NOT have the actual bits * inside it - we will not load the package bits in memory for obvious reasons. This will be <code> * null</code> if the content source is configured to never actually download package bits. */ PackageBits downloadPackageBits(Subject subject, PackageVersionContentSource pvcs); /** * Requests that the identified content source be synchronized. This ensures that the server maintains an accurate * list of what is available on the content source by seeing what was added, removed or updated since the last time * the content source was synchronized. * * <p>Do <b>not</b> call this method unless you know what you are doing. It is potentially a long running process * and will block the calling thread. In addition, this method must <b>never</b> be called from inside a * transaction, because it can be long running. You probably want to call * {@link #synchronizeAndLoadContentSource(int)}.</p> * * @param contentSourceId identifies the content source to synchronize * * @return <code>true</code> if the synchronization is complete; <code>false</code> if there is already a * synchronization already in progress and this call did nothing and aborted. * * @throws Exception if failed to synchronize */ boolean internalSynchronizeContentSource(int contentSourceId) throws Exception; /** * Creates a new sync results object. Note that this will return <code>null</code> if the given results object has a * status of INPROGRESS but there is already a sync results object that is still INPROGRESS and has been in that * state for less than 24 hours. Use this to prohibit the system from synchronizing on the same content source * concurrently. * * @param results the results that should be persisted * * @return the persisted object, or <code>null</code> if another sync is currently inprogress. */ ContentSourceSyncResults persistContentSourceSyncResults(ContentSourceSyncResults results); /** * Updates an existing sync results object. Do not use this method to create a new sync results object - use * {@link #persistContentSourceSyncResults(ContentSourceSyncResults)} for that. * * @param results the existing results that should be or merged * * @return the merged object */ ContentSourceSyncResults mergeContentSourceSyncResults(ContentSourceSyncResults results); /** * Returns the full sync results object. * * @param resultsId the ID of the object to return * * @return the full sync results */ ContentSourceSyncResults getContentSourceSyncResults(int resultsId); /** * Updates the server with the results of a repo import from a content source. * * @param repos list of repo data received from the content source; should not be <code>null</code> */ void mergeRepoImportResults(List<RepoDetails> repos); /** * After a sync has happened, this is responsible for persisting the results. * * @param contentSource content source that was just sync'ed * @param report information on what the current inventory should look like * @param previous information from the previous inventory, before the sync happened * @param syncResults sync results object that should be updated to track this method's progress * * @return the updated syncResults that includes more summary information in the results string that indicates what * was done */ RepoSyncResults mergePackageSyncReport(ContentSource contentSource, Repo repo, PackageSyncReport report, Map<ContentProviderPackageDetailsKey, PackageVersionContentSource> previous, RepoSyncResults syncResults); /** * After a sync has happened, this is responsible for persisting the results. * * @param contentSource content source that was just sync'ed * @param report information on what the current inventory should look like * @param syncResults sync results object that should be updated to track this method's progress * * @return the updated syncResults that includes more summary information in the results string that indicates what * was done */ RepoSyncResults mergeDistributionSyncReport(ContentSource contentSource, DistributionSyncReport report, RepoSyncResults syncResults); /** * After a sync has happened, this is responsible for persisting the results. * * @param contentSource content source that was just sync'ed * @param report information on what the current inventory should look like * @param syncResults sync results object that should be updated to track this method's progress * * @return the updated syncResults that includes more summary information in the results string that indicates what * was done */ RepoSyncResults mergeAdvisorySyncReport(ContentSource contentSource, AdvisorySyncReport report, RepoSyncResults syncResults); void _mergePackageSyncReportUpdateRepo(int contentSourceId); RepoSyncResults _mergePackageSyncReportREMOVE(ContentSource contentSource, Repo repo, PackageSyncReport report, Map<ContentProviderPackageDetailsKey, PackageVersionContentSource> previous, RepoSyncResults syncResults, StringBuilder progress); RepoSyncResults _mergePackageSyncReportADD(ContentSource contentSource, Repo repo, Collection<ContentProviderPackageDetails> newPackages, Map<ContentProviderPackageDetailsKey, PackageVersionContentSource> previous, RepoSyncResults syncResults, StringBuilder progress, int addCount); RepoSyncResults _mergePackageSyncReportUPDATE(ContentSource contentSource, PackageSyncReport report, Map<ContentProviderPackageDetailsKey, PackageVersionContentSource> previous, RepoSyncResults syncResults, StringBuilder progress); RepoSyncResults _mergeDistributionSyncReportREMOVE(ContentSource contentSource, DistributionSyncReport report, RepoSyncResults syncResults, StringBuilder progress); RepoSyncResults _mergeDistributionSyncReportADD(ContentSource contentSource, DistributionSyncReport report, RepoSyncResults syncResults, StringBuilder progress); RepoSyncResults _mergeAdvisorySyncReportADD(ContentSource contentSource, AdvisorySyncReport report, RepoSyncResults syncResults, StringBuilder progress); RepoSyncResults _mergeAdvisorySyncReportREMOVE(ContentSource contentSource, AdvisorySyncReport report, RepoSyncResults syncResults, StringBuilder progress); /** * Requests all {@link PackageVersion#getMetadata() metadata} for all package versions that the given resource * component is subscribed to (see {@link Repo#getResources()}. The returned object has the metadata bytes that * are meaningful to the calling plugin component. * * <p>Note that the returned object has the package version IDs that can be used to retrieve the actual content bits * of the package versions via a call to {@link #retrievePackageVersionBits(int, int)}.</p> * * <p>Callers should consider caching the returned metadata. Use {@link #getResourceSubscriptionMD5(int)} to get the * MD5 hashcode of the metadata for the resource to aid in determining when a cache of metadata is stale.</p> * * @param resourceId identifies the resource requesting the data; all package versions in all the resource's * subscribed repos will be represented in the returned map * @param pc this method can potentially return a large set; this page control object allows the caller to * page through that large set, as opposed to requesting the entire set in one large chunk * * @return the list of all package versions' metadata * * @see #getResourceSubscriptionMD5(int) */ PageList<PackageVersionMetadataComposite> getPackageVersionMetadata(int resourceId, PageControl pc); /** * Gets the MD5 hash which identifies a resource "content subscription". This MD5 hash will change when any repo * the resource is subscribed to has changed its contents (that is, if a package version was added/updated/removed * from it). * * @param resourceId identifies the resource requesting the MD5; any change to any package version in any of the * resource's subscribed repos will determine the MD5 * * @return the MD5 * * @see #getPackageVersionMetadata(int, PageControl) */ String getResourceSubscriptionMD5(int resourceId); /** * Requests that the actual content data (the "bits") of the identified package version be streamed down to the * caller over the given output stream that the caller provides. This method will <b>not</b> be responsible for * closing the stream when its done, the caller needs to close it. This may be a time-consuming method call because * if the bits have not yet been loaded (i.e. the content source where the package version lives * {@link ContentSource#isLazyLoad() is lazy loading} then this may be the time when it is downloaded from the * remote repository. * * <p>This is the same as calling * {@link #outputPackageVersionBitsRangeGivenResource(int, PackageDetailsKey, OutputStream, long, long)} with the start/end bytes * of 0 and -1 respectively.</p> * * @param resourceId identifies the resource making the request; if this resource is not allowed to see the * package version (due to the fact that it is not subscribed to a repo that is serving * that package version), an exception is thrown * @param packageDetailsKey identifies the {@link PackageVersion} whose {@link PackageBits} are to be streamed * @param outputStream a stream that the caller prepared where this method will write the actual content * * @return the number of bytes written to the output stream */ long outputPackageVersionBitsGivenResource(int resourceId, PackageDetailsKey packageDetailsKey, OutputStream outputStream); /** * Requests that the actual content data (the "bits") of the identified package version be streamed down to the * caller over the given output stream that the caller provides. This method will <b>not</b> be responsible for * closing the stream when its done, the caller needs to close it. This may be a time-consuming method call because * if the bits have not yet been loaded (i.e. the content source where the package version lives * {@link ContentSource#isLazyLoad() is lazy loading} then this may be the time when it is downloaded from the * remote repository. * * @param resourceId identifies the resource making the request; if this resource is not allowed to see the * package version (due to the fact that it is not subscribed to a repo that is serving * that package version), an exception is thrown * @param packageDetailsKey identifies the {@link PackageVersion} whose {@link PackageBits} are to be streamed * @param outputStream a stream that the caller prepared where this method will write the actual content * @param startByte the first byte (inclusive) of the byte range to retrieve and output (bytes start at * index 0) * @param endByte the last byte (inclusive) of the byte range to retrieve and output (-1 means up to EOF) * (bytes start at index 0) * * @return the number of bytes written to the output stream */ long outputPackageVersionBitsRangeGivenResource(int resourceId, PackageDetailsKey packageDetailsKey, OutputStream outputStream, long startByte, long endByte); /** * Requests the bits of a package being used to create a child resource be stream down to the caller over * the given output stream. This method will <b>not</b> take care of closing the stream when it is finished; * it is the caller's responsibility. This may be a time-consuming method call because * if the bits have not yet been loaded (i.e. the content source where the package version lives * {@link ContentSource#isLazyLoad() is lazy loading} then this may be the time when it is downloaded from the * remote repository. * * @param parentResourceId identifies the parent resource under which the new resource is being created * @param resourceTypeName type of child resource being created * @param packageDetailsKey package being used to create the child resource * @param outputStream an output stream where the server should write the package contents. It is up to the * caller to prepare this output stream in order to write the package content to an * appropriate location. * * @return the number of bytes written to the output stream */ long outputPackageBitsForChildResource(int parentResourceId, String resourceTypeName, PackageDetailsKey packageDetailsKey, OutputStream outputStream); /** * Requests the bits of a package be streamed down to the caller over the given output stream. * This method will <b>not</b> take care of closing the stream when it is finished; * it is the caller's responsibility. This may be a time-consuming method call because * if the bits have not yet been loaded (i.e. the content source where the package version lives * {@link ContentSource#isLazyLoad() is lazy loading} then this may be the time when it is downloaded from the * remote repository. * * @param packageVersion packageVersion to fetch * @param outputStream an output stream where the server should write the package contents. It is up to the * caller to prepare this output stream in order to write the package content to an * appropriate location. * * @return the number of bytes written to the output stream */ long outputPackageVersionBits(PackageVersion packageVersion, OutputStream outputStream); /** * Requests a range of bits from a package. This range of bits will be streamed down to the caller over the given * output stream. This method will <b>not</b> take care of closing the stream when it is finished; * it is the caller's responsibility. This may be a time-consuming method call because * if the bits have not yet been loaded (i.e. the content source where the package version lives * {@link ContentSource#isLazyLoad() is lazy loading} then this may be the time when it is downloaded from the * remote repository. * * @param packageVersion packageVersion to fetch * @param outputStream an output stream where the server should write the package contents. It is up to the * caller to prepare this output stream in order to write the package content to an * appropriate location. * @param startByte start index * @param endByte end index * * @return the number of bytes written to the output stream */ long outputPackageVersionBits(PackageVersion packageVersion, OutputStream outputStream, long startByte, long endByte); /** * Requests the bits of a distribution file be streamed down to the caller over the given output stream. * This method will <b>not</b> take care of closing the stream when it is finished; * it is the caller's responsibility. * * @param distFile distribution file to fetch * @param outputStream an output stream where the server should write the package contents. It is up to the * caller to prepare this output stream in order to write the package content to an * appropriate location. * * @return the number of bytes written to the output stream */ long outputDistributionFileBits(DistributionFile distFile, OutputStream outputStream); /** * Adds the specified content source to the database but does not attempt to create or start * the server-side plugin provider implementation associated with it. * <p/> * This should only be used for test purposes. * * @param subject may not be <code>null</code> * @param contentSource may not be <code>null</code> * @return instance after being persisted; will contain a populated ID value * @throws ContentSourceException if the content source cannot be created, such as if the data in * the given object are not valid */ ContentSource simpleCreateContentSource(Subject subject, ContentSource contentSource) throws ContentSourceException; }