Search in sources :

Example 91 with BusinessObjectDataKey

use of org.finra.herd.model.api.xml.BusinessObjectDataKey in project herd by FINRAOS.

the class BusinessObjectDataServiceCreateBusinessObjectDataTest method testCreateBusinessObjectDataInitialDataVersionExists.

@Test
public void testCreateBusinessObjectDataInitialDataVersionExists() {
    // Create relative database entities including the initial version of the business object data.
    businessObjectDataDaoTestHelper.createBusinessObjectDataEntity(NAMESPACE, BDEF_NAME, FORMAT_USAGE_CODE, FORMAT_FILE_TYPE_CODE, INITIAL_FORMAT_VERSION, PARTITION_VALUE, INITIAL_DATA_VERSION, true, BDATA_STATUS);
    storageDaoTestHelper.createStorageEntity(STORAGE_NAME);
    // Build a list of storage files.
    List<StorageFile> storageFiles = businessObjectDataServiceTestHelper.getTestStorageFiles(testS3KeyPrefix, SORTED_LOCAL_FILES);
    // Build a new business object data create request.
    BusinessObjectDataCreateRequest request = businessObjectDataServiceTestHelper.createBusinessObjectDataCreateRequest(NAMESPACE, BDEF_NAME, FORMAT_USAGE_CODE, FORMAT_FILE_TYPE_CODE, INITIAL_FORMAT_VERSION, PARTITION_KEY, PARTITION_VALUE, BDATA_STATUS, STORAGE_NAME, testS3KeyPrefix, storageFiles);
    // Try to create the second version of the business object data (version 1) with createNewVersion flag set to null and to false.
    for (Boolean createNewVersionFlag : new Boolean[] { null, Boolean.FALSE }) {
        request.setCreateNewVersion(createNewVersionFlag);
        try {
            businessObjectDataService.createBusinessObjectData(request);
            fail(String.format("Should throw an IllegalArgumentException when the initial data version exists and createNewVersion flag is set to \"%s\".", createNewVersionFlag));
        } catch (AlreadyExistsException e) {
            assertEquals("Unable to create business object data because it already exists.", e.getMessage());
        }
    }
    // Try to create the second version of the business object data with createNewVersion flag set to true.
    request.setCreateNewVersion(true);
    BusinessObjectData resultBusinessObjectData = businessObjectDataService.createBusinessObjectData(request);
    // Validate the results for the second version if the business object data.
    businessObjectDataServiceTestHelper.validateBusinessObjectData(request, SECOND_DATA_VERSION, true, resultBusinessObjectData);
    // Confirm that the initial version of the business object data now does not have the latestFlag set.
    BusinessObjectDataEntity initialVersionBusinessObjectDataEntity = businessObjectDataDao.getBusinessObjectDataByAltKey(new BusinessObjectDataKey(NAMESPACE, BDEF_NAME, FORMAT_USAGE_CODE, FORMAT_FILE_TYPE_CODE, INITIAL_FORMAT_VERSION, PARTITION_VALUE, NO_SUBPARTITION_VALUES, INITIAL_DATA_VERSION));
    assertEquals(false, initialVersionBusinessObjectDataEntity.getLatestVersion());
}
Also used : AlreadyExistsException(org.finra.herd.model.AlreadyExistsException) BusinessObjectData(org.finra.herd.model.api.xml.BusinessObjectData) StorageFile(org.finra.herd.model.api.xml.StorageFile) BusinessObjectDataCreateRequest(org.finra.herd.model.api.xml.BusinessObjectDataCreateRequest) BusinessObjectDataEntity(org.finra.herd.model.jpa.BusinessObjectDataEntity) BusinessObjectDataKey(org.finra.herd.model.api.xml.BusinessObjectDataKey) Test(org.junit.Test)

Example 92 with BusinessObjectDataKey

use of org.finra.herd.model.api.xml.BusinessObjectDataKey in project herd by FINRAOS.

the class BusinessObjectDataServiceCreateBusinessObjectDataTest method testCreateBusinessObjectDataIgnoringCircularDependency.

/**
 * This test case validates that business object data registration succeeds even when specified business object data parents form a circular dependency. We
 * have B registered B as a child of C and C registered as a child of B (B->C and C->B), and now we try to register A as a child of C.  That business object
 * data registration is expected not to fail due to a pre-existing circular dependency between B and C.  Circular dependency for the already registered
 * business object data instances is an edge case and should not happen for normal operations and can only occur if the database was modified directly.
 */
