/** * 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.dao; import java.text.MessageFormat; import java.util.List; import javax.persistence.TypedQuery; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.orm.RequiresSession; import org.apache.ambari.server.orm.entities.RepositoryVersionEntity; import org.apache.ambari.server.orm.entities.StackEntity; import org.apache.ambari.server.state.RepositoryType; import org.apache.ambari.server.state.StackId; import com.google.inject.Singleton; import com.google.inject.persist.Transactional; /** * DAO for repository versions. * */ @Singleton public class RepositoryVersionDAO extends CrudDAO<RepositoryVersionEntity, Long> { /** * Constructor. */ public RepositoryVersionDAO() { super(RepositoryVersionEntity.class); } /** * Creates entity. * * @param entity entity to create */ @Override @Transactional public void create(RepositoryVersionEntity entity){ super.create(entity); } /** * Retrieves repository version by name. * * @param displayName display name * @return null if there is no suitable repository version */ @RequiresSession public RepositoryVersionEntity findByDisplayName(String displayName) { // TODO, this assumes that the display name is unique, but neither the code nor the DB schema enforces this. final TypedQuery<RepositoryVersionEntity> query = entityManagerProvider.get().createNamedQuery("repositoryVersionByDisplayName", RepositoryVersionEntity.class); query.setParameter("displayname", displayName); return daoUtils.selectSingle(query); } /** * Retrieves repository version by stack. * * @param stackId * stackId * @param version * version * @return null if there is no suitable repository version */ @RequiresSession public RepositoryVersionEntity findByStackAndVersion(StackId stackId, String version) { return findByStackNameAndVersion(stackId.getStackName(), version); } /** * Retrieves repository version by stack. * * @param stackEntity Stack entity * @param version version * @return null if there is no suitable repository version */ @RequiresSession public RepositoryVersionEntity findByStackAndVersion(StackEntity stackEntity, String version) { return findByStackNameAndVersion(stackEntity.getStackName(), version); } /** * Retrieves repository version, which is unique in this stack. * * @param stackName Stack name such as HDP, HDPWIN, BIGTOP * @param version version * @return null if there is no suitable repository version */ @RequiresSession public RepositoryVersionEntity findByStackNameAndVersion(String stackName, String version) { // TODO, need to make a unique composite key in DB using the repo_version's stack_id and version. // Ideally, 1.0-1234 foo should be unique in all HDP stacks. // The composite key is slightly more relaxed since it would only prevent 2.3.0-1234 multiple times in the HDP 2.3 stack. // There's already business logic to prevent creating 2.3-1234 in the wrong stack such as HDP 2.2. final TypedQuery<RepositoryVersionEntity> query = entityManagerProvider.get().createNamedQuery("repositoryVersionByStackNameAndVersion", RepositoryVersionEntity.class); query.setParameter("stackName", stackName); query.setParameter("version", version); return daoUtils.selectSingle(query); } /** * Retrieves repository version by stack. * * @param stackId stack id * stack with major version (like HDP-2.2) * @return null if there is no suitable repository version */ @RequiresSession public List<RepositoryVersionEntity> findByStack(StackId stackId) { final TypedQuery<RepositoryVersionEntity> query = entityManagerProvider.get().createNamedQuery("repositoryVersionByStack", RepositoryVersionEntity.class); query.setParameter("stackName", stackId.getStackName()); query.setParameter("stackVersion", stackId.getStackVersion()); return daoUtils.selectList(query); } /** * Validates and creates an object. * The version must be unique within this stack name (e.g., HDP, HDPWIN, BIGTOP). * @param stackEntity Stack entity. * @param version Stack version, e.g., 2.2 or 2.2.0.1-885 * @param displayName Unique display name * @param operatingSystems JSON structure of repository URLs for each OS * @return Returns the object created if successful, and throws an exception otherwise. * @throws AmbariException */ public RepositoryVersionEntity create(StackEntity stackEntity, String version, String displayName, String operatingSystems) throws AmbariException { return create(stackEntity, version, displayName, operatingSystems, RepositoryType.STANDARD); } /** * Validates and creates an object. * The version must be unique within this stack name (e.g., HDP, HDPWIN, BIGTOP). * @param stackEntity Stack entity. * @param version Stack version, e.g., 2.2 or 2.2.0.1-885 * @param displayName Unique display name * @param operatingSystems JSON structure of repository URLs for each OS * @param type the repository type * @return Returns the object created if successful, and throws an exception otherwise. * @throws AmbariException */ @Transactional public RepositoryVersionEntity create(StackEntity stackEntity, String version, String displayName, String operatingSystems, RepositoryType type) throws AmbariException { if (stackEntity == null || version == null || version.isEmpty() || displayName == null || displayName.isEmpty()) { throw new AmbariException("At least one of the required properties is null or empty"); } RepositoryVersionEntity existingByDisplayName = findByDisplayName(displayName); if (existingByDisplayName != null) { throw new AmbariException("Repository version with display name '" + displayName + "' already exists"); } RepositoryVersionEntity existingVersionInStack = findByStackNameAndVersion(stackEntity.getStackName(), version); if (existingVersionInStack != null) { throw new AmbariException(MessageFormat.format("Repository Version for version {0} already exists, in stack {1}-{2}", version, existingVersionInStack.getStack().getStackName(), existingVersionInStack.getStack().getStackVersion())); } StackId stackId = new StackId(stackEntity.getStackName(), stackEntity.getStackVersion() ); if (!RepositoryVersionEntity.isVersionInStack(stackId, version)) { throw new AmbariException(MessageFormat.format("Version {0} needs to belong to stack {1}", version, stackEntity.getStackName() + "-" + stackEntity.getStackVersion())); } RepositoryVersionEntity newEntity = new RepositoryVersionEntity( stackEntity, version, displayName, operatingSystems); newEntity.setType(type); this.create(newEntity); return newEntity; } /** * Retrieves repository version when they are loaded by a version definition file * * @return a list of entities, or an empty list when there are none */ @RequiresSession public List<RepositoryVersionEntity> findAllDefinitions() { final TypedQuery<RepositoryVersionEntity> query = entityManagerProvider.get().createNamedQuery( "repositoryVersionsFromDefinition", RepositoryVersionEntity.class); return daoUtils.selectList(query); } }