Java tutorial
/* * Copyright 2015 herd contributors * * Licensed 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.finra.herd.dao.impl; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.persistence.Tuple; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.From; import javax.persistence.criteria.Join; import javax.persistence.criteria.Order; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import javax.persistence.criteria.Subquery; import javax.persistence.metamodel.SingularAttribute; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Repository; import org.springframework.util.CollectionUtils; import org.finra.herd.dao.StorageUnitDao; import org.finra.herd.model.api.xml.BusinessObjectDataKey; import org.finra.herd.model.api.xml.BusinessObjectDataStorageUnitKey; import org.finra.herd.model.api.xml.BusinessObjectFormatKey; import org.finra.herd.model.dto.StorageUnitAvailabilityDto; import org.finra.herd.model.jpa.BusinessObjectDataEntity; import org.finra.herd.model.jpa.BusinessObjectDataEntity_; import org.finra.herd.model.jpa.BusinessObjectDataStatusEntity; import org.finra.herd.model.jpa.BusinessObjectDataStatusEntity_; import org.finra.herd.model.jpa.BusinessObjectDefinitionEntity; import org.finra.herd.model.jpa.BusinessObjectDefinitionEntity_; import org.finra.herd.model.jpa.BusinessObjectFormatEntity; import org.finra.herd.model.jpa.BusinessObjectFormatEntity_; import org.finra.herd.model.jpa.FileTypeEntity; import org.finra.herd.model.jpa.FileTypeEntity_; import org.finra.herd.model.jpa.NamespaceEntity; import org.finra.herd.model.jpa.NamespaceEntity_; import org.finra.herd.model.jpa.StorageEntity; import org.finra.herd.model.jpa.StorageEntity_; import org.finra.herd.model.jpa.StoragePlatformEntity; import org.finra.herd.model.jpa.StoragePlatformEntity_; import org.finra.herd.model.jpa.StorageUnitEntity; import org.finra.herd.model.jpa.StorageUnitEntity_; import org.finra.herd.model.jpa.StorageUnitStatusEntity; import org.finra.herd.model.jpa.StorageUnitStatusEntity_; @Repository public class StorageUnitDaoImpl extends AbstractHerdDao implements StorageUnitDao { @Override public List<StorageUnitEntity> getLatestVersionStorageUnitsByStoragePlatformAndFileType(String storagePlatform, String businessObjectFormatFileType) { // Create the criteria builder and the criteria. CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<StorageUnitEntity> criteria = builder.createQuery(StorageUnitEntity.class); // The criteria root is the storage unit. Root<StorageUnitEntity> storageUnitEntityRoot = criteria.from(StorageUnitEntity.class); // Join to the other tables we can filter on. Join<StorageUnitEntity, StorageEntity> storageEntityJoin = storageUnitEntityRoot .join(StorageUnitEntity_.storage); Join<StorageEntity, StoragePlatformEntity> storagePlatformEntityJoin = storageEntityJoin .join(StorageEntity_.storagePlatform); Join<StorageUnitEntity, BusinessObjectDataEntity> businessObjectDataEntityJoin = storageUnitEntityRoot .join(StorageUnitEntity_.businessObjectData); Join<BusinessObjectDataEntity, BusinessObjectFormatEntity> businessObjectFormatEntityJoin = businessObjectDataEntityJoin .join(BusinessObjectDataEntity_.businessObjectFormat); Join<BusinessObjectFormatEntity, FileTypeEntity> fileTypeEntityJoin = businessObjectFormatEntityJoin .join(BusinessObjectFormatEntity_.fileType); // Create the standard restrictions (i.e. the standard where clauses). List<Predicate> predicates = new ArrayList<>(); predicates.add(builder.equal(builder.upper(storagePlatformEntityJoin.get(StoragePlatformEntity_.name)), storagePlatform.toUpperCase())); predicates.add(builder.equal(builder.upper(fileTypeEntityJoin.get(FileTypeEntity_.code)), businessObjectFormatFileType.toUpperCase())); predicates .add(builder.isTrue(businessObjectFormatEntityJoin.get(BusinessObjectFormatEntity_.latestVersion))); predicates.add(builder.isTrue(businessObjectDataEntityJoin.get(BusinessObjectDataEntity_.latestVersion))); // Order by storage unit created on timestamp. Order orderBy = builder.asc(storageUnitEntityRoot.get(StorageUnitEntity_.createdOn)); // Add the clauses for the query. criteria.select(storageUnitEntityRoot) .where(builder.and(predicates.toArray(new Predicate[predicates.size()]))).orderBy(orderBy); // Execute the query and return the results. return entityManager.createQuery(criteria).getResultList(); } @Override public List<StorageUnitEntity> getS3StorageUnitsToCleanup(int maxResult) { // Create the criteria builder and the criteria. CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<StorageUnitEntity> criteria = builder.createQuery(StorageUnitEntity.class); // The criteria root is the storage unit. Root<StorageUnitEntity> storageUnitEntityRoot = criteria.from(StorageUnitEntity.class); // Join to the other tables we can filter on. Join<StorageUnitEntity, StorageEntity> storageEntityJoin = storageUnitEntityRoot .join(StorageUnitEntity_.storage); Join<StorageEntity, StoragePlatformEntity> storagePlatformEntityJoin = storageEntityJoin .join(StorageEntity_.storagePlatform); Join<StorageUnitEntity, StorageUnitStatusEntity> storageUnitStatusEntityJoin = storageUnitEntityRoot .join(StorageUnitEntity_.status); Join<StorageUnitEntity, BusinessObjectDataEntity> businessObjectDataEntityJoin = storageUnitEntityRoot .join(StorageUnitEntity_.businessObjectData); Join<BusinessObjectDataEntity, BusinessObjectDataStatusEntity> businessObjectDataStatusEntity = businessObjectDataEntityJoin .join(BusinessObjectDataEntity_.status); // Get the current time. Timestamp currentTime = new Timestamp(System.currentTimeMillis()); // Create the standard restrictions (i.e. the standard where clauses). // Restrictions include: // - Storage platform is set to S3 storage // - Storage unit status is DISABLED // - Associated BData has a DELETED status // - Final destroy on timestamp < current time List<Predicate> predicates = new ArrayList<>(); predicates.add(builder.equal(storagePlatformEntityJoin.get(StoragePlatformEntity_.name), StoragePlatformEntity.S3)); predicates.add(builder.equal(storageUnitStatusEntityJoin.get(StorageUnitStatusEntity_.code), StorageUnitStatusEntity.DISABLED)); predicates.add(builder.equal(businessObjectDataStatusEntity.get(BusinessObjectDataStatusEntity_.code), BusinessObjectDataStatusEntity.DELETED)); predicates.add(builder.lessThan(storageUnitEntityRoot.get(StorageUnitEntity_.finalDestroyOn), currentTime)); // Order the results. Order orderBy = builder.asc(storageUnitEntityRoot.get(StorageUnitEntity_.finalDestroyOn)); // Add the clauses for the query. criteria.select(storageUnitEntityRoot) .where(builder.and(predicates.toArray(new Predicate[predicates.size()]))).orderBy(orderBy); // Execute the query and return the results. return entityManager.createQuery(criteria).setMaxResults(maxResult).getResultList(); } @Override public List<StorageUnitEntity> getS3StorageUnitsToExpire(int maxResult) { // Create the criteria builder and the criteria. CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<StorageUnitEntity> criteria = builder.createQuery(StorageUnitEntity.class); // The criteria root is the storage unit. Root<StorageUnitEntity> storageUnitEntityRoot = criteria.from(StorageUnitEntity.class); // Join to the other tables we can filter on. Join<StorageUnitEntity, StorageEntity> storageEntityJoin = storageUnitEntityRoot .join(StorageUnitEntity_.storage); Join<StorageEntity, StoragePlatformEntity> storagePlatformEntityJoin = storageEntityJoin .join(StorageEntity_.storagePlatform); Join<StorageUnitEntity, StorageUnitStatusEntity> storageUnitStatusEntityJoin = storageUnitEntityRoot .join(StorageUnitEntity_.status); // Get the current time. Timestamp currentTime = new Timestamp(System.currentTimeMillis()); // Create the standard restrictions (i.e. the standard where clauses). List<Predicate> predicates = new ArrayList<>(); predicates.add(builder.equal(storagePlatformEntityJoin.get(StoragePlatformEntity_.name), StoragePlatformEntity.S3)); predicates.add(builder.equal(storageUnitStatusEntityJoin.get(StorageUnitStatusEntity_.code), StorageUnitStatusEntity.RESTORED)); predicates.add( builder.lessThan(storageUnitEntityRoot.get(StorageUnitEntity_.restoreExpirationOn), currentTime)); // Order the results. Order orderBy = builder.asc(storageUnitEntityRoot.get(StorageUnitEntity_.restoreExpirationOn)); // Add the clauses for the query. criteria.select(storageUnitEntityRoot) .where(builder.and(predicates.toArray(new Predicate[predicates.size()]))).orderBy(orderBy); // Execute the query and return the results. return entityManager.createQuery(criteria).setMaxResults(maxResult).getResultList(); } @Override public List<StorageUnitEntity> getS3StorageUnitsToRestore(int maxResult) { // Create the criteria builder and the criteria. CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<StorageUnitEntity> criteria = builder.createQuery(StorageUnitEntity.class); // The criteria root is the storage unit. Root<StorageUnitEntity> storageUnitEntityRoot = criteria.from(StorageUnitEntity.class); // Join to the other tables we can filter on. Join<StorageUnitEntity, StorageEntity> storageEntityJoin = storageUnitEntityRoot .join(StorageUnitEntity_.storage); Join<StorageEntity, StoragePlatformEntity> storagePlatformEntityJoin = storageEntityJoin .join(StorageEntity_.storagePlatform); Join<StorageUnitEntity, StorageUnitStatusEntity> storageUnitStatusEntityJoin = storageUnitEntityRoot .join(StorageUnitEntity_.status); // Create the standard restrictions (i.e. the standard where clauses). List<Predicate> predicates = new ArrayList<>(); predicates.add(builder.equal(storagePlatformEntityJoin.get(StoragePlatformEntity_.name), StoragePlatformEntity.S3)); predicates.add(builder.equal(storageUnitStatusEntityJoin.get(StorageUnitStatusEntity_.code), StorageUnitStatusEntity.RESTORING)); // Order the results by storage unit updated on timestamp. Order orderBy = builder.asc(storageUnitEntityRoot.get(StorageUnitEntity_.updatedOn)); // Add the clauses for the query. criteria.select(storageUnitEntityRoot) .where(builder.and(predicates.toArray(new Predicate[predicates.size()]))).orderBy(orderBy); // Execute the query and return the results. return entityManager.createQuery(criteria).setMaxResults(maxResult).getResultList(); } @Override public StorageUnitEntity getStorageUnitByBusinessObjectDataAndStorage( BusinessObjectDataEntity businessObjectDataEntity, StorageEntity storageEntity) { // Create the criteria builder and the criteria. CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<StorageUnitEntity> criteria = builder.createQuery(StorageUnitEntity.class); // The criteria root is the storage unit. Root<StorageUnitEntity> storageUnitEntityRoot = criteria.from(StorageUnitEntity.class); // Create the standard restrictions (i.e. the standard where clauses). List<Predicate> predicates = new ArrayList<>(); predicates.add(builder.equal(storageUnitEntityRoot.get(StorageUnitEntity_.businessObjectData), businessObjectDataEntity)); predicates.add( builder.equal(storageUnitEntityRoot.get(StorageUnitEntity_.storageName), storageEntity.getName())); // Add the clauses for the query. criteria.select(storageUnitEntityRoot) .where(builder.and(predicates.toArray(new Predicate[predicates.size()]))); // Execute the query. List<StorageUnitEntity> resultList = entityManager.createQuery(criteria).getResultList(); // Return single result or null. return resultList.size() >= 1 ? resultList.get(0) : null; } @Override public StorageUnitEntity getStorageUnitByBusinessObjectDataAndStorageName( BusinessObjectDataEntity businessObjectDataEntity, String storageName) { CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<StorageUnitEntity> criteria = builder.createQuery(StorageUnitEntity.class); Root<StorageUnitEntity> storageUnitEntity = criteria.from(StorageUnitEntity.class); // join storage unit to storage to retrieve name Join<StorageUnitEntity, StorageEntity> storageEntity = storageUnitEntity.join(StorageUnitEntity_.storage); // where business object data equals Predicate businessObjectDataRestriction = builder .equal(storageUnitEntity.get(StorageUnitEntity_.businessObjectData), businessObjectDataEntity); // where storage name equals, ignoring case Predicate storageNameRestriction = builder.equal(builder.upper(storageEntity.get(StorageEntity_.name)), storageName.toUpperCase()); criteria.select(storageUnitEntity) .where(builder.and(businessObjectDataRestriction, storageNameRestriction)); List<StorageUnitEntity> resultList = entityManager.createQuery(criteria).getResultList(); // return single result or null return resultList.size() >= 1 ? resultList.get(0) : null; } @Override public StorageUnitEntity getStorageUnitByKey( BusinessObjectDataStorageUnitKey businessObjectDataStorageUnitKey) { // Create the criteria builder and the criteria. CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<StorageUnitEntity> criteria = builder.createQuery(StorageUnitEntity.class); // The criteria root is the storage unit. Root<StorageUnitEntity> storageUnitEntityRoot = criteria.from(StorageUnitEntity.class); // Join to the other tables we can filter on. Join<StorageUnitEntity, BusinessObjectDataEntity> businessObjectDataEntityJoin = storageUnitEntityRoot .join(StorageUnitEntity_.businessObjectData); Join<BusinessObjectDataEntity, BusinessObjectFormatEntity> businessObjectFormatEntityJoin = businessObjectDataEntityJoin .join(BusinessObjectDataEntity_.businessObjectFormat); Join<BusinessObjectFormatEntity, FileTypeEntity> fileTypeEntityJoin = businessObjectFormatEntityJoin .join(BusinessObjectFormatEntity_.fileType); Join<BusinessObjectFormatEntity, BusinessObjectDefinitionEntity> businessObjectDefinitionEntityJoin = businessObjectFormatEntityJoin .join(BusinessObjectFormatEntity_.businessObjectDefinition); Join<BusinessObjectDefinitionEntity, NamespaceEntity> namespaceEntityJoin = businessObjectDefinitionEntityJoin .join(BusinessObjectDefinitionEntity_.namespace); Join<StorageUnitEntity, StorageEntity> storageEntityJoin = storageUnitEntityRoot .join(StorageUnitEntity_.storage); // Create the standard restrictions (i.e. the standard where clauses). List<Predicate> predicates = new ArrayList<>(); predicates.add(builder.equal(builder.upper(namespaceEntityJoin.get(NamespaceEntity_.code)), businessObjectDataStorageUnitKey.getNamespace().toUpperCase())); predicates.add(builder.equal( builder.upper(businessObjectDefinitionEntityJoin.get(BusinessObjectDefinitionEntity_.name)), businessObjectDataStorageUnitKey.getBusinessObjectDefinitionName().toUpperCase())); predicates.add(builder.equal( builder.upper(businessObjectDefinitionEntityJoin.get(BusinessObjectDefinitionEntity_.name)), businessObjectDataStorageUnitKey.getBusinessObjectDefinitionName().toUpperCase())); predicates.add( builder.equal(builder.upper(businessObjectFormatEntityJoin.get(BusinessObjectFormatEntity_.usage)), businessObjectDataStorageUnitKey.getBusinessObjectFormatUsage().toUpperCase())); predicates.add(builder.equal(builder.upper(fileTypeEntityJoin.get(FileTypeEntity_.code)), businessObjectDataStorageUnitKey.getBusinessObjectFormatFileType().toUpperCase())); predicates.add(builder.equal( businessObjectFormatEntityJoin.get(BusinessObjectFormatEntity_.businessObjectFormatVersion), businessObjectDataStorageUnitKey.getBusinessObjectFormatVersion())); predicates.add(getQueryRestrictionOnPartitionValues(builder, businessObjectDataEntityJoin, businessObjectDataStorageUnitKey.getPartitionValue(), businessObjectDataStorageUnitKey.getSubPartitionValues())); predicates.add(builder.equal(businessObjectDataEntityJoin.get(BusinessObjectDataEntity_.version), businessObjectDataStorageUnitKey.getBusinessObjectDataVersion())); predicates.add(builder.equal(builder.upper(storageEntityJoin.get(StorageEntity_.name)), businessObjectDataStorageUnitKey.getStorageName().toUpperCase())); // Add the clauses for the query. criteria.select(storageUnitEntityRoot) .where(builder.and(predicates.toArray(new Predicate[predicates.size()]))); // Execute the query and return the result. return executeSingleResultQuery(criteria, String.format( "Found more than one business object data storage unit instance with parameters {namespace=\"%s\", businessObjectDefinitionName=\"%s\"," + " businessObjectFormatUsage=\"%s\", businessObjectFormatFileType=\"%s\", businessObjectFormatVersion=\"%d\"," + " businessObjectDataPartitionValue=\"%s\", businessObjectDataSubPartitionValues=\"%s\", businessObjectDataVersion=\"%d\"," + " storageName=\"%s\"}.", businessObjectDataStorageUnitKey.getNamespace(), businessObjectDataStorageUnitKey.getBusinessObjectDefinitionName(), businessObjectDataStorageUnitKey.getBusinessObjectFormatUsage(), businessObjectDataStorageUnitKey.getBusinessObjectFormatFileType(), businessObjectDataStorageUnitKey.getBusinessObjectFormatVersion(), businessObjectDataStorageUnitKey.getPartitionValue(), CollectionUtils.isEmpty(businessObjectDataStorageUnitKey.getSubPartitionValues()) ? "" : StringUtils.join(businessObjectDataStorageUnitKey.getSubPartitionValues(), ","), businessObjectDataStorageUnitKey.getBusinessObjectDataVersion(), businessObjectDataStorageUnitKey.getStorageName())); } @Override public StorageUnitEntity getStorageUnitByStorageAndDirectoryPath(StorageEntity storageEntity, String directoryPath) { // Create the criteria builder and the criteria. CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<StorageUnitEntity> criteria = builder.createQuery(StorageUnitEntity.class); // The criteria root is the storage unit. Root<StorageUnitEntity> storageUnitEntityRoot = criteria.from(StorageUnitEntity.class); // Create the standard restrictions (i.e. the standard where clauses). List<Predicate> predicates = new ArrayList<>(); predicates.add(builder.equal(storageUnitEntityRoot.get(StorageUnitEntity_.storage), storageEntity)); predicates.add(builder.equal(storageUnitEntityRoot.get(StorageUnitEntity_.directoryPath), directoryPath)); // Add all clauses for the query. criteria.select(storageUnitEntityRoot) .where(builder.and(predicates.toArray(new Predicate[predicates.size()]))); // Execute the query and return the first found storage unit or null if none were found. List<StorageUnitEntity> storageUnitEntities = entityManager.createQuery(criteria).getResultList(); return storageUnitEntities.size() >= 1 ? storageUnitEntities.get(0) : null; } @Override public List<StorageUnitAvailabilityDto> getStorageUnitsByPartitionFilters( BusinessObjectFormatKey businessObjectFormatKey, List<List<String>> partitionFilters, Integer businessObjectDataVersion, String businessObjectDataStatus, List<String> storageNames, String storagePlatformType, String excludedStoragePlatformType, boolean selectOnlyAvailableStorageUnits) { List<StorageUnitAvailabilityDto> results = new ArrayList<>(); // Loop through each chunk of partition filters until we have reached the end of the list. for (int i = 0; i < partitionFilters.size(); i += MAX_PARTITION_FILTERS_PER_REQUEST) { // Get a sub-list for the current chunk of partition filters. List<StorageUnitAvailabilityDto> storageUnitAvailabilityDtosSubset = getStorageUnitsByPartitionFilters( businessObjectFormatKey, partitionFilters, businessObjectDataVersion, businessObjectDataStatus, storageNames, storagePlatformType, excludedStoragePlatformType, selectOnlyAvailableStorageUnits, i, (i + MAX_PARTITION_FILTERS_PER_REQUEST) > partitionFilters.size() ? partitionFilters.size() - i : MAX_PARTITION_FILTERS_PER_REQUEST); // Add the sub-list to the result. results.addAll(storageUnitAvailabilityDtosSubset); } return results; } @Override public List<StorageUnitEntity> getStorageUnitsByStorageAndBusinessObjectData(StorageEntity storageEntity, List<BusinessObjectDataEntity> businessObjectDataEntities) { // Create the criteria builder and the criteria. CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<StorageUnitEntity> criteria = builder.createQuery(StorageUnitEntity.class); // The criteria root is the storage unit. Root<StorageUnitEntity> storageUnitEntity = criteria.from(StorageUnitEntity.class); // Create the standard restrictions (i.e. the standard where clauses). Predicate queryRestriction = builder.equal(storageUnitEntity.get(StorageUnitEntity_.storage), storageEntity); queryRestriction = builder.and(queryRestriction, getPredicateForInClause(builder, storageUnitEntity.get(StorageUnitEntity_.businessObjectData), businessObjectDataEntities)); // Add the clauses for the query. criteria.select(storageUnitEntity).where(queryRestriction); // Execute the query and return the results. return entityManager.createQuery(criteria).getResultList(); } @Override public List<StorageUnitEntity> getStorageUnitsByStoragePlatformAndBusinessObjectData(String storagePlatform, BusinessObjectDataEntity businessObjectDataEntity) { // Create the criteria builder and the criteria. CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<StorageUnitEntity> criteria = builder.createQuery(StorageUnitEntity.class); // The criteria root is the storage unit. Root<StorageUnitEntity> storageUnitEntity = criteria.from(StorageUnitEntity.class); // Join to the other tables we can filter on. Join<StorageUnitEntity, StorageEntity> storageEntity = storageUnitEntity.join(StorageUnitEntity_.storage); Join<StorageEntity, StoragePlatformEntity> storagePlatformEntity = storageEntity .join(StorageEntity_.storagePlatform); // Create the standard restrictions (i.e. the standard where clauses). List<Predicate> predicates = new ArrayList<>(); predicates.add(builder.equal(builder.upper(storagePlatformEntity.get(StoragePlatformEntity_.name)), storagePlatform.toUpperCase())); predicates.add(builder.equal(storageUnitEntity.get(StorageUnitEntity_.businessObjectData), businessObjectDataEntity)); // Order by storage name. Order orderBy = builder.asc(storageEntity.get(StorageEntity_.name)); // Add the clauses for the query. criteria.select(storageUnitEntity).where(builder.and(predicates.toArray(new Predicate[predicates.size()]))) .orderBy(orderBy); // Execute the query and return the results. return entityManager.createQuery(criteria).getResultList(); } /** * Builds a sub-query to select the maximum business object data version. * * @param builder the criteria builder * @param criteria the criteria query * @param businessObjectDefinitionEntity the business object definition entity that appears in the from clause of the main query * @param businessObjectFormatEntity the business object format entity that appears in the from clause of the main query * @param fileTypeEntity the file type entity that appears in the from clause of the main query * @param businessObjectDataEntity the business object data entity that appears in the from clause of the main query * @param businessObjectDataVersion the business object data version. If a business object data version isn't specified, the latest data version based on * the specified business object data status is returned * @param businessObjectDataStatus the business object data status. This parameter is ignored when the business object data version is specified. When * business object data version and business object data status both are not specified, the latest data version for each set of partition values will be * used regardless of the status * @param storageNames the list of storage names where the business object data storage units should be looked for (case-insensitive) * @param storagePlatformType the optional storage platform type, e.g. S3 for Hive DDL. It is ignored when the list of storages is not empty * @param excludedStoragePlatformType the optional storage platform type to be excluded from search. It is ignored when the list of storages is not empty or * the storage platform type is specified * @param selectOnlyAvailableStorageUnits specifies if only available storage units will be selected or any storage units regardless of their status * * @return the sub-query to select the maximum business object data version */ private Subquery<Integer> getMaximumBusinessObjectFormatVersionSubQuery(CriteriaBuilder builder, CriteriaQuery<?> criteria, From<?, BusinessObjectDefinitionEntity> businessObjectDefinitionEntity, From<?, BusinessObjectFormatEntity> businessObjectFormatEntity, From<?, FileTypeEntity> fileTypeEntity, From<?, BusinessObjectDataEntity> businessObjectDataEntity, Integer businessObjectDataVersion, String businessObjectDataStatus, List<String> storageNames, String storagePlatformType, String excludedStoragePlatformType, boolean selectOnlyAvailableStorageUnits) { // Business object format version is not specified, so just use the latest available for this set of partition values. Subquery<Integer> subQuery = criteria.subquery(Integer.class); // The criteria root is the business object data. Root<BusinessObjectDataEntity> subBusinessObjectDataEntity = subQuery.from(BusinessObjectDataEntity.class); // Join to the other tables we can filter on. Join<BusinessObjectDataEntity, StorageUnitEntity> subStorageUnitEntity = subBusinessObjectDataEntity .join(BusinessObjectDataEntity_.storageUnits); Join<StorageUnitEntity, StorageEntity> subStorageEntity = subStorageUnitEntity .join(StorageUnitEntity_.storage); Join<StorageEntity, StoragePlatformEntity> subStoragePlatformEntity = subStorageEntity .join(StorageEntity_.storagePlatform); Join<BusinessObjectDataEntity, BusinessObjectFormatEntity> subBusinessObjectFormatEntity = subBusinessObjectDataEntity .join(BusinessObjectDataEntity_.businessObjectFormat); Join<BusinessObjectFormatEntity, BusinessObjectDefinitionEntity> subBusinessObjectDefinitionEntity = subBusinessObjectFormatEntity .join(BusinessObjectFormatEntity_.businessObjectDefinition); Join<BusinessObjectFormatEntity, FileTypeEntity> subBusinessObjectFormatFileTypeEntity = subBusinessObjectFormatEntity .join(BusinessObjectFormatEntity_.fileType); Join<BusinessObjectDataEntity, BusinessObjectDataStatusEntity> subBusinessObjectDataStatusEntity = subBusinessObjectDataEntity .join(BusinessObjectDataEntity_.status); Join<StorageUnitEntity, StorageUnitStatusEntity> subStorageUnitStatusEntity = subStorageUnitEntity .join(StorageUnitEntity_.status); // Create the standard restrictions (i.e. the standard where clauses). Predicate subQueryRestriction = builder.equal(subBusinessObjectDefinitionEntity, businessObjectDefinitionEntity); subQueryRestriction = builder.and(subQueryRestriction, builder.equal(subBusinessObjectFormatEntity.get(BusinessObjectFormatEntity_.usage), businessObjectFormatEntity.get(BusinessObjectFormatEntity_.usage))); subQueryRestriction = builder.and(subQueryRestriction, builder.equal(subBusinessObjectFormatFileTypeEntity, fileTypeEntity)); // Create and add standard restrictions on primary and sub-partition values. subQueryRestriction = builder.and(subQueryRestriction, getQueryRestrictionOnPartitionValues(builder, subBusinessObjectDataEntity, businessObjectDataEntity)); // Add restrictions on business object data version and business object data status. Predicate subQueryRestrictionOnBusinessObjectDataVersionAndStatus = getQueryRestrictionOnBusinessObjectDataVersionAndStatus( builder, subBusinessObjectDataEntity, subBusinessObjectDataStatusEntity, businessObjectDataVersion, businessObjectDataStatus); if (subQueryRestrictionOnBusinessObjectDataVersionAndStatus != null) { subQueryRestriction = builder.and(subQueryRestriction, subQueryRestrictionOnBusinessObjectDataVersionAndStatus); } // Create and add a standard restriction on storage. subQueryRestriction = builder.and(subQueryRestriction, getQueryRestrictionOnStorage(builder, subStorageEntity, subStoragePlatformEntity, storageNames, storagePlatformType, excludedStoragePlatformType)); // If specified, add a restriction on storage unit status availability flag. if (selectOnlyAvailableStorageUnits) { subQueryRestriction = builder.and(subQueryRestriction, builder.isTrue(subStorageUnitStatusEntity.get(StorageUnitStatusEntity_.available))); } // Add all of the clauses to the subquery. subQuery.select(builder .max(subBusinessObjectFormatEntity.get(BusinessObjectFormatEntity_.businessObjectFormatVersion))) .where(subQueryRestriction); return subQuery; } /** * Retrieves a list of storage unit availability DTOs per specified parameters. This method processes a sublist of partition filters specified by * partitionFilterSubListFromIndex and partitionFilterSubListSize parameters. * * @param businessObjectFormatKey the business object format key (case-insensitive). If a business object format version isn't specified, the latest * available format version for each partition value will be used * @param partitionFilters the list of partition filter to be used to select business object data instances. Each partition filter contains a list of * primary and sub-partition values in the right order up to the maximum partition levels allowed by business object data registration - with partition * values for the relative partitions not to be used for selection passed as nulls * @param businessObjectDataVersion the business object data version. If a business object data version isn't specified, the latest data version based on * the specified business object data status is returned * @param businessObjectDataStatus the business object data status. This parameter is ignored when the business object data version is specified. When * business object data version and business object data status both are not specified, the latest data version for each set of partition values will be * used regardless of the status * @param storageNames the list of storage names where the business object data storage units should be looked for (case-insensitive) * @param storagePlatformType the optional storage platform type, e.g. S3 for Hive DDL. It is ignored when the list of storage names is not empty * @param excludedStoragePlatformType the optional storage platform type to be excluded from search. It is ignored when the list of storage names is not * empty or the storage platform type is specified * @param partitionFilterSubListFromIndex the index of the first element in the partition filter sublist * @param partitionFilterSubListSize the size of the partition filter sublist * @param selectOnlyAvailableStorageUnits specifies if only available storage units will be selected or any storage units regardless of their status * * @return the list of storage unit availability DTOs sorted by partition values */ private List<StorageUnitAvailabilityDto> getStorageUnitsByPartitionFilters( BusinessObjectFormatKey businessObjectFormatKey, List<List<String>> partitionFilters, Integer businessObjectDataVersion, String businessObjectDataStatus, List<String> storageNames, String storagePlatformType, String excludedStoragePlatformType, boolean selectOnlyAvailableStorageUnits, int partitionFilterSubListFromIndex, int partitionFilterSubListSize) { // Create the criteria builder and the criteria. CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<Tuple> criteria = builder.createTupleQuery(); // The criteria root is the storage unit. Root<StorageUnitEntity> storageUnitEntity = criteria.from(StorageUnitEntity.class); // Join to the other tables we can filter on. Join<StorageUnitEntity, BusinessObjectDataEntity> businessObjectDataEntity = storageUnitEntity .join(StorageUnitEntity_.businessObjectData); Join<StorageUnitEntity, StorageEntity> storageEntity = storageUnitEntity.join(StorageUnitEntity_.storage); Join<StorageEntity, StoragePlatformEntity> storagePlatformEntity = storageEntity .join(StorageEntity_.storagePlatform); Join<BusinessObjectDataEntity, BusinessObjectFormatEntity> businessObjectFormatEntity = businessObjectDataEntity .join(BusinessObjectDataEntity_.businessObjectFormat); Join<BusinessObjectFormatEntity, FileTypeEntity> fileTypeEntity = businessObjectFormatEntity .join(BusinessObjectFormatEntity_.fileType); Join<BusinessObjectFormatEntity, BusinessObjectDefinitionEntity> businessObjectDefinitionEntity = businessObjectFormatEntity .join(BusinessObjectFormatEntity_.businessObjectDefinition); Join<BusinessObjectDefinitionEntity, NamespaceEntity> namespaceEntity = businessObjectDefinitionEntity .join(BusinessObjectDefinitionEntity_.namespace); Join<StorageUnitEntity, StorageUnitStatusEntity> storageUnitStatusEntity = storageUnitEntity .join(StorageUnitEntity_.status); // Create the standard restrictions (i.e. the standard where clauses). // Create a standard restriction based on the business object format key values. // Please note that we specify not to ignore the business object format version. Predicate mainQueryRestriction = getQueryRestriction(builder, businessObjectFormatEntity, fileTypeEntity, businessObjectDefinitionEntity, namespaceEntity, businessObjectFormatKey, false); // If a format version was not specified, use the latest available for this set of partition values. if (businessObjectFormatKey.getBusinessObjectFormatVersion() == null) { // Get the latest available format version for this set of partition values and per other restrictions. Subquery<Integer> subQuery = getMaximumBusinessObjectFormatVersionSubQuery(builder, criteria, businessObjectDefinitionEntity, businessObjectFormatEntity, fileTypeEntity, businessObjectDataEntity, businessObjectDataVersion, businessObjectDataStatus, storageNames, storagePlatformType, excludedStoragePlatformType, selectOnlyAvailableStorageUnits); mainQueryRestriction = builder.and(mainQueryRestriction, builder.in( businessObjectFormatEntity.get(BusinessObjectFormatEntity_.businessObjectFormatVersion)) .value(subQuery)); } // Add restriction as per specified primary and/or sub-partition values. mainQueryRestriction = builder.and(mainQueryRestriction, getQueryRestrictionOnPartitionValues(builder, businessObjectDataEntity, partitionFilters.subList(partitionFilterSubListFromIndex, partitionFilterSubListFromIndex + partitionFilterSubListSize))); // If a data version was specified, use it. Otherwise, use the latest one as per specified business object data status. if (businessObjectDataVersion != null) { mainQueryRestriction = builder.and(mainQueryRestriction, builder.equal( businessObjectDataEntity.get(BusinessObjectDataEntity_.version), businessObjectDataVersion)); } else { // Business object data version is not specified, so get the latest one as per specified business object data status, if any. // Meaning, when both business object data version and business object data status are not specified, we just return // the latest business object data version in the specified storage. Subquery<Integer> subQuery = getMaximumBusinessObjectDataVersionSubQuery(builder, criteria, businessObjectDataEntity, businessObjectFormatEntity, businessObjectDataStatus, storageNames, storagePlatformType, excludedStoragePlatformType, selectOnlyAvailableStorageUnits); mainQueryRestriction = builder.and(mainQueryRestriction, builder.in(businessObjectDataEntity.get(BusinessObjectDataEntity_.version)).value(subQuery)); } // If specified, add restriction on storage. mainQueryRestriction = builder.and(mainQueryRestriction, getQueryRestrictionOnStorage(builder, storageEntity, storagePlatformEntity, storageNames, storagePlatformType, excludedStoragePlatformType)); // If specified, add a restriction on storage unit status availability flag. if (selectOnlyAvailableStorageUnits) { mainQueryRestriction = builder.and(mainQueryRestriction, builder.isTrue(storageUnitStatusEntity.get(StorageUnitStatusEntity_.available))); } // Order by partitions and storage names. List<Order> orderBy = new ArrayList<>(); for (SingularAttribute<BusinessObjectDataEntity, String> businessObjectDataPartition : BUSINESS_OBJECT_DATA_PARTITIONS) { orderBy.add(builder.asc(businessObjectDataEntity.get(businessObjectDataPartition))); } orderBy.add(builder.asc(storageEntity.get(StorageEntity_.name))); // Get the columns. Path<Integer> storageUnitIdColumn = storageUnitEntity.get(StorageUnitEntity_.id); Path<String> namespaceCodeColumn = namespaceEntity.get(NamespaceEntity_.code); Path<String> businessObjectDefinitionNameColumn = businessObjectDefinitionEntity .get(BusinessObjectDefinitionEntity_.name); Path<String> businessObjectFormatUsageColumn = businessObjectFormatEntity .get(BusinessObjectFormatEntity_.usage); Path<String> fileTypeColumn = fileTypeEntity.get(FileTypeEntity_.code); Path<Integer> businessObjectFormatVersionColumn = businessObjectFormatEntity .get(BusinessObjectFormatEntity_.businessObjectFormatVersion); Path<String> primaryPartitionValueColumn = businessObjectDataEntity .get(BusinessObjectDataEntity_.partitionValue); Path<String> subPartitionValue1Column = businessObjectDataEntity .get(BusinessObjectDataEntity_.partitionValue2); Path<String> subPartitionValue2Column = businessObjectDataEntity .get(BusinessObjectDataEntity_.partitionValue3); Path<String> subPartitionValue3Column = businessObjectDataEntity .get(BusinessObjectDataEntity_.partitionValue4); Path<String> subPartitionValue4Column = businessObjectDataEntity .get(BusinessObjectDataEntity_.partitionValue5); Path<Integer> businessObjectDataVersionColumn = businessObjectDataEntity .get(BusinessObjectDataEntity_.version); Path<String> storageNameColumn = storageEntity.get(StorageEntity_.name); Path<String> storageUnitDirectoryPathColumn = storageUnitEntity.get(StorageUnitEntity_.directoryPath); Path<String> businessObjectDataStatusColumn = businessObjectDataEntity .get(BusinessObjectDataEntity_.statusCode); Path<String> storageUnitStatusColumn = storageUnitEntity.get(StorageUnitEntity_.statusCode); Path<Boolean> storageUnitAvailableColumn = storageUnitStatusEntity.get(StorageUnitStatusEntity_.available); // Add the clauses for the query. criteria.multiselect(storageUnitIdColumn, namespaceCodeColumn, businessObjectDefinitionNameColumn, businessObjectFormatUsageColumn, fileTypeColumn, businessObjectFormatVersionColumn, primaryPartitionValueColumn, subPartitionValue1Column, subPartitionValue2Column, subPartitionValue3Column, subPartitionValue4Column, businessObjectDataVersionColumn, storageNameColumn, storageUnitDirectoryPathColumn, businessObjectDataStatusColumn, storageUnitStatusColumn, storageUnitAvailableColumn).where(mainQueryRestriction).orderBy(orderBy); // Run the query to get a list of tuples back. List<Tuple> tuples = entityManager.createQuery(criteria).getResultList(); // Build a list of storage unit availability DTOs to return. List<StorageUnitAvailabilityDto> storageUnitAvailabilityDtos = new ArrayList<>(); for (Tuple tuple : tuples) { storageUnitAvailabilityDtos.add(new StorageUnitAvailabilityDto(tuple.get(storageUnitIdColumn), new BusinessObjectDataKey(tuple.get(namespaceCodeColumn), tuple.get(businessObjectDefinitionNameColumn), tuple.get(businessObjectFormatUsageColumn), tuple.get(fileTypeColumn), tuple.get(businessObjectFormatVersionColumn), tuple.get(primaryPartitionValueColumn), getSubPartitionValuesFromRawSubPartitionValues(Arrays.asList( tuple.get(subPartitionValue1Column), tuple.get(subPartitionValue2Column), tuple.get(subPartitionValue3Column), tuple.get(subPartitionValue4Column))), tuple.get(businessObjectDataVersionColumn)), tuple.get(storageNameColumn), tuple.get(storageUnitDirectoryPathColumn), tuple.get(businessObjectDataStatusColumn), tuple.get(storageUnitStatusColumn), tuple.get(storageUnitAvailableColumn))); } return storageUnitAvailabilityDtos; } /** * Gets the sub-partition values for the specified list of raw sub-partition values. * * @param rawSubPartitionValues the list of raw sub-partition values * * @return the list of sub-partition values */ private List<String> getSubPartitionValuesFromRawSubPartitionValues(List<String> rawSubPartitionValues) { List<String> subPartitionValues = new ArrayList<>(); for (String rawSubPartitionValue : rawSubPartitionValues) { if (rawSubPartitionValue != null) { subPartitionValues.add(rawSubPartitionValue); } else { break; } } return subPartitionValues; } }