@Test
public void testCreateBusinessObjectDataIgnoringCircularDependency() {
    // Create two business object data keys.
    BusinessObjectDataKey alphaBusinessObjectDataKey = new BusinessObjectDataKey(NAMESPACE, BDEF_NAME, FORMAT_USAGE_CODE, FORMAT_FILE_TYPE_CODE, FORMAT_VERSION, PARTITION_VALUE, SUBPARTITION_VALUES, DATA_VERSION);
    BusinessObjectDataKey betaBusinessObjectDataKey = new BusinessObjectDataKey(NAMESPACE, BDEF_NAME, FORMAT_USAGE_CODE_2, FORMAT_FILE_TYPE_CODE, FORMAT_VERSION, PARTITION_VALUE, SUBPARTITION_VALUES, DATA_VERSION);
    // Create the relative business object data entities.
    BusinessObjectDataEntity alphaBusinessObjectDataEntity = businessObjectDataDaoTestHelper.createBusinessObjectDataEntity(alphaBusinessObjectDataKey, true, BDATA_STATUS);
    BusinessObjectDataEntity betaBusinessObjectDataEntity = businessObjectDataDaoTestHelper.createBusinessObjectDataEntity(betaBusinessObjectDataKey, true, BDATA_STATUS);
    // Associate with each other the two business object data entities created above, so we get a circular dependency.
    // Make "alpha" a parent of "beta".
    alphaBusinessObjectDataEntity.getBusinessObjectDataChildren().add(betaBusinessObjectDataEntity);
    betaBusinessObjectDataEntity.getBusinessObjectDataParents().add(alphaBusinessObjectDataEntity);
    // Make "beta" a parent of "alpha".
    betaBusinessObjectDataEntity.getBusinessObjectDataChildren().add(alphaBusinessObjectDataEntity);
    alphaBusinessObjectDataEntity.getBusinessObjectDataParents().add(betaBusinessObjectDataEntity);
    // Create other database entities required for testing.
    storageDaoTestHelper.createStorageEntity(STORAGE_NAME);
    // Create a business object data create request with one of the entities created above listed as a parent.
    BusinessObjectDataCreateRequest request = businessObjectDataServiceTestHelper.createBusinessObjectDataCreateRequest(NAMESPACE, BDEF_NAME, FORMAT_USAGE_CODE, FORMAT_FILE_TYPE_CODE, FORMAT_VERSION, PARTITION_KEY, PARTITION_VALUE_2, BDATA_STATUS, STORAGE_NAME, testS3KeyPrefix, businessObjectDataServiceTestHelper.getTestStorageFiles(testS3KeyPrefix, Arrays.asList(LOCAL_FILE)));
    List<BusinessObjectDataKey> parents = new ArrayList<>();
    request.setBusinessObjectDataParents(parents);
    parents.add(betaBusinessObjectDataKey);
    // Create a business object data when a parent is part of a circular dependency.
    BusinessObjectData resultBusinessObjectData = businessObjectDataService.createBusinessObjectData(request);
    // Validate the results.
    assertNotNull(resultBusinessObjectData);
    assertNotNull(resultBusinessObjectData.getBusinessObjectDataParents());
    assertEquals(1, resultBusinessObjectData.getBusinessObjectDataParents().size());
    assertTrue(resultBusinessObjectData.getBusinessObjectDataParents().contains(betaBusinessObjectDataKey));
}
Also used : BusinessObjectData(org.finra.herd.model.api.xml.BusinessObjectData) BusinessObjectDataCreateRequest(org.finra.herd.model.api.xml.BusinessObjectDataCreateRequest) ArrayList(java.util.ArrayList) BusinessObjectDataEntity(org.finra.herd.model.jpa.BusinessObjectDataEntity) BusinessObjectDataKey(org.finra.herd.model.api.xml.BusinessObjectDataKey) Test(org.junit.Test)

Example 93 with BusinessObjectDataKey

use of org.finra.herd.model.api.xml.BusinessObjectDataKey in project herd by FINRAOS.

the class BusinessObjectDataServiceDestroyBusinessObjectDataTest method testDestroyBusinessObjectData.

