| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.ambari.server.orm.entities; |
| |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Set; |
| |
| import javax.persistence.Basic; |
| import javax.persistence.CascadeType; |
| import javax.persistence.Column; |
| import javax.persistence.Entity; |
| import javax.persistence.EnumType; |
| import javax.persistence.Enumerated; |
| import javax.persistence.FetchType; |
| import javax.persistence.GeneratedValue; |
| import javax.persistence.GenerationType; |
| import javax.persistence.Id; |
| import javax.persistence.JoinColumn; |
| import javax.persistence.Lob; |
| import javax.persistence.ManyToOne; |
| import javax.persistence.NamedQueries; |
| import javax.persistence.NamedQuery; |
| import javax.persistence.OneToMany; |
| import javax.persistence.OneToOne; |
| import javax.persistence.PrePersist; |
| import javax.persistence.PreUpdate; |
| import javax.persistence.Table; |
| import javax.persistence.TableGenerator; |
| import javax.persistence.Transient; |
| import javax.persistence.UniqueConstraint; |
| |
| import org.apache.ambari.server.StaticallyInject; |
| import org.apache.ambari.server.state.RepositoryType; |
| import org.apache.ambari.server.state.StackId; |
| import org.apache.ambari.server.state.repository.Release; |
| import org.apache.ambari.server.state.repository.VersionDefinitionXml; |
| import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper; |
| import org.apache.commons.lang.StringUtils; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.google.inject.Inject; |
| import com.google.inject.Provider; |
| |
| @Entity |
| @Table(name = "repo_version", uniqueConstraints = { |
| @UniqueConstraint(columnNames = {"display_name"}), |
| @UniqueConstraint(columnNames = {"stack_id", "version"}) |
| }) |
| @TableGenerator(name = "repository_version_id_generator", |
| table = "ambari_sequences", |
| pkColumnName = "sequence_name", |
| valueColumnName = "sequence_value", |
| pkColumnValue = "repo_version_id_seq", |
| initialValue = 0 |
| ) |
| @NamedQueries({ |
| @NamedQuery(name = "repositoryVersionByDisplayName", query = "SELECT repoversion FROM RepositoryVersionEntity repoversion WHERE repoversion.displayName=:displayname"), |
| @NamedQuery(name = "repositoryVersionByStack", query = "SELECT repoversion FROM RepositoryVersionEntity repoversion WHERE repoversion.stack.stackName=:stackName AND repoversion.stack.stackVersion=:stackVersion"), |
| @NamedQuery(name = "repositoryVersionByStackNameAndVersion", query = "SELECT repoversion FROM RepositoryVersionEntity repoversion WHERE repoversion.stack.stackName=:stackName AND repoversion.version=:version"), |
| @NamedQuery(name = "repositoryVersionsFromDefinition", query = "SELECT repoversion FROM RepositoryVersionEntity repoversion WHERE repoversion.versionXsd IS NOT NULL") |
| }) |
| @StaticallyInject |
| public class RepositoryVersionEntity { |
| private static Logger LOG = LoggerFactory.getLogger(RepositoryVersionEntity.class); |
| |
| @Inject |
| private static Provider<RepositoryVersionHelper> repositoryVersionHelperProvider; |
| |
| @Id |
| @Column(name = "repo_version_id") |
| @GeneratedValue(strategy = GenerationType.TABLE, generator = "repository_version_id_generator") |
| private Long id; |
| |
| /** |
| * Unidirectional one-to-one association to {@link StackEntity} |
| */ |
| @OneToOne |
| @JoinColumn(name = "stack_id", unique = false, nullable = false, insertable = true, updatable = true) |
| private StackEntity stack; |
| |
| @Column(name = "version") |
| private String version; |
| |
| @Column(name = "display_name") |
| private String displayName; |
| |
| @Lob |
| @Column(name = "repositories") |
| private String operatingSystems; |
| |
| |
| @OneToMany(cascade = CascadeType.REMOVE, mappedBy = "repositoryVersion") |
| private Set<ClusterVersionEntity> clusterVersionEntities; |
| |
| @OneToMany(cascade = CascadeType.REMOVE, mappedBy = "repositoryVersion") |
| private Set<HostVersionEntity> hostVersionEntities; |
| |
| @Column(name = "repo_type", nullable = false, insertable = true, updatable = true) |
| @Enumerated(value = EnumType.STRING) |
| private RepositoryType type = RepositoryType.STANDARD; |
| |
| @Basic(fetch=FetchType.LAZY) |
| @Lob |
| @Column(name="version_xml", insertable = true, updatable = true) |
| private String versionXml; |
| |
| @Transient |
| private VersionDefinitionXml versionDefinition = null; |
| |
| @Column(name="version_url", nullable=true, insertable=true, updatable=true) |
| private String versionUrl; |
| |
| @Column(name="version_xsd", insertable = true, updatable = true) |
| private String versionXsd; |
| |
| @ManyToOne |
| @JoinColumn(name = "parent_id") |
| private RepositoryVersionEntity parent; |
| |
| @OneToMany(mappedBy = "parent") |
| private List<RepositoryVersionEntity> children; |
| |
| // ----- RepositoryVersionEntity ------------------------------------------------------- |
| |
| public RepositoryVersionEntity() { |
| |
| } |
| |
| public RepositoryVersionEntity(StackEntity stack, String version, |
| String displayName, String operatingSystems) { |
| this.stack = stack; |
| this.version = version; |
| this.displayName = displayName; |
| this.operatingSystems = operatingSystems; |
| } |
| |
| @PreUpdate |
| @PrePersist |
| public void removePrefixFromVersion() { |
| String stackName = stack.getStackName(); |
| if (version.startsWith(stackName)) { |
| version = version.substring(stackName.length() + 1); |
| } |
| } |
| /** |
| * Update one-to-many relation without rebuilding the whole entity |
| * @param entity many-to-one entity |
| */ |
| public void updateClusterVersionEntityRelation(ClusterVersionEntity entity){ |
| clusterVersionEntities.add(entity); |
| } |
| |
| /** |
| * Update one-to-many relation without rebuilding the whole entity |
| * @param entity many-to-one entity |
| */ |
| public void updateHostVersionEntityRelation(HostVersionEntity entity){ |
| hostVersionEntities.add(entity); |
| } |
| |
| public Long getId() { |
| return id; |
| } |
| |
| public void setId(Long id) { |
| this.id = id; |
| } |
| |
| /** |
| * Gets the repository version's stack. |
| * |
| * @return the stack. |
| */ |
| public StackEntity getStack() { |
| return stack; |
| } |
| |
| /** |
| * Sets the repository version's stack. |
| * |
| * @param stack |
| * the stack to set for the repo version (not {@code null}). |
| */ |
| public void setStack(StackEntity stack) { |
| this.stack = stack; |
| } |
| |
| public String getVersion() { |
| return version; |
| } |
| |
| public void setVersion(String version) { |
| this.version = version; |
| } |
| |
| public String getDisplayName() { |
| return displayName; |
| } |
| |
| public void setDisplayName(String displayName) { |
| this.displayName = displayName; |
| } |
| |
| /** |
| * @param stackId the stack id for the version |
| * @param release the XML release instance |
| */ |
| public void setDisplayName(StackId stackId, Release release) { |
| if (StringUtils.isNotBlank(release.display)) { |
| displayName = release.display; |
| } else { |
| displayName = stackId.getStackName() + "-" + release.getFullVersion(); |
| } |
| } |
| |
| |
| public String getOperatingSystemsJson() { |
| return operatingSystems; |
| } |
| |
| public void setOperatingSystems(String repositories) { |
| operatingSystems = repositories; |
| } |
| |
| /** |
| * Getter which hides json nature of operating systems and returns them as entities. |
| * |
| * @return empty list if stored json is invalid |
| */ |
| public List<OperatingSystemEntity> getOperatingSystems() { |
| if (StringUtils.isNotBlank(operatingSystems)) { |
| try { |
| return repositoryVersionHelperProvider.get().parseOperatingSystems(operatingSystems); |
| } catch (Exception ex) { |
| String msg = String.format("Failed to parse repository from OS/Repo information in the database: %s. Required fields: repo_name, repo_id, base_url", operatingSystems); |
| LOG.error(msg, ex); |
| } |
| } |
| return Collections.emptyList(); |
| } |
| |
| public String getStackName() { |
| return getStackId().getStackName(); |
| } |
| |
| public String getStackVersion() { |
| return getStackId().getStackVersion(); |
| } |
| |
| public StackId getStackId() { |
| if (null == stack) { |
| return null; |
| } |
| |
| return new StackId(stack.getStackName(), stack.getStackVersion()); |
| } |
| |
| /** |
| * @return the type |
| */ |
| public RepositoryType getType() { |
| return type; |
| } |
| |
| /** |
| * @param type the repo type |
| */ |
| public void setType(RepositoryType type) { |
| this.type = type; |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) { |
| return true; |
| } |
| if (o == null || getClass() != o.getClass()) { |
| return false; |
| } |
| |
| RepositoryVersionEntity that = (RepositoryVersionEntity) o; |
| |
| if (id != null ? !id.equals(that.id) : that.id != null) { |
| return false; |
| } |
| if (stack != null ? !stack.equals(that.stack) : that.stack != null) { |
| return false; |
| } |
| if (version != null ? !version.equals(that.version) : that.version != null) { |
| return false; |
| } |
| if (displayName != null ? !displayName.equals(that.displayName) : that.displayName != null) { |
| return false; |
| } |
| |
| if (operatingSystems != null ? !operatingSystems.equals(that.operatingSystems) : that.operatingSystems != null) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * @return the XML that is the basis for the version |
| */ |
| public String getVersionXml() { |
| return versionXml; |
| } |
| |
| /** |
| * @param xml the XML that is the basis for the version |
| */ |
| public void setVersionXml(String xml) { |
| versionXml = xml; |
| } |
| |
| /** |
| * @return The url used for the version. Optional in case the XML was loaded via blob. |
| */ |
| public String getVersionUrl() { |
| return versionUrl; |
| } |
| |
| /** |
| * @param url the url used to load the XML. |
| */ |
| public void setVersionUrl(String url) { |
| versionUrl = url; |
| } |
| |
| /** |
| * @return the XSD name extracted from the XML. |
| */ |
| public String getVersionXsd() { |
| return versionXsd; |
| } |
| |
| /** |
| * @param xsdLocation the XSD name extracted from XML. |
| */ |
| public void setVersionXsd(String xsdLocation) { |
| versionXsd = xsdLocation; |
| } |
| |
| /** |
| * Parse the version XML into its object representation. This causes the XML to be lazy-loaded |
| * from storage, and will only be parsed once per request. |
| * @return {@code null} if the XSD (from the XML) is not available. |
| * @throws Exception |
| */ |
| public VersionDefinitionXml getRepositoryXml() throws Exception { |
| if (null == versionXsd) { |
| return null; |
| } |
| |
| if (null == versionDefinition) { |
| versionDefinition = VersionDefinitionXml.load(getVersionXml()); |
| } |
| |
| return versionDefinition; |
| } |
| |
| @Override |
| public int hashCode() { |
| int result = id != null ? id.hashCode() : 0; |
| result = 31 * result + (stack != null ? stack.hashCode() : 0); |
| result = 31 * result + (version != null ? version.hashCode() : 0); |
| result = 31 * result + (displayName != null ? displayName.hashCode() : 0); |
| result = 31 * result + (operatingSystems != null ? operatingSystems.hashCode() : 0); |
| return result; |
| } |
| |
| /** |
| * Determine if the version belongs to the stack. |
| * @param stackId Stack, such as HDP-2.3 |
| * @param version Version number, such as 2.3.0.0, or 2.3.0.0-1234 |
| * @return Return true if the version starts with the digits of the stack. |
| */ |
| public static boolean isVersionInStack(StackId stackId, String version) { |
| if (null != version && !StringUtils.isBlank(version)) { |
| String stackName = stackId.getStackName(); |
| if (version.startsWith(stackName + "-")) { |
| version = version.substring(stackName.length() + 1); |
| } |
| |
| String leading = stackId.getStackVersion(); // E.g, 2.3 |
| // In some cases during unit tests, the leading can contain 3 digits, so only the major number (first two parts) are needed. |
| String[] leadingParts = leading.split("\\."); |
| if (null != leadingParts && leadingParts.length > 2) { |
| leading = leadingParts[0] + "." + leadingParts[1]; |
| } |
| return version.startsWith(leading); |
| } |
| return false; |
| } |
| |
| /** |
| * @param entity parent entity |
| */ |
| public void setParent(RepositoryVersionEntity entity) { |
| parent = entity; |
| parent.children.add(this); |
| } |
| |
| /** |
| * @return the repositories that are denoted children |
| */ |
| public List<RepositoryVersionEntity> getChildren() { |
| return children; |
| } |
| |
| /** |
| * @return the parentId, or {@code null} if the entity is already a parent |
| */ |
| public Long getParentId() { |
| return null == parent ? null : parent.getId(); |
| } |
| |
| } |