/**
* 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);
}
}