@Test
public void testDestroyBusinessObjectData() throws Exception {
    // Create a primary partition value that satisfies the retention threshold check.
    String primaryPartitionValue = DateFormatUtils.format(DateUtils.addDays(new Date(), -1 * (RETENTION_PERIOD_DAYS + 1)), AbstractHerdDao.DEFAULT_SINGLE_DAY_DATE_MASK);
    // Build the expected S3 key prefix for test business object data.
    String s3KeyPrefix = getExpectedS3KeyPrefix(BDEF_NAMESPACE, DATA_PROVIDER_NAME, BDEF_NAME, FORMAT_USAGE_CODE, FORMAT_FILE_TYPE_CODE, FORMAT_VERSION, PARTITION_KEY, primaryPartitionValue, null, null, DATA_VERSION);
    // Create S3FileTransferRequestParamsDto to access the S3 bucket location.
    // Since test S3 key prefix represents a directory, we add a trailing '/' character to it.
    S3FileTransferRequestParamsDto s3FileTransferRequestParamsDto = S3FileTransferRequestParamsDto.builder().withS3BucketName(S3_BUCKET_NAME).withS3KeyPrefix(s3KeyPrefix + "/").build();
    // Create an S3 storage with the relative attributes.
    storageDaoTestHelper.createStorageEntity(STORAGE_NAME, StoragePlatformEntity.S3, Arrays.asList(new Attribute(configurationHelper.getProperty(ConfigurationValue.S3_ATTRIBUTE_NAME_BUCKET_NAME), AbstractServiceTest.S3_BUCKET_NAME), new Attribute(configurationHelper.getProperty(ConfigurationValue.S3_ATTRIBUTE_NAME_KEY_PREFIX_VELOCITY_TEMPLATE), AbstractServiceTest.S3_KEY_PREFIX_VELOCITY_TEMPLATE), new Attribute(configurationHelper.getProperty(ConfigurationValue.S3_ATTRIBUTE_NAME_VALIDATE_PATH_PREFIX), Boolean.TRUE.toString()), new Attribute(configurationHelper.getProperty(ConfigurationValue.S3_ATTRIBUTE_NAME_VALIDATE_FILE_EXISTENCE), Boolean.TRUE.toString())));
    // Create a business object data key.
    BusinessObjectDataKey businessObjectDataKey = new BusinessObjectDataKey(BDEF_NAMESPACE, BDEF_NAME, FORMAT_USAGE_CODE, FORMAT_FILE_TYPE_CODE, FORMAT_VERSION, primaryPartitionValue, NO_SUBPARTITION_VALUES, DATA_VERSION);
    // Create and persist a storage unit in the storage.
    StorageUnitEntity storageUnitEntity = storageUnitDaoTestHelper.createStorageUnitEntity(STORAGE_NAME, businessObjectDataKey, LATEST_VERSION_FLAG_SET, BusinessObjectDataStatusEntity.VALID, StorageUnitStatusEntity.ENABLED, NO_STORAGE_DIRECTORY_PATH);
    // Add storage files to the storage unit.
    for (String filePath : LOCAL_FILES) {
        storageFileDaoTestHelper.createStorageFileEntity(storageUnitEntity, s3KeyPrefix + "/" + filePath, FILE_SIZE_1_KB, ROW_COUNT_1000);
    }
    // Get the storage files.
    List<StorageFile> storageFiles = storageFileHelper.createStorageFilesFromEntities(storageUnitEntity.getStorageFiles());
    // Get the business object format entity.
    BusinessObjectFormatEntity businessObjectFormatEntity = storageUnitEntity.getBusinessObjectData().getBusinessObjectFormat();
    // Set the retention information for the business object format, which is the latest version business object format.
    businessObjectFormatEntity.setRetentionType(retentionTypeDao.getRetentionTypeByCode(RetentionTypeEntity.PARTITION_VALUE));
    businessObjectFormatEntity.setRetentionPeriodInDays(RETENTION_PERIOD_DAYS);
    businessObjectFormatDao.saveAndRefresh(businessObjectFormatEntity);
    // Override configuration to specify some settings required for testing.
    Map<String, Object> overrideMap = new HashMap<>();
    overrideMap.put(ConfigurationValue.S3_OBJECT_DELETE_TAG_KEY.getKey(), S3_OBJECT_TAG_KEY);
    overrideMap.put(ConfigurationValue.S3_OBJECT_DELETE_TAG_VALUE.getKey(), S3_OBJECT_TAG_VALUE);
    overrideMap.put(ConfigurationValue.S3_OBJECT_DELETE_ROLE_ARN.getKey(), S3_OBJECT_TAGGER_ROLE_ARN);
    overrideMap.put(ConfigurationValue.S3_OBJECT_DELETE_ROLE_SESSION_NAME.getKey(), S3_OBJECT_TAGGER_ROLE_SESSION_NAME);
    modifyPropertySourceInEnvironment(overrideMap);
    try {
        // Put relative S3 files into the S3 bucket.
        for (StorageFile storageFile : storageFiles) {
            s3Operations.putObject(new PutObjectRequest(S3_BUCKET_NAME, storageFile.getFilePath(), new ByteArrayInputStream(new byte[storageFile.getFileSizeBytes().intValue()]), null), null);
        }
        // Request to destroy business object data.
        BusinessObjectData result = businessObjectDataService.destroyBusinessObjectData(businessObjectDataKey);
        // Validate the result.
        assertNotNull(result);
        assertEquals(storageUnitEntity.getBusinessObjectData().getId(), Integer.valueOf(result.getId()));
        // Validate the status of the storage unit entity.
        assertEquals(StorageUnitStatusEntity.DISABLED, storageUnitEntity.getStatus().getCode());
        // Validate the status of the business object data entity.
        assertEquals(BusinessObjectDataStatusEntity.DELETED, storageUnitEntity.getBusinessObjectData().getStatus().getCode());
        // Validate that all S3 files are now tagged.
        for (StorageFile storageFile : storageFiles) {
            GetObjectTaggingResult getObjectTaggingResult = s3Operations.getObjectTagging(new GetObjectTaggingRequest(S3_BUCKET_NAME, storageFile.getFilePath()), null);
            assertEquals(Arrays.asList(new Tag(S3_OBJECT_TAG_KEY, S3_OBJECT_TAG_VALUE)), getObjectTaggingResult.getTagSet());
        }
    } finally {
        // Delete test files from S3 storage.
        if (!s3Dao.listDirectory(s3FileTransferRequestParamsDto).isEmpty()) {
            s3Dao.deleteDirectory(s3FileTransferRequestParamsDto);
        }
        s3Operations.rollback();
        // Restore the property sources so we don't affect other tests.
        restorePropertySourceInEnvironment();
    }
}
Also used : GetObjectTaggingRequest(com.amazonaws.services.s3.model.GetObjectTaggingRequest) S3FileTransferRequestParamsDto(org.finra.herd.model.dto.S3FileTransferRequestParamsDto) Attribute(org.finra.herd.model.api.xml.Attribute) StorageUnitEntity(org.finra.herd.model.jpa.StorageUnitEntity) HashMap(java.util.HashMap) BusinessObjectData(org.finra.herd.model.api.xml.BusinessObjectData) BusinessObjectDataKey(org.finra.herd.model.api.xml.BusinessObjectDataKey) BusinessObjectFormatEntity(org.finra.herd.model.jpa.BusinessObjectFormatEntity) Date(java.util.Date) GetObjectTaggingResult(com.amazonaws.services.s3.model.GetObjectTaggingResult) ByteArrayInputStream(java.io.ByteArrayInputStream) StorageFile(org.finra.herd.model.api.xml.StorageFile) Tag(com.amazonaws.services.s3.model.Tag) PutObjectRequest(com.amazonaws.services.s3.model.PutObjectRequest) Test(org.junit.Test)

