/* * 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, 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.core.domain.content; import java.io.Serializable; import java.util.Comparator; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.SequenceGenerator; import javax.persistence.Table; import javax.xml.bind.annotation.XmlTransient; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.resource.ProductVersion; import org.rhq.core.domain.util.OSGiVersionComparator; /** * Represents a specific version of a {@link Package}. This does <i>not</i> represent an installed package found * deployed in any platform or on a resource (that's {@link InstalledPackage}). This object refers to a known version of * a particular package that can be installed on applicable resources. * * @author Jason Dobies */ @Entity @NamedQueries({ @NamedQuery(name = PackageVersion.QUERY_FIND_ID_PACKAGES_BY_RESOURCE_ID, query = "" // + "SELECT DISTINCT pv.generalPackage.id FROM PackageVersion pv WHERE pv.id IN " + "(SELECT ip.packageVersion.id FROM InstalledPackage ip WHERE ip.resource.id = :resourceId )"), @NamedQuery(name = PackageVersion.QUERY_FIND_BY_PACKAGE_VERSION, query = "" // + "SELECT pv FROM PackageVersion AS pv " // + " WHERE pv.generalPackage.id = :packageId " // + " AND pv.version = :version "// + " ORDER BY pv.id DESC "), @NamedQuery(name = PackageVersion.QUERY_FIND_BY_PACKAGE_VER_ARCH, query = "SELECT pv FROM PackageVersion AS pv " + " WHERE pv.generalPackage.name = :name " + " AND pv.generalPackage.packageType.id = :packageTypeId " + " AND pv.architecture.id = :architectureId " + " AND pv.version = :version "), @NamedQuery(name = PackageVersion.QUERY_FIND_BY_PACKAGE_DETAILS_KEY_WITH_NON_NULL_RESOURCE_TYPE, query = "SELECT pv FROM PackageVersion AS pv " + " WHERE pv.generalPackage.name = :packageName " + " AND pv.generalPackage.packageType.name = :packageTypeName " + " AND pv.generalPackage.packageType.resourceType.id = :resourceTypeId " + " AND pv.architecture.name = :architectureName " + " AND pv.version = :version "), @NamedQuery(name = PackageVersion.QUERY_FIND_BY_PACKAGE_DETAILS_KEY, query = "SELECT pv FROM PackageVersion AS pv " + " WHERE pv.generalPackage.name = :packageName " + " AND pv.generalPackage.packageType.name = :packageTypeName " + " AND pv.generalPackage.packageType.resourceType = :resourceType " + " AND pv.architecture.name = :architectureName " + " AND pv.version = :version "), @NamedQuery(name = PackageVersion.QUERY_FIND_ID_BY_PACKAGE_DETAILS_KEY_AND_RES_ID, query = "SELECT pv.id " + " FROM PackageVersion AS pv " + " JOIN pv.generalPackage.packageType.resourceType.resources r " + " WHERE pv.generalPackage.name = :packageName " + " AND pv.generalPackage.packageType.name = :packageTypeName " + " AND r.id = :resourceId " + " AND pv.architecture.name = :architectureName " + " AND pv.version = :version "), // DO NOT SELECT DISTINCT IN OUTER SELECT - Oracle bombs on PackageVersion.metadata BLOB column @NamedQuery(name = PackageVersion.QUERY_FIND_BY_REPO_ID, query = "SELECT pv " + " FROM PackageVersion pv " + " WHERE pv.id IN (SELECT DISTINCT pv1.id " + " FROM PackageVersion pv1 " + " LEFT JOIN pv1.repoPackageVersions cpv " + " WHERE cpv.repo.id = :repoId) "), // DO NOT SELECT DISTINCT IN OUTER SELECT - Oracle bombs on PackageVersion.metadata BLOB column @NamedQuery(name = PackageVersion.QUERY_FIND_BY_REPO_ID_FILTERED, query = "SELECT pv " + " FROM PackageVersion pv " + " WHERE pv.id IN (SELECT DISTINCT pv1.id " + " FROM PackageVersion pv1 " + " LEFT JOIN pv1.repoPackageVersions cpv " + " WHERE cpv.repo.id = :repoId" + " AND (UPPER(pv1.displayName) LIKE :filter " + " OR :filter IS NULL)) "), @NamedQuery(name = PackageVersion.QUERY_FIND_BY_PACKAGE_ID, query = "SELECT pv " + " FROM PackageVersion pv " + " WHERE pv.generalPackage.id = :packageId "), @NamedQuery(name = PackageVersion.QUERY_FIND_BY_REPO_ID_WITH_PACKAGE, query = "SELECT pv " + " FROM PackageVersion pv " + " LEFT JOIN FETCH pv.generalPackage " + " WHERE pv.id IN (SELECT DISTINCT pv1.id " + " FROM PackageVersion pv1 " + " LEFT JOIN pv1.repoPackageVersions cpv " + " WHERE cpv.repo.id = :repoId) "), @NamedQuery(name = PackageVersion.QUERY_FIND_BY_REPO_ID_WITH_PACKAGE_FILTERED, query = "SELECT pv " + " FROM PackageVersion pv " + " LEFT JOIN FETCH pv.generalPackage " + " WHERE pv.id IN (SELECT DISTINCT pv1.id " + " FROM PackageVersion pv1 " + " LEFT JOIN pv1.repoPackageVersions cpv " + " WHERE cpv.repo.id = :repoId" + " AND (UPPER(pv1.displayName) LIKE :filter ESCAPE :escapeChar " + " OR :filter IS NULL)) "), @NamedQuery(name = PackageVersion.QUERY_FIND_METADATA_BY_RESOURCE_ID, query = "SELECT new org.rhq.core.domain.content.composite.PackageVersionMetadataComposite " + " ( " + " pv.id, " + " pv.metadata, " + " pv.generalPackage.name, " + " pv.version, " + " pv.generalPackage.packageType.name, " + " pv.architecture.name " + " ) " + " FROM PackageVersion pv " + " WHERE pv.id IN (SELECT DISTINCT pv1.id " + " FROM PackageVersion pv1 " + " LEFT JOIN pv1.repoPackageVersions cpv " + " LEFT JOIN cpv.repo.resourceRepos rc " + " WHERE rc.resource.id = :resourceId) "), @NamedQuery(name = PackageVersion.QUERY_GET_PKG_BITS_LENGTH_BY_PKG_DETAILS_AND_RES_ID, query = "SELECT pv.fileSize " + " FROM PackageVersion AS pv " + " JOIN pv.generalPackage.packageType.resourceType.resources r " + " WHERE pv.generalPackage.name = :packageName " + " AND pv.generalPackage.packageType.name = :packageTypeName " + " AND r.id = :resourceId " + " AND pv.architecture.name = :architectureName " + " AND pv.version = :version "), // deletes orphaned package versions - that is, if they have no associated content sources or repos and is not installed anywhere @NamedQuery(name = PackageVersion.DELETE_IF_NO_CONTENT_SOURCES_OR_REPOS, query = "DELETE PackageVersion pv " + " WHERE pv.id NOT IN (SELECT pvcs.packageVersion.id " // + " FROM PackageVersionContentSource pvcs) " // + " AND pv.repoPackageVersions IS EMPTY " // + " AND pv.installedPackages IS EMPTY " // + " AND pv.installedPackageHistory IS EMPTY "), @NamedQuery(name = PackageVersion.DELETE_BY_PKG_IF_NO_CONTENT_SOURCES_OR_REPOS, query = "DELETE PackageVersion pv " + " WHERE pv.id NOT IN (SELECT pvcs.packageVersion.id " // + " FROM PackageVersionContentSource pvcs) " // + " AND pv.repoPackageVersions IS EMPTY " // + " AND pv.installedPackages IS EMPTY " // + " AND pv.installedPackageHistory IS EMPTY " // + " AND pv.generalPackage.id = :packageId"), @NamedQuery(name = PackageVersion.DELETE_SINGLE_IF_NO_CONTENT_SOURCES_OR_REPOS, query = "DELETE PackageVersion pv " + " WHERE pv.id = :packageVersionId" // + " AND pv.repoPackageVersions IS EMPTY " // + " AND pv.installedPackages IS EMPTY " // + " AND pv.installedPackageHistory IS EMPTY "), @NamedQuery(name = PackageVersion.DELETE_MULTIPLE_IF_NO_CONTENT_SOURCES_OR_REPOS, query = "DELETE PackageVersion pv " + " WHERE pv.id IN ( :packageVersionIds )" // + " AND pv.repoPackageVersions IS EMPTY " // + " AND pv.installedPackages IS EMPTY " // + " AND pv.installedPackageHistory IS EMPTY "), // the bulk delete that removes the PVPV mapping from orphaned package versions @NamedQuery(name = PackageVersion.DELETE_PVPV_IF_NO_CONTENT_SOURCES_OR_REPOS, query = "DELETE ProductVersionPackageVersion pvpv " + " WHERE pvpv.packageVersion.id NOT IN (SELECT pvcs.packageVersion.id " + " FROM PackageVersionContentSource pvcs) " + " AND pvpv.packageVersion.repoPackageVersions IS EMPTY " + " AND pvpv.packageVersion.installedPackages IS EMPTY " + " AND pvpv.packageVersion.installedPackageHistory IS EMPTY "), // finds all orphaned PVs that have extra props configurations (so the configs can be deleted) @NamedQuery(name = PackageVersion.FIND_EXTRA_PROPS_IF_NO_CONTENT_SOURCES_OR_REPOS, query = "SELECT pv " + " FROM PackageVersion pv LEFT JOIN FETCH pv.extraProperties " + " WHERE pv.id NOT IN (SELECT pvcs.packageVersion.id " + " FROM PackageVersionContentSource pvcs) " + " AND pv.repoPackageVersions IS EMPTY " + " AND pv.installedPackages IS EMPTY " + " AND pv.installedPackageHistory IS EMPTY " + " AND pv.extraProperties IS NOT NULL "), // finds all orphaned PVs that have its bits loaded on the filesystem @NamedQuery(name = PackageVersion.FIND_FILES_IF_NO_CONTENT_SOURCES_OR_REPOS, query = "SELECT new org.rhq.core.domain.content.composite.PackageVersionFile( " + " pv.id, " + " pv.fileName " + " ) " + " FROM PackageVersion pv JOIN pv.packageBits pb " + " WHERE pv.id NOT IN (SELECT pvcs.packageVersion.id " + " FROM PackageVersionContentSource pvcs) " + " AND pv.repoPackageVersions IS EMPTY " + " AND pv.installedPackages IS EMPTY " + " AND pv.installedPackageHistory IS EMPTY " + " AND pb.blob.bits IS NULL "), @NamedQuery(name = PackageVersion.QUERY_FIND_COMPOSITE_BY_ID, query = "SELECT new org.rhq.core.domain.content.composite.PackageVersionComposite( " + " pv, " + " pv.generalPackage.packageType.name, " + " pv.generalPackage.packageType.category, " + " pv.generalPackage.name, " + " pv.architecture.name, " + " pv.generalPackage.classification, " + " pv.packageBits.id, " + " (SELECT count(pb.id) FROM pv.packageBits pb WHERE pb.blob.bits IS NOT NULL) " + " ) " + " FROM PackageVersion pv WHERE pv.id = :id "), @NamedQuery(name = PackageVersion.QUERY_FIND_COMPOSITE_BY_ID_WITH_PROPS, query = "SELECT new org.rhq.core.domain.content.composite.PackageVersionComposite( " + " pv, " + " (SELECT c FROM Configuration c WHERE c.id = pv.extraProperties.id), " + " pv.generalPackage.packageType.name, " + " pv.generalPackage.packageType.category, " + " pv.generalPackage.name, " + " pv.architecture.name, " + " pv.generalPackage.classification, " + " pv.packageBits.id, " + " (SELECT count(pb.id) FROM pv.packageBits pb WHERE pb.blob.bits IS NOT NULL) " + " ) " + " FROM PackageVersion pv WHERE pv.id = :id"), @NamedQuery(name = PackageVersion.QUERY_FIND_COMPOSITES_BY_IDS, query = "SELECT new org.rhq.core.domain.content.composite.PackageVersionComposite( " + " pv, " + " pv.generalPackage.packageType.name, " + " pv.generalPackage.packageType.category, " + " pv.generalPackage.name, " + " pv.architecture.name, " + " pv.generalPackage.classification " + " ) " + " FROM PackageVersion pv WHERE pv.id IN (:ids) "), @NamedQuery(name = PackageVersion.QUERY_FIND_COMPOSITE_BY_FILTERS, query = "SELECT new org.rhq.core.domain.content.composite.PackageVersionComposite( " + " pv, " + " pv.generalPackage.packageType.displayName, " + " pv.generalPackage.packageType.category, " + " pv.generalPackage.name, " + " pv.architecture.name, " + " pv.generalPackage.classification " + " ) " + " FROM PackageVersion pv " + " JOIN pv.repoPackageVersions cpv " + " JOIN cpv.repo.resourceRepos rc " + " LEFT JOIN pv.productVersionPackageVersions pvpv " + " WHERE rc.resource.id = :resourceId " + " AND cpv.repo.id = rc.repo.id " + " AND (UPPER(pv.displayName) LIKE :filter " + " OR :filter IS NULL) " + " AND (pv.productVersionPackageVersions IS EMPTY " + " OR (pv.productVersionPackageVersions IS NOT EMPTY " + " AND pvpv.productVersion = rc.resource.productVersion)) " + " AND (pv.id NOT IN " + " (SELECT pv1.id FROM PackageVersion pv1 " + " WHERE pv1.id IN " + " (SELECT ip1.packageVersion.id FROM InstalledPackage ip1 WHERE ip1.resource.id = :resourceId)" + " )" + " )"), @NamedQuery(name = PackageVersion.QUERY_FIND_BY_ID, query = "SELECT pv FROM PackageVersion pv WHERE pv.id = :id"), @NamedQuery(name = PackageVersion.QUERY_FIND_PACKAGEVERSION_BY_FILENAME, query = "SELECT pv FROM PackageVersion AS pv WHERE pv.fileName = :rpmName)"), @NamedQuery(name = PackageVersion.QUERY_FIND_BY_PACKAGE_AND_REPO_ID, query = "SELECT pv" + " FROM PackageVersion pv" + " JOIN pv.repoPackageVersions rpv" + " WHERE pv.generalPackage.id = :packageId" + " AND rpv.repo.id = :repoId"), @NamedQuery(name = PackageVersion.QUERY_FIND_DELETEABLE_IDS_IN_REPO, query = "SELECT pv.id FROM PackageVersion pv" + " WHERE (pv.id, 1) IN" + " (SELECT pv2.id, (SELECT COUNT(rpv) FROM RepoPackageVersion rpv WHERE rpv.packageVersion.id = pv2.id)" + " FROM PackageVersion pv2" + " WHERE pv2.id IN ( :packageVersionIds )" + " AND pv2.id IN (SELECT rpv.packageVersion.id FROM RepoPackageVersion rpv WHERE rpv.repo.id = :repoId)" + ")"), @NamedQuery(name = PackageVersion.QUERY_FIND_PACKAGE_HISTORICAL_VERSIONS, query = "SELECT pv FROM PackageVersion pv " + "WHERE pv.generalPackage.id = :packageId AND pv.id NOT IN ( SELECT ip.packageVersion FROM InstalledPackage ip) AND " + "pv.packageBits IS NOT NULL AND pv.id NOT IN (SELECT pvcs.packageVersion.id FROM " + "PackageVersionContentSource pvcs) ORDER BY pv.id DESC ") // }) @SequenceGenerator(allocationSize = org.rhq.core.domain.util.Constants.ALLOCATION_SIZE, name = "RHQ_PACKAGE_VERSION_ID_SEQ", sequenceName = "RHQ_PACKAGE_VERSION_ID_SEQ") @Table(name = "RHQ_PACKAGE_VERSION") public class PackageVersion implements Serializable { // Constants -------------------------------------------- private static final long serialVersionUID = 1L; public static final String QUERY_FIND_ID_PACKAGES_BY_RESOURCE_ID = "PackageVersion.findIdPackagesByResouceId"; public static final String QUERY_FIND_BY_PACKAGE_VERSION = "PackageVersion.findByPackageVersion"; public static final String QUERY_FIND_BY_PACKAGE_VER_ARCH = "PackageVersion.findByPackageVerArch"; public static final String QUERY_FIND_BY_PACKAGE_SHA_RES_TYPE = "PackageVersion.findByPackageShaResType"; public static final String QUERY_FIND_BY_PACKAGE_DETAILS_KEY_WITH_NON_NULL_RESOURCE_TYPE = "PackageVersion.findByPackageDetailsKeyWithNonNullResourceType"; public static final String QUERY_FIND_BY_PACKAGE_DETAILS_KEY = "PackageVersion.findByPackageDetailsKey"; public static final String QUERY_FIND_BY_PACKAGE_DETAILS_SHA = "PackageVersion.findByPackageDetailsSha"; public static final String QUERY_FIND_ID_BY_PACKAGE_DETAILS_KEY_AND_RES_ID = "PackageVersion.findIdByPackageDetailsKeyAndResId"; public static final String QUERY_FIND_BY_REPO_ID = "PackageVersion.findByRepoId"; public static final String QUERY_FIND_BY_REPO_ID_FILTERED = "PackageVersion.findByRepoIdFiltered"; public static final String QUERY_FIND_BY_PACKAGE_ID = "PackageVersion.findByPackageId"; public static final String QUERY_FIND_BY_PACKAGE_AND_REPO_ID = "PackageVersion.findByPackageAndRepoId"; public static final String QUERY_FIND_BY_REPO_ID_WITH_PACKAGE = "PackageVersion.findByRepoIdWithPackage"; public static final String QUERY_FIND_BY_REPO_ID_WITH_PACKAGE_FILTERED = "PackageVersion.findByRepoIdWithPackageFiltered"; public static final String QUERY_FIND_METADATA_BY_RESOURCE_ID = "PackageVersion.findMetadataByResourceId"; public static final String QUERY_GET_PKG_BITS_LENGTH_BY_PKG_DETAILS_AND_RES_ID = "PackageVersion.getPkgBitsLengthByPkgDetailsAndResId"; public static final String DELETE_IF_NO_CONTENT_SOURCES_OR_REPOS = "PackageVersion.deleteIfNoContentSourcesOrRepos"; public static final String DELETE_BY_PKG_IF_NO_CONTENT_SOURCES_OR_REPOS = "PackageVersion.deleteByPkgIfNoContentSourcesOrRepos"; public static final String DELETE_SINGLE_IF_NO_CONTENT_SOURCES_OR_REPOS = "PackageVersion.deleteSingleIfNoContentSourcesOrRepos"; public static final String DELETE_MULTIPLE_IF_NO_CONTENT_SOURCES_OR_REPOS = "PackageVersion.deleteMultipleIfNoContentSourcesOrRepos"; public static final String DELETE_PVPV_IF_NO_CONTENT_SOURCES_OR_REPOS = "PackageVersion.deletePVPVIfNoContentSourcesOrRepos"; public static final String FIND_EXTRA_PROPS_IF_NO_CONTENT_SOURCES_OR_REPOS = "PackageVersion.findOrphanedExtraProps"; public static final String FIND_FILES_IF_NO_CONTENT_SOURCES_OR_REPOS = "PackageVersion.findOrphanedFiles"; public static final String QUERY_FIND_COMPOSITE_BY_ID = "PackageVersion.findCompositeById"; public static final String QUERY_FIND_COMPOSITE_BY_ID_WITH_PROPS = "PackageVersion.findCompositeByIdWithProps"; public static final String QUERY_FIND_COMPOSITES_BY_IDS = "PackageVersion.findCompositesByIds"; public static final String QUERY_FIND_COMPOSITE_BY_FILTERS = "PackageVersion.findCompositeByFilters"; public static final String QUERY_FIND_BY_ID = "PackageVersion.findById"; public static final String QUERY_FIND_PACKAGEVERSION_BY_FILENAME = "PackageVersion.findPackageVersionByFilename"; public static final String QUERY_FIND_DELETEABLE_IDS_IN_REPO = "PackageVersion.findDeleteableVersionIds"; public static final String QUERY_FIND_PACKAGE_HISTORICAL_VERSIONS = "PackageVersion.findPackageHistoricalVersions"; /** * This is a default {@link Comparator} implementation for package versions. * If the package versions being compared both have non-null {@link PackageVersion#getVersion() versions} * an {@link OSGiVersionComparator} is used to compare them. If it fails or if one of the versions * is null the package versions are compared by {@link PackageVersion#getFileCreatedDate() file created date}. * If the creation date is not specified for one of the package versions, they proclaimed equal. * <p> * Note that this comparator is *INCONSISTENT* with <code>equals()</code> and therefore care should be taken * when using it with sets and maps (read this {@link Comparator documentation}). * * @author Lukas Krejci */ public static class DefaultPackageVersionComparator implements Comparator<PackageVersion>, Serializable { private static final long serialVersionUID = 1L; public int compare(PackageVersion p1, PackageVersion p2) { String v1 = p1.getVersion(); String v2 = p2.getVersion(); OSGiVersionComparator c = new OSGiVersionComparator(); if (v1 != null && v2 != null) { try { return c.compare(v1, v2); } catch (IllegalArgumentException e) { //well, this can happen.. not all packages have OSGi type versions. } } if (p1.getFileCreatedDate() != null && p2.getFileCreatedDate() != null) { return p1.getFileCreatedDate().compareTo(p2.getFileCreatedDate()); } //hmm... there's actually nothing we can sort these two by.. //let's compare them by id - the one inserted sooner will have a lower id return Integer.valueOf(p1.getId()).compareTo(p2.getId()); } }; /** * @see DefaultPackageVersionComparator */ public static final DefaultPackageVersionComparator DEFAULT_COMPARATOR = new DefaultPackageVersionComparator(); // Attributes -------------------------------------------- @Column(name = "ID", nullable = false) @GeneratedValue(strategy = GenerationType.AUTO, generator = "RHQ_PACKAGE_VERSION_ID_SEQ") @Id private int id; @JoinColumn(name = "PACKAGE_ID", referencedColumnName = "ID", nullable = false) @ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST }, optional = false) private Package generalPackage; @Column(name = "DISPLAY_NAME", nullable = true) private String displayName; @Column(name = "SHORT_DESCRIPTION", nullable = true) private String shortDescription; @Column(name = "LONG_DESCRIPTION", nullable = true) private String longDescription; /** * This is basically an enhanced SHA, and will be unique across PVs for a package. Architecture is no longer * a required differentiator. */ @Column(name = "VERSION", nullable = false) private String version; @Column(name = "DISPLAY_VERSION", nullable = true) private String displayVersion; @JoinColumn(name = "ARCHITECTURE_ID", referencedColumnName = "ID", nullable = false) @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST, optional = false) private Architecture architecture; @Column(name = "FILE_NAME", nullable = true) private String fileName; @Column(name = "FILE_SIZE", nullable = true) private Long fileSize; @Column(name = "FILE_MD5", nullable = true) private String md5; @Column(name = "FILE_SHA256", nullable = true) private String sha256; @Column(name = "FILE_CREATION_TIME", nullable = true) private Long fileCreatedDate; @Column(name = "LICENSE_NAME", nullable = true) private String licenseName; @Column(name = "LICENSE_VERSION", nullable = true) private String licenseVersion; @Column(name = "METADATA", nullable = true) private byte[] metadata; @JoinColumn(name = "CONFIG_ID", referencedColumnName = "ID", nullable = true) @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = true) private Configuration extraProperties; @OneToMany(mappedBy = "packageVersion", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE) private Set<RepoPackageVersion> repoPackageVersions; // this mapping is here mainly to support our JPA queries @OneToMany(mappedBy = "packageVersion", fetch = FetchType.LAZY) private Set<InstalledPackage> installedPackages; // this mapping is here mainly to support our JPA queries @OneToMany(mappedBy = "packageVersion", fetch = FetchType.LAZY) private Set<InstalledPackageHistory> installedPackageHistory; // No longer use cascade PERSIST on this. We'll associate it manually due to intracacies in blob handling @JoinColumn(name = "PACKAGE_BITS_ID", referencedColumnName = "ID", nullable = true) @OneToOne(cascade = { CascadeType.REMOVE }, fetch = FetchType.LAZY, optional = true) @XmlTransient private PackageBits packageBits; @OneToMany(mappedBy = "packageVersion", cascade = { CascadeType.REMOVE }, fetch = FetchType.LAZY) private Set<ProductVersionPackageVersion> productVersionPackageVersions; // Constructor ---------------------------------------- public PackageVersion() { // for JPA use } public PackageVersion(Package pkg, String version, Architecture arch) { setGeneralPackage(pkg); setVersion(version); setArchitecture(arch); } // Public -------------------------------------------- public int getId() { return id; } public void setId(int id) { this.id = id; } /** * Package that this version applies to. */ public Package getGeneralPackage() { return generalPackage; } public void setGeneralPackage(Package generalPackage) { this.generalPackage = generalPackage; } /** * Name of this package version that is suitable for display to the user in the UI. */ public String getDisplayName() { return displayName; } public void setDisplayName(String displayName) { this.displayName = displayName; } /** * Short free text description of this version of the package. In other words, a summary of the package. */ public String getShortDescription() { return shortDescription; } public void setShortDescription(String shortDescription) { this.shortDescription = shortDescription; } /** * Long free text description of this version of the package. */ public String getLongDescription() { return longDescription; } public void setLongDescription(String longDescription) { this.longDescription = longDescription; } /** * The machine understandable version of the package. The format of this attribute will vary based on the package. * It should be possible by simply sorting package versions on this column to determine which package version is * newer or older than another. Anyone that creates package versions must be able to generate valid version strings * that support those semantics. */ public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } /** * A version string suitable for displaying to a user. It may or may not be the same as {#getVersion()}. */ public String getDisplayVersion() { return (displayVersion != null) ? displayVersion : version; } public void setDisplayVersion(String displayVersion) { this.displayVersion = displayVersion; } /** * Architecture of this package version which tells you the kinds of platforms (e.g. operating system or hardware) * that this package version can be installed on. */ public Architecture getArchitecture() { return architecture; } public void setArchitecture(Architecture architecture) { this.architecture = architecture; } /** * Name of the file with the contents of this package. */ public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } /** * Size of the package's file. */ public Long getFileSize() { return fileSize; } public void setFileSize(Long fileSize) { this.fileSize = fileSize; } /** * The MD5 hash of this package version's file contents. */ public String getMD5() { return md5; } public void setMD5(String md5) { this.md5 = md5; } /** * The SHA-256 hash of this package version's file contents. */ public String getSHA256() { return sha256; } public void setSHA256(String sha256) { this.sha256 = sha256; } /** * Timestamp indicating when the package's file was created. */ public Long getFileCreatedDate() { return fileCreatedDate; } public void setFileCreatedDate(Long fileCreatedDate) { this.fileCreatedDate = fileCreatedDate; } /** * Name of the license under which the package falls. * * @see #getLicenseVersion() */ public String getLicenseName() { return licenseName; } public void setLicenseName(String licenseName) { this.licenseName = licenseName; } /** * Version of the package's {@link #getLicenseName() license}. */ public String getLicenseVersion() { return licenseVersion; } public void setLicenseVersion(String licenseVersion) { this.licenseVersion = licenseVersion; } /** * Optional blob of metadata that is only meaningful to the plugin that is responsible for installing this package * version. This may be <code>null</code> if this package version has no applicable metadata for it. Typical usages * of this is to provide instructional information describing the install steps the plugin needs to perform to * install the package; or yum XML information on rpms. */ public byte[] getMetadata() { return metadata; } public void setMetadata(byte[] metadata) { this.metadata = metadata; } /** * Values to further describe this package version. Values in this object will adhere to the configuration defined * by the associated package type as found in this object's {@link #getGeneralPackage() package}. * * @see PackageType#getPackageExtraPropertiesDefinition() */ public Configuration getExtraProperties() { return extraProperties; } public void setExtraProperties(Configuration extraProperties) { this.extraProperties = extraProperties; } /** * Returns the explicit mapping entities. * * @return the mapping entities * * @see #getRepos() */ public Set<RepoPackageVersion> getRepoPackageVersions() { return repoPackageVersions; } /** * The set of repos that can serve up this package version. * * <p>The returned set is not backed by this entity - if you want to alter the set of associated repos, use * {@link #getRepoPackageVersions()} or {@link #addRepo(Repo)}, {@link #removeRepo(Repo)}.</p> */ public Set<Repo> getRepos() { HashSet<Repo> repos = new HashSet<Repo>(); if (repoPackageVersions != null) { for (RepoPackageVersion cpv : repoPackageVersions) { repos.add(cpv.getRepoPackageVersionPK().getRepo()); } } return repos; } /** * Directly assign this package version to the given repo. * * @param repo * * @return the mapping that was added */ public RepoPackageVersion addRepo(Repo repo) { if (this.repoPackageVersions == null) { this.repoPackageVersions = new HashSet<RepoPackageVersion>(); } RepoPackageVersion mapping = new RepoPackageVersion(repo, this); this.repoPackageVersions.add(mapping); repo.addPackageVersion(this); return mapping; } public Set<InstalledPackage> getInstalledPackages() { return installedPackages; } public Set<InstalledPackageHistory> getInstalledPackageHistory() { return installedPackageHistory; } /** * Removes the repo as one that this package version is related to. The mapping that was removed is returned; if * the given package version was not a member of the repo, <code>null</code> is returned. * * @param repo * * @return the mapping that was removed or <code>null</code> if this package version was not mapped to the given * repo */ public RepoPackageVersion removeRepo(Repo repo) { if ((this.repoPackageVersions == null) || (repo == null)) { return null; } RepoPackageVersion doomed = null; for (RepoPackageVersion cpv : this.repoPackageVersions) { if (repo.equals(cpv.getRepoPackageVersionPK().getRepo())) { doomed = cpv; repo.removePackageVersion(this); break; } } if (doomed != null) { this.repoPackageVersions.remove(doomed); } return doomed; } /** * If this package version's actual contents (its "bits") have been inventoried, this will return a * {@link PackageBits} object representing that data. If there is no content available yet, this will return <code> * null</code>. When <code>null</code> is returned, it means it has to be pulled down, usually via a * {@link ContentSource}. <b>WARNING!</b> You most likely do <i>not</i> want to call this method if inside the scope * of an entity manager session. If you do, this will load in the {@link PackageBits} object which potentially will * load the entire package's contents in memory (and thus, if large enough, will cause an OutOfMemoryError). */ @XmlTransient public PackageBits getPackageBits() { return packageBits; } public void setPackageBits(PackageBits packageBits) { this.packageBits = packageBits; } /** * Returns the explicit mapping entities. * * @return the mapping entities * * @see #getProductVersions() */ public Set<ProductVersionPackageVersion> getProductVersionPackageVersions() { return productVersionPackageVersions; } /** * The product versions that this package version is associated with. * * <p>The returned set is not backed by this entity - if you want to alter the set of associated product versions, * use {@link #getProductVersionPackageVersions()} or {@link #addProductVersion(ProductVersion)}, * {@link #removeProductVersion(ProductVersion)}.</p> */ public Set<ProductVersion> getProductVersions() { HashSet<ProductVersion> productVersions = new HashSet<ProductVersion>(); if (productVersionPackageVersions != null) { for (ProductVersionPackageVersion pvpv : productVersionPackageVersions) { productVersions.add(pvpv.getProductVersionPackageVersionPK().getProductVersion()); } } return productVersions; } /** * Directly assign a product version to this package version. * * @param productVersion * * @return the mapping that was added */ public ProductVersionPackageVersion addProductVersion(ProductVersion productVersion) { if (this.productVersionPackageVersions == null) { this.productVersionPackageVersions = new HashSet<ProductVersionPackageVersion>(); } ProductVersionPackageVersion mapping = new ProductVersionPackageVersion(productVersion, this); this.productVersionPackageVersions.add(mapping); return mapping; } /** * Removes the product version from this package version, if it exists. If it does exist, the mapping that was * removed is returned; if the given product version did not exist as one that is a member of this package version, * <code>null</code> is returned. * * @param productVersion the product version to remove * * @return the mapping that was removed or <code>null</code> if the product version was not mapped to this package * version */ public ProductVersionPackageVersion removeProductVersion(ProductVersion productVersion) { if ((this.productVersionPackageVersions == null) || (productVersion == null)) { return null; } ProductVersionPackageVersion doomed = null; for (ProductVersionPackageVersion pvpv : this.productVersionPackageVersions) { if (productVersion.equals(pvpv.getProductVersionPackageVersionPK().getProductVersion())) { doomed = pvpv; break; } } if (doomed != null) { this.productVersionPackageVersions.remove(doomed); } return doomed; } // Object Overridden Methods -------------------------------------------- @Override public String toString() { StringBuffer toString = new StringBuffer(); toString.append("PackageVersion["); toString.append("package=").append(generalPackage).append(","); toString.append("version=").append(version).append(","); toString.append("architecture=").append(architecture); toString.append("]"); return toString.toString(); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null) { return false; } if (!(o instanceof PackageVersion)) { return false; } PackageVersion that = (PackageVersion) o; if ((architecture != null) ? (!architecture.equals(that.architecture)) : (that.architecture != null)) { return false; } if ((generalPackage != null) ? (!generalPackage.equals(that.generalPackage)) : (that.generalPackage != null)) { return false; } if ((version != null) ? (!version.equals(that.version)) : (that.version != null)) { return false; } return true; } @Override public int hashCode() { int result; result = ((generalPackage != null) ? generalPackage.hashCode() : 0); result = (31 * result) + ((version != null) ? version.hashCode() : 0); result = (31 * result) + ((architecture != null) ? architecture.hashCode() : 0); return result; } }