/* * 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.service.impl; import static org.finra.herd.model.dto.SearchIndexUpdateDto.SEARCH_INDEX_UPDATE_TYPE_CREATE; import static org.finra.herd.model.dto.SearchIndexUpdateDto.SEARCH_INDEX_UPDATE_TYPE_DELETE; import static org.finra.herd.model.dto.SearchIndexUpdateDto.SEARCH_INDEX_UPDATE_TYPE_UPDATE; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Future; import java.util.function.Predicate; import com.google.common.collect.ImmutableSet; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.AsyncResult; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import org.finra.herd.core.HerdDateUtils; import org.finra.herd.core.helper.ConfigurationHelper; import org.finra.herd.dao.BusinessObjectDefinitionDao; import org.finra.herd.dao.TagDao; import org.finra.herd.dao.config.DaoSpringModuleConfig; import org.finra.herd.model.AlreadyExistsException; import org.finra.herd.model.annotation.PublishJmsMessages; import org.finra.herd.model.api.xml.Tag; import org.finra.herd.model.api.xml.TagChild; import org.finra.herd.model.api.xml.TagCreateRequest; import org.finra.herd.model.api.xml.TagKey; import org.finra.herd.model.api.xml.TagListResponse; import org.finra.herd.model.api.xml.TagSearchFilter; import org.finra.herd.model.api.xml.TagSearchKey; import org.finra.herd.model.api.xml.TagSearchRequest; import org.finra.herd.model.api.xml.TagSearchResponse; import org.finra.herd.model.api.xml.TagTypeKey; import org.finra.herd.model.api.xml.TagUpdateRequest; import org.finra.herd.model.dto.ConfigurationValue; import org.finra.herd.model.dto.SearchIndexUpdateDto; import org.finra.herd.model.jpa.BusinessObjectDefinitionEntity; import org.finra.herd.model.jpa.SearchIndexTypeEntity; import org.finra.herd.model.jpa.TagEntity; import org.finra.herd.model.jpa.TagTypeEntity; import org.finra.herd.service.SearchableService; import org.finra.herd.service.TagService; import org.finra.herd.service.functional.SearchFunctions; import org.finra.herd.service.helper.AlternateKeyHelper; import org.finra.herd.service.helper.SearchIndexUpdateHelper; import org.finra.herd.service.helper.TagDaoHelper; import org.finra.herd.service.helper.TagHelper; import org.finra.herd.service.helper.TagTypeDaoHelper; /** * The tag service implementation. */ @Service @Transactional(value = DaoSpringModuleConfig.HERD_TRANSACTION_MANAGER_BEAN_NAME) public class TagServiceImpl implements TagService, SearchableService { private static final Logger LOGGER = LoggerFactory.getLogger(TagServiceImpl.class); // Constant to hold the description field option for the search response. public final static String DESCRIPTION_FIELD = "description".toLowerCase(); // Constant to hold the display name field option for the search response. public final static String DISPLAY_NAME_FIELD = "displayName".toLowerCase(); // Constant to hold the has children field option for the search response. public final static String HAS_CHILDREN_FIELD = "hasChildren".toLowerCase(); // Constant to hold the parent tag key field option for the search response. public final static String PARENT_TAG_KEY_FIELD = "parentTagKey".toLowerCase(); @Autowired private AlternateKeyHelper alternateKeyHelper; @Autowired private BusinessObjectDefinitionDao businessObjectDefinitionDao; @Autowired private ConfigurationHelper configurationHelper; @Autowired private SearchFunctions searchFunctions; @Autowired private SearchIndexUpdateHelper searchIndexUpdateHelper; @Autowired private TagDao tagDao; @Autowired private TagDaoHelper tagDaoHelper; @Autowired private TagHelper tagHelper; @Autowired private TagTypeDaoHelper tagTypeDaoHelper; @PublishJmsMessages @Override public Tag createTag(TagCreateRequest request) { // Validate and trim the request parameters. validateTagCreateRequest(request); // Get the tag type and ensure it exists. TagTypeEntity tagTypeEntity = tagTypeDaoHelper.getTagTypeEntity(new TagTypeKey(request.getTagKey().getTagTypeCode())); // Validate that the tag entity does not already exist. if (tagDao.getTagByKey(request.getTagKey()) != null) { throw new AlreadyExistsException(String .format("Unable to create tag with tag type code \"%s\" and tag code \"%s\" because it already exists.", request.getTagKey().getTagTypeCode(), request.getTagKey().getTagCode())); } // List of tag entities to update in the search index List<TagEntity> tagEntities = new ArrayList<>(); // Validate that the specified display name does not already exist for the specified tag type tagDaoHelper.assertDisplayNameDoesNotExistForTag(request.getTagKey().getTagTypeCode(), request.getDisplayName()); TagEntity parentTagEntity = null; if (request.getParentTagKey() != null) { parentTagEntity = tagDaoHelper.getTagEntity(request.getParentTagKey()); // Add the parent tag entity to the list of tag entities to update in the search index tagEntities.add(parentTagEntity); } // Create and persist a new tag entity from the information in the request. TagEntity tagEntity = createTagEntity(request, tagTypeEntity, parentTagEntity); // Notify the tag search index that a tag must be created. tagEntities.add(tagEntity); searchIndexUpdateHelper.modifyTagsInSearchIndex(tagEntities, SEARCH_INDEX_UPDATE_TYPE_CREATE); // Create and return the tag object from the persisted entity. return createTagFromEntity(tagEntity); } @PublishJmsMessages @Override public Tag deleteTag(TagKey tagKey) { // Validate and trim the tag key. tagHelper.validateTagKey(tagKey); // Retrieve and ensure that a Tag already exists for the given tag key. TagEntity tagEntity = tagDaoHelper.getTagEntity(tagKey); // List of tag entities to update in the search index List<TagEntity> tagEntities = new ArrayList<>(); tagEntities.add(tagEntity); // If there is a parent tag entity add it to the tag entities list if (tagEntity.getParentTagEntity() != null) { tagEntities.add(tagEntity.getParentTagEntity()); } List<BusinessObjectDefinitionEntity> businessObjectDefinitionEntities = businessObjectDefinitionDao.getBusinessObjectDefinitions(tagEntities); // delete the tag. tagDao.delete(tagEntity); // Notify the tag search index that a tag must be deleted. searchIndexUpdateHelper.modifyTagInSearchIndex(tagEntity, SEARCH_INDEX_UPDATE_TYPE_DELETE); // If there is a parent tag entity, notify the tag search index that the parent tag must be updated if (tagEntity.getParentTagEntity() != null) { searchIndexUpdateHelper.modifyTagInSearchIndex(tagEntity.getParentTagEntity(), SEARCH_INDEX_UPDATE_TYPE_UPDATE); } // Notify the search index that a business object definition must be updated. searchIndexUpdateHelper.modifyBusinessObjectDefinitionsInSearchIndex(businessObjectDefinitionEntities, SEARCH_INDEX_UPDATE_TYPE_UPDATE); // Create and return the tag object from the deleted entity. return createTagFromEntity(tagEntity); } @Override public Tag getTag(TagKey tagKey) { // Perform validation and trim. tagHelper.validateTagKey(tagKey); // Retrieve and ensure that a Tag already exists with the specified key. TagEntity tagEntity = tagDaoHelper.getTagEntity(tagKey); // Create and return the tag object from the entity which was retrieved. return createTagFromEntity(tagEntity); } @Override public TagListResponse getTags(String tagTypeCode, String tagCode) { // Validate and trim the tag type code. String tagTypeCodeLocal = alternateKeyHelper.validateStringParameter("tag type code", tagTypeCode); String cleanTagCode = tagCode; // Retrieve and ensure that a tag type exists for the specified tag type code. tagTypeDaoHelper.getTagTypeEntity(new TagTypeKey(tagTypeCodeLocal)); // Get the list of tag keys. TagListResponse response = new TagListResponse(); //not root, need to set the tag key and parent tag key //getTag method will validate the requested tag exists if (tagCode != null) { cleanTagCode = alternateKeyHelper.validateStringParameter("tag code", tagCode); TagKey tagKey = new TagKey(tagTypeCodeLocal, cleanTagCode); Tag tag = getTag(tagKey); response.setTagKey(tag.getTagKey()); response.setParentTagKey(tag.getParentTagKey()); } List<TagChild> tagChildren = tagDao.getTagsByTagTypeAndParentTagCode(tagTypeCodeLocal, cleanTagCode); response.setTagChildren(tagChildren); return response; } @Override public Set<String> getValidSearchResponseFields() { return ImmutableSet.of(DISPLAY_NAME_FIELD, DESCRIPTION_FIELD, PARENT_TAG_KEY_FIELD, HAS_CHILDREN_FIELD); } @Override public TagSearchResponse searchTags(TagSearchRequest request, Set<String> fields) { // Validate and trim the request parameters. validateTagSearchRequest(request); // Validate and trim the search response fields. validateSearchResponseFields(fields); // Prepare the result list. List<TagEntity> tagEntities = new ArrayList<>(); // If search key is specified, use it to retrieve the tags. if (CollectionUtils.isNotEmpty(request.getTagSearchFilters()) && request.getTagSearchFilters().get(0) != null) { // Get the tag search key. TagSearchKey tagSearchKey = request.getTagSearchFilters().get(0).getTagSearchKeys().get(0); // Retrieve and ensure that a tag type exists for the specified tag type code. TagTypeEntity tagTypeEntity = tagTypeDaoHelper.getTagTypeEntity(new TagTypeKey(tagSearchKey.getTagTypeCode())); // Retrieve the tags. tagEntities.addAll(tagDao.getTagsByTagTypeEntityAndParentTagCode(tagTypeEntity, tagSearchKey.getParentTagCode(), tagSearchKey.isIsParentTagNull())); } // The search key is not specified, so select all tags registered in the system. else { // Retrieve the tags. tagEntities.addAll(tagDao.getTags()); } // Build the list of tags. List<Tag> tags = new ArrayList<>(); for (TagEntity tagEntity : tagEntities) { tags.add(createTagFromEntity(tagEntity, false, fields.contains(DISPLAY_NAME_FIELD), fields.contains(DESCRIPTION_FIELD), false, false, false, fields.contains(PARENT_TAG_KEY_FIELD), fields.contains(HAS_CHILDREN_FIELD))); } // Build and return the tag search response. return new TagSearchResponse(tags); } @Override public void updateSearchIndexDocumentTag(SearchIndexUpdateDto searchIndexUpdateDto) { final String indexName = SearchIndexTypeEntity.SearchIndexTypes.TAG.name().toLowerCase(); final String documentType = configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_BDEF_DOCUMENT_TYPE, String.class); String modificationType = searchIndexUpdateDto.getModificationType(); List<Integer> ids = searchIndexUpdateDto.getTagIds(); // Switch on the type of CRUD modification to be done switch (modificationType) { case SEARCH_INDEX_UPDATE_TYPE_CREATE: // Create a search index document searchFunctions.getCreateIndexDocumentsFunction() .accept(indexName, documentType, convertTagEntityListToJSONStringMap(tagDao.getTagsByIds(ids))); break; case SEARCH_INDEX_UPDATE_TYPE_UPDATE: // Update a search index document searchFunctions.getUpdateIndexDocumentsFunction() .accept(indexName, documentType, convertTagEntityListToJSONStringMap(tagDao.getTagsByIds(ids))); break; case SEARCH_INDEX_UPDATE_TYPE_DELETE: // Delete a search index document searchFunctions.getDeleteIndexDocumentsFunction().accept(indexName, documentType, ids); break; default: LOGGER.warn("Unknown modification type received."); break; } } @PublishJmsMessages @Override public Tag updateTag(TagKey tagKey, TagUpdateRequest tagUpdateRequest) { // Perform validation and trim tagHelper.validateTagKey(tagKey); // Perform validation and trim. validateTagUpdateRequest(tagKey, tagUpdateRequest); // Retrieve and ensure that a tag already exists with the specified key. TagEntity tagEntity = tagDaoHelper.getTagEntity(tagKey); // Validate the display name does not already exist for another tag for this tag type in the database. if (!StringUtils.equalsIgnoreCase(tagEntity.getDisplayName(), tagUpdateRequest.getDisplayName())) { // Validate that the description is different. tagDaoHelper.assertDisplayNameDoesNotExistForTag(tagKey.getTagTypeCode(), tagUpdateRequest.getDisplayName()); } // List of tag entities to update in the search index List<TagEntity> tagEntities = new ArrayList<>(); tagEntities.add(tagEntity); // If there is an original tag entity parent, then update if (tagEntity.getParentTagEntity() != null) { tagEntities.add(tagEntity.getParentTagEntity()); } // Validate the parent tag if one specified. TagEntity parentTagEntity = null; if (tagUpdateRequest.getParentTagKey() != null) { // Get parent tag entity and ensure it exists. parentTagEntity = tagDaoHelper.getTagEntity(tagUpdateRequest.getParentTagKey()); // Validate the parent tag entity. tagDaoHelper.validateParentTagEntity(tagEntity, parentTagEntity); // Add the parent tag entity to the tag entities list tagEntities.add(parentTagEntity); } // Update and persist the tag entity. updateTagEntity(tagEntity, tagUpdateRequest, parentTagEntity); // Notify the search index that a business object definition must be updated. searchIndexUpdateHelper.modifyBusinessObjectDefinitionsInSearchIndex(businessObjectDefinitionDao.getBusinessObjectDefinitions(tagEntities), SEARCH_INDEX_UPDATE_TYPE_UPDATE); // Notify the tag search index that tags must be updated. searchIndexUpdateHelper.modifyTagsInSearchIndex(tagEntities, SEARCH_INDEX_UPDATE_TYPE_UPDATE); // Create and return the tag object from the tag entity. return createTagFromEntity(tagEntity); } /** * Creates and persists a new Tag entity. * * @param request the tag create request * @param tagTypeEntity the specified tag type entity. * @param parentTagEntity the specified parent tag entity * * @return the newly created tag entity. */ private TagEntity createTagEntity(TagCreateRequest request, TagTypeEntity tagTypeEntity, TagEntity parentTagEntity) { TagEntity tagEntity = new TagEntity(); tagEntity.setTagType(tagTypeEntity); tagEntity.setTagCode(request.getTagKey().getTagCode()); tagEntity.setDisplayName(request.getDisplayName()); tagEntity.setDescription(request.getDescription()); tagEntity.setParentTagEntity(parentTagEntity); return tagDao.saveAndRefresh(tagEntity); } /** * Creates the tag from the persisted entity. * * @param tagEntity the tag entity * * @return the tag */ private Tag createTagFromEntity(TagEntity tagEntity) { return createTagFromEntity(tagEntity, true, true, true, true, true, true, true, false); } /** * Creates the tag from the persisted entity. * * @param tagEntity the tag entity * @param includeId specifies to include the display name field * @param includeDisplayName specifies to include the display name field * @param includeDescription specifies to include the description field * @param includeUserId specifies to include the user id of the user who created this tag * @param includeLastUpdatedByUserId specifies to include the user id of the user who last updated this tag * @param includeUpdatedTime specifies to include the timestamp of when this tag is last updated * @param includeParentTagKey specifies to include the parent tag key field * @param includeHasChildren specifies to include the hasChildren field * * @return the tag */ private Tag createTagFromEntity(TagEntity tagEntity, boolean includeId, boolean includeDisplayName, boolean includeDescription, boolean includeUserId, boolean includeLastUpdatedByUserId, boolean includeUpdatedTime, boolean includeParentTagKey, boolean includeHasChildren) { Tag tag = new Tag(); if (includeId) { tag.setId(tagEntity.getId()); } tag.setTagKey(new TagKey(tagEntity.getTagType().getCode(), tagEntity.getTagCode())); if (includeDisplayName) { tag.setDisplayName(tagEntity.getDisplayName()); } if (includeDescription) { tag.setDescription(tagEntity.getDescription()); } if (includeUserId) { tag.setUserId(tagEntity.getCreatedBy()); } if (includeLastUpdatedByUserId) { tag.setLastUpdatedByUserId(tagEntity.getUpdatedBy()); } if (includeUpdatedTime) { tag.setUpdatedTime(HerdDateUtils.getXMLGregorianCalendarValue(tagEntity.getUpdatedOn())); } if (includeParentTagKey) { TagEntity parentTagEntity = tagEntity.getParentTagEntity(); if (parentTagEntity != null) { tag.setParentTagKey(new TagKey(parentTagEntity.getTagType().getCode(), parentTagEntity.getTagCode())); } } if (includeHasChildren) { tag.setHasChildren(!tagEntity.getChildrenTagEntities().isEmpty()); } return tag; } /** * Private method to convert a tag entity list to a list of JSON strings. * * @param tagEntities the list of tags * * @return Map of key, business object definition ids, and value, business object definition entity as JSON string */ private Map<String, String> convertTagEntityListToJSONStringMap(List<TagEntity> tagEntities) { Map<String, String> tagJSONMap = new HashMap<>(); tagEntities.forEach(tagEntity -> { String jsonString = tagHelper.safeObjectMapperWriteValueAsString(tagEntity); if (StringUtils.isNotEmpty(jsonString)) { tagJSONMap.put(tagEntity.getId().toString(), jsonString); } }); return tagJSONMap; } /** * Updates and persists the tag entity per the specified update request. * * @param tagEntity the tag entity * @param request the tag update request * @param parentTagEntity the parent tag entity, maybe null */ private void updateTagEntity(TagEntity tagEntity, TagUpdateRequest request, TagEntity parentTagEntity) { tagEntity.setDisplayName(request.getDisplayName()); tagEntity.setDescription(request.getDescription()); tagEntity.setParentTagEntity(parentTagEntity); tagDao.saveAndRefresh(tagEntity); } /** * Validate the tag create request. This method also trims the request parameters. * * @param request the tag create request */ private void validateTagCreateRequest(TagCreateRequest request) { Assert.notNull(request, "A tag create request must be specified."); tagHelper.validateTagKey(request.getTagKey()); if (request.getParentTagKey() != null) { tagHelper.validateTagKey(request.getParentTagKey()); tagDaoHelper.validateParentTagType(request.getTagKey().getTagTypeCode(), request.getParentTagKey().getTagTypeCode()); } request.setDisplayName(alternateKeyHelper.validateStringParameter("display name", request.getDisplayName())); } /** * Validate the tag search request. This method also trims the request parameters. * * @param tagSearchRequest the tag search request */ private void validateTagSearchRequest(TagSearchRequest tagSearchRequest) { Assert.notNull(tagSearchRequest, "A tag search request must be specified."); // Continue validation if the list of tag search filters is not empty. if (CollectionUtils.isNotEmpty(tagSearchRequest.getTagSearchFilters()) && tagSearchRequest.getTagSearchFilters().get(0) != null) { // Validate that there is only one tag search filter. Assert.isTrue(CollectionUtils.size(tagSearchRequest.getTagSearchFilters()) == 1, "At most one tag search filter must be specified."); // Get the tag search filter. TagSearchFilter tagSearchFilter = tagSearchRequest.getTagSearchFilters().get(0); // Validate that exactly one tag search key is specified. Assert.isTrue(CollectionUtils.size(tagSearchFilter.getTagSearchKeys()) == 1 && tagSearchFilter.getTagSearchKeys().get(0) != null, "Exactly one tag search key must be specified."); // Get the tag search key. TagSearchKey tagSearchKey = tagSearchFilter.getTagSearchKeys().get(0); tagSearchKey.setTagTypeCode(alternateKeyHelper.validateStringParameter("tag type code", tagSearchKey.getTagTypeCode())); if (tagSearchKey.getParentTagCode() != null) { tagSearchKey.setParentTagCode(tagSearchKey.getParentTagCode().trim()); } // Fail validation when parent tag code is specified along with the isParentTagNull flag set to true. Assert.isTrue(StringUtils.isBlank(tagSearchKey.getParentTagCode()) || BooleanUtils.isNotTrue(tagSearchKey.isIsParentTagNull()), "A parent tag code can not be specified when isParentTagNull flag is set to true."); } } /** * Validates the tag update request. This method also trims the request parameters. * * @param tagKey the tag key * @param request the specified tag update request */ private void validateTagUpdateRequest(TagKey tagKey, TagUpdateRequest request) { Assert.notNull(request, "A tag update request must be specified."); if (request.getParentTagKey() != null) { tagHelper.validateTagKey(request.getParentTagKey()); tagDaoHelper.validateParentTagType(tagKey.getTagTypeCode(), request.getParentTagKey().getTagTypeCode()); } request.setDisplayName(alternateKeyHelper.validateStringParameter("display name", request.getDisplayName())); } @Override public boolean indexSizeCheckValidationTags() { final String indexName = SearchIndexTypeEntity.SearchIndexTypes.TAG.name().toLowerCase(); final String documentType = configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_BDEF_DOCUMENT_TYPE, String.class); // Simple count validation, index size should equal entity list size final long indexSize = searchFunctions.getNumberOfTypesInIndexFunction().apply(indexName, documentType); final long tagDatabaseTableSize = tagDao.getCountOfAllTags(); if (tagDatabaseTableSize != indexSize) { LOGGER.error("Index validation failed, tag database table size {}, does not equal index size {}.", tagDatabaseTableSize, indexSize); } return tagDatabaseTableSize == indexSize; } @Override public boolean indexSpotCheckPercentageValidationTags() { final Double spotCheckPercentage = configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_TAG_SPOT_CHECK_PERCENTAGE, Double.class); // Get a list of all tags final List<TagEntity> tagEntityList = Collections.unmodifiableList(tagDao.getPercentageOfAllTags(spotCheckPercentage)); return indexValidateTagsList(tagEntityList); } @Override public boolean indexSpotCheckMostRecentValidationTags() { final Integer spotCheckMostRecentNumber = configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_TAG_SPOT_CHECK_MOST_RECENT_NUMBER, Integer.class); // Get a list of all tags final List<TagEntity> tagEntityList = Collections.unmodifiableList(tagDao.getMostRecentTags(spotCheckMostRecentNumber)); return indexValidateTagsList(tagEntityList); } @Override @Async public Future<Void> indexValidateAllTags() { final String indexName = SearchIndexTypeEntity.SearchIndexTypes.TAG.name().toLowerCase(); final String documentType = configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_BDEF_DOCUMENT_TYPE, String.class); // Get a list of all tags final List<TagEntity> tagEntityList = Collections.unmodifiableList(tagDao.getTags()); // Remove any index documents that are not in the database removeAnyIndexDocumentsThatAreNotInTagsList(indexName, documentType, tagEntityList); // Validate all Tags tagHelper.executeFunctionForTagEntities(indexName, documentType, tagEntityList, searchFunctions.getValidateFunction()); // Return an AsyncResult so callers will know the future is "done". They can call "isDone" to know when this method has completed and they // can call "get" to see if any exceptions were thrown. return new AsyncResult<>(null); } /** * Method to remove tags in the index that don't exist in the database * * @param indexName the name of the index * @param documentType the document type * @param tagEntityList list of tags in the database */ private void removeAnyIndexDocumentsThatAreNotInTagsList(final String indexName, final String documentType, List<TagEntity> tagEntityList) { // Get a list of tag ids from the list of tag entities in the database List<String> databaseTagIdList = new ArrayList<>(); tagEntityList.forEach(tagEntity -> databaseTagIdList.add(tagEntity.getId().toString())); // Get a list of tag ids in the search index List<String> indexDocumentTagIdList = searchFunctions.getIdsInIndexFunction().apply(indexName, documentType); // Remove the database ids from the index ids indexDocumentTagIdList.removeAll(databaseTagIdList); // If there are any ids left in the index list they need to be removed indexDocumentTagIdList.forEach(id -> searchFunctions.getDeleteDocumentByIdFunction().accept(indexName, documentType, id)); } /** * A helper method that will validate a list of tags * * @param tagEntityList the list of tags that will be validated * * @return true all of the tags are valid in the index */ private boolean indexValidateTagsList(final List<TagEntity> tagEntityList) { final String indexName = SearchIndexTypeEntity.SearchIndexTypes.TAG.name().toLowerCase(); final String documentType = configurationHelper.getProperty(ConfigurationValue.ELASTICSEARCH_BDEF_DOCUMENT_TYPE, String.class); Predicate<TagEntity> validInIndexPredicate = tagEntity -> { // Fetch Join with .size() tagEntity.getChildrenTagEntities().size(); // Convert the tag entity to a JSON string final String jsonString = tagHelper.safeObjectMapperWriteValueAsString(tagEntity); return searchFunctions.getIsValidFunction().test(indexName, documentType, tagEntity.getId().toString(), jsonString); }; boolean isValid = true; for (TagEntity tagEntity : tagEntityList) { if (!validInIndexPredicate.test(tagEntity)) { isValid = false; } } return isValid; } }