Example 94 with BusinessObjectDataKey

use of org.finra.herd.model.api.xml.BusinessObjectDataKey in project herd by FINRAOS.

the class BusinessObjectDataFinalizeRestoreServiceTest method testGetS3StorageUnitsToRestore.

@Test
public void testGetS3StorageUnitsToRestore() throws Exception {
    // Create a list of business object data keys.
    List<BusinessObjectDataKey> businessObjectDataKeys = Arrays.asList(new BusinessObjectDataKey(BDEF_NAMESPACE, BDEF_NAME, FORMAT_USAGE_CODE, FORMAT_FILE_TYPE_CODE, FORMAT_VERSION, PARTITION_VALUE, SUBPARTITION_VALUES, DATA_VERSION), new BusinessObjectDataKey(BDEF_NAMESPACE, BDEF_NAME, FORMAT_USAGE_CODE, FORMAT_FILE_TYPE_CODE, FORMAT_VERSION, PARTITION_VALUE_2, SUBPARTITION_VALUES, DATA_VERSION));
    // Create database entities required for testing.
    for (BusinessObjectDataKey businessObjectDataKey : businessObjectDataKeys) {
        storageUnitDaoTestHelper.createStorageUnitEntity(STORAGE_NAME, businessObjectDataKey, StorageUnitStatusEntity.RESTORING);
    }
    // Select the RESTORING storage units.
    List<BusinessObjectDataStorageUnitKey> resultStorageUnitKeys = businessObjectDataFinalizeRestoreService.getS3StorageUnitsToRestore(MAX_RESULT);
    // Validate the results.
    assertEquals(businessObjectDataKeys.size(), resultStorageUnitKeys.size());
    for (BusinessObjectDataKey businessObjectDataKey : businessObjectDataKeys) {
        assertTrue(resultStorageUnitKeys.contains(storageUnitHelper.createStorageUnitKey(businessObjectDataKey, STORAGE_NAME)));
    }
    // Try to select the RESTORING storage units with max result limit set to 1. Only one storage unit is expected to be returned.
    assertEquals(1, businessObjectDataFinalizeRestoreService.getS3StorageUnitsToRestore(1).size());
}
Also used : BusinessObjectDataStorageUnitKey(org.finra.herd.model.api.xml.BusinessObjectDataStorageUnitKey) BusinessObjectDataKey(org.finra.herd.model.api.xml.BusinessObjectDataKey) Test(org.junit.Test)

