/**
* Copyright (C) 2008 - Abiquo Holdings S.L. All rights reserved.
*
* Please see /opt/abiquo/tomcat/webapps/legal/ on Abiquo server
* or contact contact@abiquo.com for licensing information.
*/
package com.abiquo.server.core.appslibrary;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.persistence.EntityManager;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.sql.JoinFragment;
import com.abiquo.model.enumerator.ConversionState;
import com.abiquo.model.enumerator.DiskFormatType;
import com.abiquo.model.enumerator.HypervisorType;
import com.abiquo.model.enumerator.OSType;
import com.abiquo.model.enumerator.StatefulInclusion;
import com.abiquo.model.enumerator.VolumeState;
import com.abiquo.server.core.cloud.VirtualAppliance;
import com.abiquo.server.core.cloud.VirtualDatacenter;
import com.abiquo.server.core.cloud.VirtualMachine;
import com.abiquo.server.core.common.persistence.DefaultDAOBase;
import com.abiquo.server.core.enterprise.Enterprise;
import com.abiquo.server.core.enterprise.User;
import com.abiquo.server.core.infrastructure.Repository;
import com.abiquo.server.core.infrastructure.management.Rasd;
import com.abiquo.server.core.infrastructure.management.RasdManagement;
import com.abiquo.server.core.infrastructure.storage.StoragePool;
import com.abiquo.server.core.infrastructure.storage.Tier;
import com.abiquo.server.core.infrastructure.storage.VolumeManagement;
import com.abiquo.server.core.pricing.CostCode;
import com.abiquo.server.core.util.FilterOptions;
import com.abiquo.server.core.util.PagedList;
import com.softwarementors.bzngine.entities.PersistentEntity;
@org.springframework.stereotype.Repository("jpaVirtualMachineTemplateDAO")
/* package */class VirtualMachineTemplateDAO extends
DefaultDAOBase<Integer, VirtualMachineTemplate>
{
public VirtualMachineTemplateDAO()
{
super(VirtualMachineTemplate.class);
}
public VirtualMachineTemplateDAO(final EntityManager entityManager)
{
super(VirtualMachineTemplate.class, entityManager);
}
public List<VirtualMachineTemplate> findByEnterprise(final Enterprise enterprise)
{
Criteria criteria = createCriteria(sameEnterpriseOrShared(enterprise));
criteria.addOrder(Order.asc(VirtualMachine.NAME_PROPERTY));
return getResultList(criteria);
}
public List<VirtualMachineTemplate> findInPrecreatedVirtualMachineTemplate(final String ovfId,
final Enterprise enterprise,
final com.abiquo.server.core.infrastructure.Repository repository)
{
Criteria criteria =
createCriteria(Restrictions.and(sameEnterpriseOrSharedInRepo(enterprise, repository),//
Restrictions.eq(VirtualMachineTemplate.OVFID_PROPERTY, ovfId)));
criteria.addOrder(Order.asc(VirtualMachine.NAME_PROPERTY));
return getResultList(criteria);
}
public List<VirtualMachineTemplate> findByEnterpriseAndRepository(final Enterprise enterprise,
final com.abiquo.server.core.infrastructure.Repository repository)
{
Criteria criteria = createCriteria(sameEnterpriseOrSharedInRepo(enterprise, repository));
criteria.addOrder(Order.asc(VirtualMachine.NAME_PROPERTY));
return getResultList(criteria);
}
/**
* @param ostype, optionally filter by operating system (null for any filter)
* @param is64b, optionally filter by x64 architecture. It requires ''ostype'' param set to null
* (null for any filter)
* @param filters The pagination and search filters
*/
@SuppressWarnings("unchecked")
public List<VirtualMachineTemplate> findBy(final Enterprise enterprise,
final com.abiquo.server.core.infrastructure.Repository repository, final Category category,
final HypervisorType hypervisor, final OSType ostype, final Boolean is64b,
final boolean imported, final FilterOptions filters)
{
Criteria criteria =
createFindTemplateCriteria(enterprise, repository, category, hypervisor, ostype, is64b,
imported, filters);
// As we added a distinct as a result transformer in the criteria we need to get the count
// result applying this distinct to match the results
Integer size = count(criteria, PersistentEntity.ID_PROPERTY).intValue();
// Rebuild the criteria since the count modified it
criteria =
createFindTemplateCriteria(enterprise, repository, category, hypervisor, ostype, is64b,
imported, filters);
// FIXME SCG: I promise to look for a best solution.
// Note that Projections.groupProperty() returns a list of single properties (and not
// entities), so isn't the solution.
criteria.add(Restrictions.sqlRestriction("1=1 group by this_."
+ VirtualMachineTemplate.ID_COLUMN));
if (filters.getLimit() == 0)
{
criteria.setFirstResult(0);
criteria.setMaxResults(size);
}
else
{
criteria.setFirstResult(filters.getStartwith());
criteria.setMaxResults(filters.getLimit());
}
PagedList<VirtualMachineTemplate> templates =
new PagedList<VirtualMachineTemplate>(criteria.list());
templates.setTotalResults(size);
templates.setPageSize(filters.getLimit() > size ? size : filters.getLimit());
templates.setCurrentElement(filters.getStartwith());
return templates;
}
public List<VirtualMachineTemplate> findBy(final Category category)
{
Criteria criteria = createCriteria(sameCategory(category));
criteria.addOrder(Order.asc(VirtualMachineTemplate.NAME_PROPERTY));
List<VirtualMachineTemplate> result = getResultList(criteria);
return result;
}
public List<VirtualMachineTemplate> findByCostCode(final CostCode costCode)
{
Criteria criteria = createCriteria(sameCostCode(costCode));
List<VirtualMachineTemplate> result = getResultList(criteria);
return result;
}
private Criterion importedVirtualMachineTemplate(final Enterprise enterprise)
{
return Restrictions.and(sameEnterprise(enterprise), repositoryNull());
}
/** Virtual Machine Template compatible or some conversion compatible. */
private Criterion compatibleOrConversions(final HypervisorType hypervisorType,
final Criteria criteria)
{
return Restrictions.or(compatible(Arrays.asList(hypervisorType.compatibilityTable)), //
compatibleConversions(Arrays.asList(hypervisorType.compatibilityTable), criteria));
}
/** Virtual Machine Template is compatible. */
private Criterion compatible(final List<DiskFormatType> types)
{
return Restrictions.in(VirtualMachineTemplate.DISKFORMAT_TYPE_PROPERTY, types);
}
/**
* If (finished) conversions check some compatible. Left join to {@link VirtualImageConversion}
*/
private Criterion compatibleConversions(final List<DiskFormatType> types,
final Criteria criteria)
{
criteria.createAlias(VirtualMachineTemplate.CONVERSIONS_PROPERTY, "conversions",
JoinFragment.LEFT_OUTER_JOIN);
Criterion finished =
Restrictions.eq("conversions." + VirtualImageConversion.STATE_PROPERTY,
ConversionState.FINISHED);
Criterion compatible =
Restrictions.in("conversions." + VirtualImageConversion.TARGET_TYPE_PROPERTY, types);
return Restrictions.and(finished, compatible);
}
/** ######### */
public VirtualMachineTemplate findByName(final String name)
{
return findUniqueByProperty(VirtualMachineTemplate.NAME_PROPERTY, name);
}
public VirtualMachineTemplate findByPath(final Enterprise enterprise,
final com.abiquo.server.core.infrastructure.Repository repository, final String path)
{
Criteria criteria =
createCriteria(sameEnterpriseOrSharedInRepo(enterprise, repository, path));
criteria.addOrder(Order.asc(VirtualMachine.NAME_PROPERTY));
return getSingleResult(criteria);
}
public boolean existWithSamePath(final Enterprise enterprise,
final com.abiquo.server.core.infrastructure.Repository repository, final String path)
{
Criteria criteria =
createCriteria(sameEnterpriseOrSharedInRepo(enterprise, repository, path));
criteria.addOrder(Order.asc(VirtualMachine.NAME_PROPERTY));
List<VirtualMachineTemplate> result = getResultList(criteria);
return CollectionUtils.isEmpty(result) ? false : true;
}
/**
* @param ostype, optionally filter by operating system (null for any filter)
* @param is64b, optionally filter by x64 architecture. It requires ''ostype'' param set to null
* (null for any filter)
*/
@SuppressWarnings("unchecked")
public List<VirtualMachineTemplate> findStatefulsByCategoryAndDatacenter(final User user,
final Enterprise enterprise, final Category category, final Repository repository,
final VirtualDatacenter vdc, final StatefulInclusion stateful, final OSType ostype,
final Boolean is64b, final FilterOptions filters)
{
Criteria crit =
createFindPersistentCriteria(user, enterprise, category, repository, vdc, stateful,
ostype, is64b, filters);
Integer size = count(crit).intValue();
// Recreate the criteria since the count modified it
crit =
createFindPersistentCriteria(user, enterprise, category, repository, vdc, stateful,
ostype, is64b, filters);
if (filters.getLimit() == 0)
{
crit.setFirstResult(0);
crit.setMaxResults(size);
}
else
{
crit.setFirstResult(filters.getStartwith());
crit.setMaxResults(filters.getLimit());
}
PagedList<VirtualMachineTemplate> templates =
new PagedList<VirtualMachineTemplate>(crit.list());
templates.setTotalResults(size);
templates.setPageSize(filters.getLimit() > size ? size : filters.getLimit());
templates.setCurrentElement(filters.getStartwith());
return templates;
}
/**
* @param ostype, optionally filter by operating system (null for any filter)
* @param is64b, optionally filter by x64 architecture. It requires ''ostype'' param set to null
* (null for any filter)
*/
@SuppressWarnings("unchecked")
public List<Integer> getPersistentIds(final User user, final Enterprise enterprise,
final Category category, final Repository repository, final StatefulInclusion stateful,
final OSType ostype, final Boolean is64b, final FilterOptions filters)
{
Criteria crit;
if (filters == null)
{
crit = criteriaWithStatefulNavigation(stateful);
crit.add(statefulVirtualMachineTemplate(stateful, crit));
if (category != null)
{
crit.add(sameCategory(category));
}
if (ostype != null)
{
crit.add(sameOSType(ostype));
}
else if (is64b != null)
{
crit.add(sameArch(is64b));
}
if (!StringUtils.isEmpty(user.getAvailableVirtualDatacenters()))
{
crit.add(checkAllowedVirtualDatacenter(user));
}
crit.add(sameStatefulRepository(repository));
crit.addOrder(Order.asc(VirtualMachineTemplate.NAME_PROPERTY));
}
else
{
crit =
createFindPersistentCriteria(user, enterprise, category, repository, null,
stateful, ostype, is64b, filters);
}
crit.setProjection(Projections.property(PersistentEntity.ID_PROPERTY));
return crit.list();
// return getResultList(crit);
}
public List<VirtualMachineTemplate> findByMaster(final VirtualMachineTemplate master)
{
Criteria criteria = createCriteria(sameMaster(master));
return getResultList(criteria);
}
@Override
public VirtualMachineTemplate findById(final Integer id)
{
return getEntityManager().find(VirtualMachineTemplate.class, id);
}
public boolean isMaster(final VirtualMachineTemplate vmtemplate)
{
Criteria criteria = createCriteria(sameMaster(vmtemplate));
return CollectionUtils.isEmpty(getResultList(criteria)) ? false : true;
}
private static Criterion sameCategory(final Category category)
{
return Restrictions.eq(VirtualMachineTemplate.CATEGORY_PROPERTY, category);
}
private static Criterion sameCostCode(final CostCode costCode)
{
return Restrictions.eq(VirtualMachineTemplate.COST_CODE_PROPERTY, costCode.getId());
}
public static Criterion sameOSType(final OSType ostype)
{
return Restrictions.eq(VirtualMachineTemplate.OS_TYPE_PROPERTY, ostype);
}
public static Criterion sameArch(final Boolean isArch64)
{
return Restrictions.in(VirtualMachineTemplate.OS_TYPE_PROPERTY, isArch64 ? OSType.arch64
: OSType.arch32);
}
private static Criterion sameEnterprise(final Enterprise enterprise)
{
return Restrictions.eq(VirtualMachineTemplate.ENTERPRISE_PROPERTY, enterprise);
}
private static Criterion sameRepositoryAndNotStatefull(
final com.abiquo.server.core.infrastructure.Repository repository)
{
// return Restrictions.and(Restrictions.eq(VirtualMachineTemplate.STATEFUL_PROPERTY, false),
// Restrictions.eq(VirtualMachineTemplate.REPOSITORY_PROPERTY, repository));
return Restrictions.eq(VirtualMachineTemplate.REPOSITORY_PROPERTY, repository);
}
private static Criterion repositoryNull()
{
return Restrictions.isNull(VirtualMachineTemplate.REPOSITORY_PROPERTY);
}
private static Criterion sharedVirtualMachineTemplate()
{
return Restrictions.eq(VirtualMachineTemplate.SHARED_PROPERTY, true);
}
private static Criterion statefulVirtualMachineTemplate(final StatefulInclusion stateful,
final Criteria criteria)
{
Criterion cri = Restrictions.eq(VirtualMachineTemplate.STATEFUL_PROPERTY, true);
switch (stateful)
{
case ALL:
/*
* NEW_PERSISTENT FEATURE: With this feature may exist "pre templates" created and
* IN_PROGRESS or FAILED, in these cases the templates won't have got a relation
* with volume
*/
// Restrictions.and(cri,
// Restrictions.isNotNull(VirtualMachineTemplate.VOLUME_PROPERTY));
return cri;
case USED:
// use function criteriaWithStatefulNavigation before
return Restrictions.and(cri,
Restrictions.eq("vl." + VolumeManagement.STATE_PROPERTY, VolumeState.ATTACHED));
case NOTUSED:
// use function criteriaWithStatefulNavigation before
return Restrictions.and(cri,
Restrictions.or(Restrictions.isNull("vl."
+ VolumeManagement.VIRTUAL_MACHINE_TEMPLATE_PROPERTY), Restrictions.and(
Restrictions.isNotNull("vl."
+ VolumeManagement.VIRTUAL_MACHINE_TEMPLATE_PROPERTY), Restrictions.eq(
"vl." + VolumeManagement.STATE_PROPERTY, VolumeState.DETACHED))));
}
return cri;
}
private static Criterion sameEnterpriseOrShared(final Enterprise enterprise)
{
return Restrictions.or(sameEnterprise(enterprise), sharedVirtualMachineTemplate());
}
private static Criterion sameEnterpriseOrSharedInRepo(final Enterprise enterprise,
final com.abiquo.server.core.infrastructure.Repository repository)
{
return Restrictions.and(sameRepositoryAndNotStatefull(repository),
Restrictions.or(sameEnterprise(enterprise), sharedVirtualMachineTemplate()));
}
private static Criterion sameEnterpriseOrSharedInRepo(final Enterprise enterprise,
final com.abiquo.server.core.infrastructure.Repository repository, final String path)
{
Criterion sameEnterpriseOrSharedInRepo =
Restrictions.and(sameRepositoryAndNotStatefull(repository),
Restrictions.or(sameEnterprise(enterprise), sharedVirtualMachineTemplate()));
return Restrictions.and(Restrictions.eq(VirtualMachineTemplate.PATH_PROPERTY, path),
sameEnterpriseOrSharedInRepo);
}
private static Criterion sameMaster(final VirtualMachineTemplate vmtemplate)
{
return Restrictions.eq(VirtualMachineTemplate.MASTER_PROPERTY, vmtemplate);
}
private static Criterion sameStatefulRepository(final Repository repository)
{
return Restrictions.and(Restrictions.isNotNull(VirtualMachineTemplate.MASTER_PROPERTY),
Restrictions.eq("ms." + VirtualMachineTemplate.REPOSITORY_PROPERTY, repository));
}
private static Criterion sameStatefulVirtualDatacenter(final VirtualDatacenter virtualDatacenter)
{
return Restrictions.eq("vl." + RasdManagement.VIRTUAL_DATACENTER_PROPERTY,
virtualDatacenter);
}
private Criteria criteriaWithStatefulNavigation(final StatefulInclusion stateful)
{
Criteria crit = createCriteria();
crit.createAlias(VirtualMachineTemplate.MASTER_PROPERTY, "ms");
switch (stateful)
{
case USED:
crit.createAlias(VirtualMachineTemplate.VOLUME_PROPERTY, "vl");
crit.createAlias("vl." + VolumeManagement.STORAGE_POOL_PROPERTY, "pool");
crit.createAlias("pool." + StoragePool.DEVICE_PROPERTY, "device");
crit.createAlias("pool." + StoragePool.TIER_PROPERTY, "tier");
crit.createAlias("vl." + RasdManagement.RASD_PROPERTY, "rasd");
crit.createAlias("vl." + RasdManagement.VIRTUAL_DATACENTER_PROPERTY, "vdc");
crit.createAlias("vl." + RasdManagement.VIRTUAL_APPLIANCE_PROPERTY, "vapp");
crit.createAlias("vl." + RasdManagement.VIRTUAL_MACHINE_PROPERTY, "vm");
break;
case NOTUSED:
case ALL:
crit.createAlias(VirtualMachineTemplate.VOLUME_PROPERTY, "vl",
JoinFragment.LEFT_OUTER_JOIN);
crit.createAlias("vl." + VolumeManagement.STORAGE_POOL_PROPERTY, "pool",
JoinFragment.LEFT_OUTER_JOIN);
crit.createAlias("pool." + StoragePool.DEVICE_PROPERTY, "device",
JoinFragment.LEFT_OUTER_JOIN);
crit.createAlias("pool." + StoragePool.TIER_PROPERTY, "tier",
JoinFragment.LEFT_OUTER_JOIN);
crit.createAlias("vl." + RasdManagement.RASD_PROPERTY, "rasd",
JoinFragment.LEFT_OUTER_JOIN);
crit.createAlias("vl." + RasdManagement.VIRTUAL_DATACENTER_PROPERTY, "vdc",
JoinFragment.LEFT_OUTER_JOIN);
crit.createAlias("vl." + RasdManagement.VIRTUAL_APPLIANCE_PROPERTY, "vapp",
JoinFragment.LEFT_OUTER_JOIN);
crit.createAlias("vl." + RasdManagement.VIRTUAL_MACHINE_PROPERTY, "vm",
JoinFragment.LEFT_OUTER_JOIN);
break;
}
return crit;
}
private Criteria createFindPersistentCriteria(final User user, final Enterprise enterprise,
final Category category, final Repository repository, final VirtualDatacenter vdc,
final StatefulInclusion stateful, final OSType ostype, final Boolean is64b,
final FilterOptions filters)
{
Criteria crit = criteriaWithStatefulNavigation(stateful);
crit.add(statefulVirtualMachineTemplate(stateful, crit));
crit.add(sameEnterprise(enterprise));
crit.add(sameStatefulRepository(repository));
if (category != null)
{
crit.add(sameCategory(category));
}
if (vdc != null)
{
crit.add(sameStatefulVirtualDatacenter(vdc));
}
if (!StringUtils.isEmpty(user.getAvailableVirtualDatacenters()))
{
crit.add(checkAllowedVirtualDatacenter(user));
}
if (ostype != null)
{
crit.add(sameOSType(ostype));
}
else if (is64b != null)
{
crit.add(sameArch(is64b));
}
// Search criterias
crit.add(filterBy(filters, VirtualMachineTemplate.NAME_PROPERTY, "ms."
+ VirtualMachineTemplate.NAME_PROPERTY, "vdc." + VirtualDatacenter.NAME_PROPERTY,
"vapp." + VirtualAppliance.NAME_PROPERTY, "vm." + VirtualMachine.NAME_PROPERTY, "tier."
+ Tier.NAME_PROPERTY));
// Set ordering
if (filters.getOrderBy() != null && !filters.getOrderBy().isEmpty())
{
String sortColumn =
PersistentTemplateOrder.valueOf(filters.getOrderBy().toUpperCase()).getHqlColumn();
crit.addOrder(filters.getAsc() == null || filters.getAsc().booleanValue() ? Order
.asc(sortColumn) : Order.desc(sortColumn));
}
return crit;
}
private Criteria createFindTemplateCriteria(final Enterprise enterprise,
final com.abiquo.server.core.infrastructure.Repository repository, final Category category,
final HypervisorType hypervisor, final OSType ostype, final Boolean is64b,
final boolean imported, final FilterOptions filters)
{
Criteria crit = null;
Criterion sameEnterpriseOrShared = sameEnterpriseOrSharedInRepo(enterprise, repository);
if (imported)
{
Criterion importedTemplate = importedVirtualMachineTemplate(enterprise);
crit = createCriteria(Restrictions.or(sameEnterpriseOrShared, importedTemplate));
}
else
{
crit = createCriteria(sameEnterpriseOrShared);
}
if (category != null)
{
crit.add(sameCategory(category));
}
if (hypervisor != null)
{
crit.add(compatibleOrConversions(hypervisor, crit));
}
if (ostype != null)
{
crit.add(sameOSType(ostype));
}
else if (is64b != null)
{
crit.add(sameArch(is64b));
}
// Search criterias
crit.add(filterBy(filters, VirtualMachineTemplate.NAME_PROPERTY));
// Set ordering
if (filters.getOrderBy() != null && !filters.getOrderBy().isEmpty())
{
crit.addOrder(filters.getAsc() == null || filters.getAsc().booleanValue() ? Order
.asc(VirtualMachineTemplate.NAME_PROPERTY) : Order
.desc(VirtualMachineTemplate.NAME_PROPERTY));
}
// The query may return duplicates. Add a distinct by id
crit.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
return crit;
}
private static enum PersistentTemplateOrder
{
ID(VirtualMachineTemplate.ID_PROPERTY), //
NAME(VirtualMachineTemplate.NAME_PROPERTY), //
MASTER("ms." + VirtualMachineTemplate.NAME_PROPERTY), //
VIRTUALDATACENTER("vdc." + VirtualDatacenter.NAME_PROPERTY), //
VIRTUALAPPLIANCE("vapp." + VirtualAppliance.NAME_PROPERTY), //
VIRTUALMACHINE("vm." + VirtualMachine.NAME_PROPERTY), //
TIER("tier." + Tier.NAME_PROPERTY), //
SIZE("rasd." + Rasd.LIMIT_PROPERTY);
private String hqlColumn;
private PersistentTemplateOrder(final String hqlColumn)
{
this.hqlColumn = hqlColumn;
}
public String getHqlColumn()
{
return hqlColumn;
}
}
private Criterion checkAllowedVirtualDatacenter(final User user)
{
List<Integer> allowedVdcs = new ArrayList<Integer>();
// Assume that user.getAvailableVirtualDatacenters() is empty or not has been checked
// previously, to add or not the restriction
for (String id : user.getAvailableVirtualDatacenters().split(","))
{
allowedVdcs.add(new Integer(id));
}
return Restrictions.in("vdc." + PersistentEntity.ID_PROPERTY, allowedVdcs);
}
}