Example 95 with BusinessObjectDataKey

use of org.finra.herd.model.api.xml.BusinessObjectDataKey in project herd by FINRAOS.

the class BusinessObjectDataNotificationJobActionServiceTest method testGetIdentifyingInformation.

@Test
public void testGetIdentifyingInformation() throws Exception {
    // Create a job definition.
    JobDefinition jobDefinition = jobDefinitionServiceTestHelper.createJobDefinition(ACTIVITI_XML_LOG_VARIABLES_NO_REGEX_WITH_CLASSPATH);
    // Create a job action.
    List<JobAction> jobActions = new ArrayList<>();
    jobActions.add(new JobAction(jobDefinition.getNamespace(), jobDefinition.getJobName(), CORRELATION_DATA));
    // Create and persist a business object data notification registration entity.
    BusinessObjectDataNotificationRegistrationEntity businessObjectDataNotificationRegistrationEntity = notificationRegistrationDaoTestHelper.createBusinessObjectDataNotificationRegistrationEntity(new NotificationRegistrationKey(NAMESPACE, NOTIFICATION_NAME), NotificationEventTypeEntity.EventTypesBdata.BUS_OBJCT_DATA_RGSTN.name(), BDEF_NAMESPACE, BDEF_NAME, FORMAT_USAGE_CODE, FORMAT_FILE_TYPE_CODE, FORMAT_VERSION, STORAGE_NAME, null, null, jobActions, NotificationRegistrationStatusEntity.ENABLED);
    // Create a business object data key.
    BusinessObjectDataKey businessObjectDataKey = new BusinessObjectDataKey(BDEF_NAMESPACE, BDEF_NAME, FORMAT_USAGE_CODE, FORMAT_FILE_TYPE_CODE, FORMAT_VERSION, PARTITION_VALUE, SUBPARTITION_VALUES, DATA_VERSION);
    // Create a business object data entity.
    BusinessObjectDataEntity businessObjectDataEntity = businessObjectDataDaoTestHelper.createBusinessObjectDataEntity(BDEF_NAMESPACE, BDEF_NAME, FORMAT_USAGE_CODE, FORMAT_FILE_TYPE_CODE, FORMAT_VERSION, PARTITION_VALUE, SUBPARTITION_VALUES, DATA_VERSION, LATEST_VERSION_FLAG_SET, BDATA_STATUS);
    // Create and initiate an instance of the business object data notification event parameters DTO.
    BusinessObjectDataNotificationEventParamsDto businessObjectDataNotificationEventParams = new BusinessObjectDataNotificationEventParamsDto();
    businessObjectDataNotificationEventParams.setBusinessObjectData(businessObjectDataHelper.createBusinessObjectDataFromEntity(businessObjectDataEntity));
    businessObjectDataNotificationEventParams.setBusinessObjectDataNotificationRegistration(businessObjectDataNotificationRegistrationEntity);
    businessObjectDataNotificationEventParams.setEventType(NotificationEventTypeEntity.EventTypesBdata.BUS_OBJCT_DATA_RGSTN.name());
    businessObjectDataNotificationEventParams.setNotificationJobAction((NotificationJobActionEntity) businessObjectDataNotificationRegistrationEntity.getNotificationActions().toArray()[0]);
    businessObjectDataNotificationEventParams.setStorageName(STORAGE_NAME);
    // Get the notification action service for the business object data registration event.
    NotificationActionService notificationActionService = notificationActionFactory.getNotificationActionHandler(NotificationTypeEntity.NOTIFICATION_TYPE_BDATA, NotificationEventTypeEntity.EventTypesBdata.BUS_OBJCT_DATA_RGSTN.name());
    // Validate the identifying information for the notification event.
    String expectedValue = String.format("namespace: \"%s\", actionId: \"%s\" with " + businessObjectDataHelper.businessObjectDataKeyToString(businessObjectDataKey) + ", storageName: \"%s\"", businessObjectDataNotificationRegistrationEntity.getNamespace().getCode(), ((NotificationJobActionEntity) businessObjectDataNotificationRegistrationEntity.getNotificationActions().toArray()[0]).getId(), STORAGE_NAME);
    assertEquals(expectedValue, notificationActionService.getIdentifyingInformation(businessObjectDataNotificationEventParams, businessObjectDataHelper));
}
Also used : JobAction(org.finra.herd.model.api.xml.JobAction) ArrayList(java.util.ArrayList) BusinessObjectDataNotificationEventParamsDto(org.finra.herd.model.dto.BusinessObjectDataNotificationEventParamsDto) BusinessObjectDataEntity(org.finra.herd.model.jpa.BusinessObjectDataEntity) BusinessObjectDataNotificationRegistrationEntity(org.finra.herd.model.jpa.BusinessObjectDataNotificationRegistrationEntity) BusinessObjectDataKey(org.finra.herd.model.api.xml.BusinessObjectDataKey) JobDefinition(org.finra.herd.model.api.xml.JobDefinition) NotificationRegistrationKey(org.finra.herd.model.api.xml.NotificationRegistrationKey) Test(org.junit.Test)

Aggregations

BusinessObjectDataKey (org.finra.herd.model.api.xml.BusinessObjectDataKey)444 Test (org.junit.Test)378 BusinessObjectDataEntity (org.finra.herd.model.jpa.BusinessObjectDataEntity)138 AbstractServiceTest (org.finra.herd.service.AbstractServiceTest)93 ArrayList (java.util.ArrayList)92 StorageUnitEntity (org.finra.herd.model.jpa.StorageUnitEntity)78 BusinessObjectData (org.finra.herd.model.api.xml.BusinessObjectData)62 StoragePolicyKey (org.finra.herd.model.api.xml.StoragePolicyKey)50 HashMap (java.util.HashMap)43 StorageFile (org.finra.herd.model.api.xml.StorageFile)38 ObjectNotFoundException (org.finra.herd.model.ObjectNotFoundException)36 BusinessObjectDataStorageUnitKey (org.finra.herd.model.api.xml.BusinessObjectDataStorageUnitKey)33 Attribute (org.finra.herd.model.api.xml.Attribute)32 NotificationMessageDefinitions (org.finra.herd.model.api.xml.NotificationMessageDefinitions)32 StoragePolicySelection (org.finra.herd.model.dto.StoragePolicySelection)32 ConfigurationEntity (org.finra.herd.model.jpa.ConfigurationEntity)32 NotificationMessageDefinition (org.finra.herd.model.api.xml.NotificationMessageDefinition)30 Parameter (org.finra.herd.model.api.xml.Parameter)30 S3FileTransferRequestParamsDto (org.finra.herd.model.dto.S3FileTransferRequestParamsDto)29 BusinessObjectFormatEntity (org.finra.herd.model.jpa.BusinessObjectFormatEntity)29