package com.thinkbiganalytics.feedmgr.service.feed; /*- * #%L * thinkbig-feed-manager-controller * %% * Copyright (C) 2017 ThinkBig Analytics * %% * 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. * #L% */ import com.fasterxml.jackson.annotation.JsonIgnore; import com.google.common.collect.Sets; import com.thinkbiganalytics.feedmgr.MetadataFieldAnnotationFieldNameResolver; import com.thinkbiganalytics.feedmgr.nifi.PropertyExpressionResolver; import com.thinkbiganalytics.feedmgr.rest.ImportComponent; import com.thinkbiganalytics.feedmgr.rest.ImportSection; import com.thinkbiganalytics.feedmgr.rest.ImportType; import com.thinkbiganalytics.feedmgr.rest.model.FeedCategory; import com.thinkbiganalytics.feedmgr.rest.model.FeedDataTransformation; import com.thinkbiganalytics.feedmgr.rest.model.FeedMetadata; import com.thinkbiganalytics.feedmgr.rest.model.ImportComponentOption; import com.thinkbiganalytics.feedmgr.rest.model.ImportFeedOptions; import com.thinkbiganalytics.feedmgr.rest.model.ImportOptions; import com.thinkbiganalytics.feedmgr.rest.model.ImportProperty; import com.thinkbiganalytics.feedmgr.rest.model.ImportTemplateOptions; import com.thinkbiganalytics.feedmgr.rest.model.NifiFeed; import com.thinkbiganalytics.feedmgr.rest.model.RegisteredTemplate; import com.thinkbiganalytics.feedmgr.rest.model.UploadProgress; import com.thinkbiganalytics.feedmgr.rest.model.UploadProgressMessage; import com.thinkbiganalytics.feedmgr.security.FeedServicesAccessControl; import com.thinkbiganalytics.feedmgr.service.MetadataService; import com.thinkbiganalytics.feedmgr.service.UploadProgressService; import com.thinkbiganalytics.feedmgr.service.datasource.DatasourceModelTransform; import com.thinkbiganalytics.feedmgr.service.template.ExportImportTemplateService; import com.thinkbiganalytics.feedmgr.service.template.RegisteredTemplateService; import com.thinkbiganalytics.feedmgr.support.ZipFileUtil; import com.thinkbiganalytics.feedmgr.util.ImportUtil; import com.thinkbiganalytics.json.ObjectMapperSerializer; import com.thinkbiganalytics.metadata.api.MetadataAccess; import com.thinkbiganalytics.metadata.api.category.Category; import com.thinkbiganalytics.metadata.api.category.CategoryProvider; import com.thinkbiganalytics.metadata.api.category.security.CategoryAccessControl; import com.thinkbiganalytics.metadata.api.datasource.DatasourceProvider; import com.thinkbiganalytics.metadata.api.datasource.UserDatasource; import com.thinkbiganalytics.metadata.api.feed.Feed; import com.thinkbiganalytics.metadata.api.feed.security.FeedAccessControl; import com.thinkbiganalytics.metadata.rest.model.data.Datasource; import com.thinkbiganalytics.nifi.rest.model.NifiProperty; import com.thinkbiganalytics.nifi.rest.support.NifiProcessUtil; import com.thinkbiganalytics.nifi.rest.support.NifiPropertyUtil; import com.thinkbiganalytics.policy.PolicyPropertyTypes; import com.thinkbiganalytics.security.AccessController; import com.thinkbiganalytics.support.FeedNameUtil; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import javax.annotation.Nonnull; import javax.inject.Inject; import javax.ws.rs.NotFoundException; /** * Service used to export and import feeds */ public class ExportImportFeedService { private static final Logger log = LoggerFactory.getLogger(ExportImportFeedService.class); public static final String FEED_JSON_FILE = "feed.json"; @Inject MetadataService metadataService; @Inject CategoryProvider categoryProvider; @Inject MetadataAccess metadataAccess; @Inject ExportImportTemplateService exportImportTemplateService; @Inject private AccessController accessController; @Inject private UploadProgressService uploadProgressService; /** * Provides access to {@code Datasource} objects. */ @Inject private DatasourceProvider datasourceProvider; /** * The {@code Datasource} transformer */ @Inject private DatasourceModelTransform datasourceTransform; @Inject private RegisteredTemplateService registeredTemplateService; //Export /** * Export a feed as a zip file * * @param feedId the id {@link Feed#getId()} of the feed to export * @return object containing the zip file with data about the feed. */ public ExportFeed exportFeed(String feedId) throws IOException { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.EXPORT_FEEDS); this.metadataService.checkFeedPermission(feedId, FeedAccessControl.EXPORT); // Prepare feed metadata final FeedMetadata feed = metadataService.getFeedById(feedId); if (feed == null) { //feed will not be found when user is allowed to export feeds but has no entity access to feed with feed id throw new NotFoundException("Feed not found for id " + feedId); } final List<Datasource> userDatasources = Optional.ofNullable(feed.getDataTransformation()) .map(FeedDataTransformation::getDatasourceIds) .map(datasourceIds -> metadataAccess.read( () -> datasourceIds.stream() .map(datasourceProvider::resolve) .map(datasourceProvider::getDatasource) .map(domain -> datasourceTransform.toDatasource(domain, DatasourceModelTransform.Level.FULL)) .map(datasource -> { // Clear sensitive fields datasource.getDestinationForFeeds().clear(); datasource.getSourceForFeeds().clear(); return datasource; }) .collect(Collectors.toList()) ) ) .orElse(null); if (userDatasources != null && !userDatasources.isEmpty()) { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_DATASOURCES); feed.setUserDatasources(userDatasources); } // Add feed json to template zip file final ExportImportTemplateService.ExportTemplate exportTemplate = exportImportTemplateService.exportTemplate(feed.getTemplateId()); final String feedJson = ObjectMapperSerializer.serialize(feed); final byte[] zipFile = ZipFileUtil.addToZip(exportTemplate.getFile(), feedJson, FEED_JSON_FILE); return new ExportFeed(feed.getSystemFeedName() + ".feed.zip", zipFile); } //Validate /** * Validate a feed for importing * * @param fileName the name of the file to import * @param content the contents of the feed zip file * @param options user options about what/how it should be imported * @return the feed data to import */ public ImportFeed validateFeedForImport(final String fileName, byte[] content, ImportFeedOptions options) throws IOException { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.IMPORT_FEEDS); ImportFeed importFeed = null; UploadProgressMessage feedImportStatusMessage = uploadProgressService.addUploadStatus(options.getUploadKey(), "Validating Feed import."); boolean isValid = ZipFileUtil.validateZipEntriesWithRequiredEntries(content, getValidZipFileEntries(), Sets.newHashSet(FEED_JSON_FILE)); if (!isValid) { feedImportStatusMessage.update("Validation error. Feed import error. The zip file you uploaded is not valid feed export.", false); throw new ImportFeedException("The zip file you uploaded is not valid feed export."); } try { //get the Feed Data importFeed = readFeedJson(fileName, content); //initially mark as valid. importFeed.setValid(true); //merge in the file components to the user options Set<ImportComponentOption> componentOptions = ImportUtil.inspectZipComponents(content, ImportType.FEED); options.addOptionsIfNotExists(componentOptions); importFeed.setImportOptions(options); //validate the import //read the JSON into the Feed object FeedMetadata metadata = importFeed.getFeedToImport(); //validate the incoming category exists validateFeedCategory(importFeed, options, metadata); //verify if we should overwrite the feed if it already exists String feedCategory = StringUtils.isNotBlank(options.getCategorySystemName()) ? options.getCategorySystemName() : metadata.getSystemCategoryName(); //query for this feed. //first read in the feed as a service account FeedMetadata existingFeed = metadataAccess.read(() -> { return metadataService.getFeedByName(feedCategory, metadata.getSystemFeedName()); },MetadataAccess.SERVICE); if (!validateOverwriteExistingFeed(existingFeed, metadata, importFeed)) { //exit return importFeed; } if(accessController.isEntityAccessControlled()){ if(!validateEntityAccess(existingFeed,feedCategory,metadata,importFeed)){ return importFeed; } } //sensitive properties if (!validateSensitiveProperties(metadata, importFeed, options)) { return importFeed; } // Valid data sources if (!validateUserDatasources(metadata, importFeed, options)) { return importFeed; } //UploadProgressMessage statusMessage = uploadProgressService.addUploadStatus(options.getUploadKey(),"Validating the template data"); ExportImportTemplateService.ImportTemplate importTemplate = exportImportTemplateService.validateTemplateForImport(importFeed.getFileName(), content, options); // need to set the importOptions back to the feed options //find importOptions for the Template and add them back to the set of options //importFeed.getImportOptions().updateOptions(importTemplate.getImportOptions().getImportComponentOptions()); importFeed.setTemplate(importTemplate); // statusMessage.update("Validated the template data",importTemplate.isValid()); if (!importTemplate.isValid()) { importFeed.setValid(false); List<String> errorMessages = importTemplate.getTemplateResults().getAllErrors().stream().map(nifiError -> nifiError.getMessage()).collect(Collectors.toList()); if (!errorMessages.isEmpty()) { for (String msg : errorMessages) { importFeed.addErrorMessage(metadata, msg); } } } // statusMessage = uploadProgressService.addUploadStatus(options.getUploadKey(),"Validation complete: the feed is "+(importFeed.isValid() ? "valid" : "invalid"),true,importFeed.isValid()); } catch (Exception e) { feedImportStatusMessage.update("Validation error. Feed import error: " + e.getMessage(), false); throw new UnsupportedOperationException("Error importing template " + fileName + ". " + e.getMessage()); } feedImportStatusMessage.update("Validated Feed import.", importFeed.isValid()); return importFeed; } private Set<String> getValidZipFileEntries() { // do not include nifiConnectingReusableTemplate.xml - it may or may not be there or there can be many of them if flow connects to multiple reusable templates String[] entries = { FEED_JSON_FILE, ExportImportTemplateService.NIFI_TEMPLATE_XML_FILE, ExportImportTemplateService.TEMPLATE_JSON_FILE }; return Sets.newHashSet(entries); } private boolean validateSensitiveProperties(FeedMetadata metadata, ImportFeed importFeed, ImportFeedOptions importOptions) { //detect any sensitive properties and prompt for input before proceeding UploadProgressMessage statusMessage = uploadProgressService.addUploadStatus(importFeed.getImportOptions().getUploadKey(), "Validating feed properties."); List<NifiProperty> sensitiveProperties = metadata.getSensitiveProperties(); ImportUtil.addToImportOptionsSensitiveProperties(importOptions, sensitiveProperties, ImportComponent.FEED_DATA); boolean valid = ImportUtil.applyImportPropertiesToFeed(metadata, importFeed, ImportComponent.FEED_DATA); if (!valid) { statusMessage.update("Validation Error. Additional properties are needed before uploading the feed.", false); importFeed.setValid(false); } else { statusMessage.update("Validated feed properties.", valid); } completeSection(importFeed.getImportOptions(), ImportSection.Section.VALIDATE_PROPERTIES); return valid; } /** * Validates that user data sources can be imported with provided properties. * * @param metadata the feed data * @param importFeed the import request * @param importOptions the import options * @return {@code true} if the feed can be imported, or {@code false} otherwise */ private boolean validateUserDatasources(@Nonnull final FeedMetadata metadata, @Nonnull final ImportFeed importFeed, @Nonnull final ImportFeedOptions importOptions) { final UploadProgressMessage statusMessage = uploadProgressService.addUploadStatus(importFeed.getImportOptions().getUploadKey(), "Validating data sources."); // Get data sources needing to be created final Set<String> availableDatasources = metadataAccess.read( () -> datasourceProvider.getDatasources(datasourceProvider.datasetCriteria().type(UserDatasource.class)).stream() .map(com.thinkbiganalytics.metadata.api.datasource.Datasource::getId) .map(Object::toString) .collect(Collectors.toSet()) ); final ImportComponentOption componentOption = importOptions.findImportComponentOption(ImportComponent.USER_DATASOURCES); final List<Datasource> providedDatasources = Optional.ofNullable(metadata.getUserDatasources()).orElse(Collections.emptyList()); if (componentOption.getProperties().isEmpty()) { componentOption.setProperties( providedDatasources.stream() .filter(datasource -> !availableDatasources.contains(datasource.getId())) .map(datasource -> new ImportProperty(datasource.getName(), datasource.getId(), null, null, null)) .collect(Collectors.toList()) ); } // Update feed with re-mapped data sources final boolean valid = componentOption.getProperties().stream() .allMatch(property -> { if (property.getPropertyValue() != null) { ImportUtil.replaceDatasource(metadata, property.getProcessorId(), property.getPropertyValue()); return true; } else { return false; } }); if (valid) { statusMessage.update("Validated data sources.", true); } else { statusMessage.update("Validation Error. Additional properties are needed before uploading the feed.", false); importFeed.setValid(false); } completeSection(importFeed.getImportOptions(), ImportSection.Section.VALIDATE_USER_DATASOURCES); return valid; } private boolean validateEntityAccess(FeedMetadata existingFeed, String feedCategory,FeedMetadata importingFeed, ImportFeed feed) { if(existingFeed != null ) { FeedMetadata userAccessFeed = metadataAccess.read(() -> { return metadataService.getFeedByName(feedCategory, importingFeed.getSystemFeedName()); }); if(userAccessFeed == null || !userAccessFeed.hasAction(FeedAccessControl.EDIT_DETAILS.getSystemName())){ //error feed.setValid(false); if(feed.getTemplate() == null) { ExportImportTemplateService.ImportTemplate importTemplate = new ExportImportTemplateService.ImportTemplate(feed.getFileName()); feed.setTemplate(importTemplate); } String msg = "Access Denied. You do not have access to edit this feed."; feed.getImportOptions().addErrorMessage(ImportComponent.FEED_DATA, msg); feed.addErrorMessage(existingFeed, msg); feed.setValid(false); return false; } else { return true; } } else { //ensure the user can create under the category Category category = metadataAccess.read(() -> { return categoryProvider.findBySystemName(feedCategory); }, MetadataAccess.SERVICE); if(category == null) { //ensure the user has functional access to create categories boolean hasPermission = accessController.hasPermission(AccessController.SERVICES,FeedServicesAccessControl.EDIT_CATEGORIES); if(!hasPermission) { String msg = "Access Denied. The category for this feed,"+feedCategory+", doesn't exist and you do not have access to create a new category."; feed.getImportOptions().addErrorMessage(ImportComponent.FEED_DATA, msg); feed.addErrorMessage(existingFeed, msg); feed.setValid(false); return false; } return true; } else { //if the feed is new ensure the user has write access to create feeds under this category return metadataAccess.read(() -> { Category domainCategory = categoryProvider.findBySystemName(feedCategory); //Query for Category and ensure the user has access to create feeds on that category if (domainCategory == null || (!domainCategory.getAllowedActions().hasPermission(CategoryAccessControl.CREATE_FEED))) { String msg = "Access Denied. You do not have access to create feeds under the category " + FeedNameUtil.fullName(feedCategory, importingFeed.getSystemFeedName()) + "."; feed.getImportOptions().addErrorMessage(ImportComponent.FEED_DATA, msg); feed.addErrorMessage(existingFeed, msg); feed.setValid(false); return false; } else { return true; } }); } } } private boolean validateOverwriteExistingFeed(FeedMetadata existingFeed, FeedMetadata importingFeed, ImportFeed feed) { if (existingFeed != null && !feed.getImportOptions().isImportAndOverwrite(ImportComponent.FEED_DATA)) { UploadProgressMessage statusMessage = uploadProgressService.addUploadStatus(feed.getImportOptions().getUploadKey(), "Validation error. " + importingFeed.getCategoryAndFeedName() + " already exists.", true, false); //if we dont have permission to overwrite then return with error that feed already exists feed.setValid(false); ExportImportTemplateService.ImportTemplate importTemplate = new ExportImportTemplateService.ImportTemplate(feed.getFileName()); feed.setTemplate(importTemplate); String msg = "The feed " + existingFeed.getCategoryAndFeedName() + " already exists."; feed.getImportOptions().addErrorMessage(ImportComponent.FEED_DATA, msg); feed.addErrorMessage(existingFeed, msg); feed.setValid(false); return false; } else { String message = "Validated Feed data. This import will " + (existingFeed != null ? "overwrite" : "create") + " the feed " + importingFeed.getCategoryAndFeedName(); uploadProgressService.addUploadStatus(feed.getImportOptions().getUploadKey(), message, true, true); } completeSection(feed.getImportOptions(), ImportSection.Section.VALIDATE_FEED); return true; } private boolean validateFeedCategory(ImportFeed importFeed, ImportFeedOptions importOptions, FeedMetadata metadata) { boolean valid = true; if (StringUtils.isNotBlank(importOptions.getCategorySystemName())) { UploadProgressMessage statusMessage = uploadProgressService.addUploadStatus(importOptions.getUploadKey(), "Validating the newly specified category. Ensure " + importOptions.getCategorySystemName() + " exists."); FeedCategory optionsCategory = metadataService.getCategoryBySystemName(importOptions.getCategorySystemName()); if (optionsCategory == null) { importFeed.setValid(false); statusMessage.update("Validation Error. The category " + importOptions.getCategorySystemName() + " does not exist, or you dont have access to it.", false); valid = false; } else { if (valid) { metadata.getCategory().setSystemName(importOptions.getCategorySystemName()); statusMessage.update("Validated. The category " + importOptions.getCategorySystemName() + " exists.", true); } } } completeSection(importOptions, ImportSection.Section.VALIDATE_FEED_CATEGORY); return valid; } //Import /** * Import a feed zip file * * @param fileName the name of the file * @param content the file content * @param importOptions user options about what/how it should be imported * @return the feed data to import */ public ImportFeed importFeed(String fileName, byte[] content, ImportFeedOptions importOptions) throws Exception { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.IMPORT_FEEDS); UploadProgress progress = uploadProgressService.getUploadStatus(importOptions.getUploadKey()); progress.setSections(ImportSection.sectionsForImportAsString(ImportType.FEED)); ImportFeed feed = validateFeedForImport(fileName, content, importOptions); if (feed.isValid()) { //read the JSON into the Feed object FeedMetadata metadata = feed.getFeedToImport(); //query for this feed. String feedCategory = StringUtils.isNotBlank(importOptions.getCategorySystemName()) ? importOptions.getCategorySystemName() : metadata.getSystemCategoryName(); FeedMetadata existingFeed = metadataAccess.read(() -> metadataService.getFeedByName(feedCategory, metadata.getSystemFeedName())); metadata.getCategory().setSystemName(feedCategory); ImportTemplateOptions importTemplateOptions = new ImportTemplateOptions(); importTemplateOptions.setImportComponentOptions(importOptions.getImportComponentOptions()); importTemplateOptions.findImportComponentOption(ImportComponent.TEMPLATE_DATA).setContinueIfExists(true); ExportImportTemplateService.ImportTemplate importTemplate = feed.getTemplate(); importTemplate.setImportOptions(importTemplateOptions); importTemplateOptions.setUploadKey(importOptions.getUploadKey()); importTemplate.setValid(true); ExportImportTemplateService.ImportTemplate template = exportImportTemplateService.importZip(importTemplate); if (template.isSuccess()) { //import the feed feed.setTemplate(template); //now that we have the Feed object we need to create the instance of the feed UploadProgressMessage uploadProgressMessage = uploadProgressService.addUploadStatus(importOptions.getUploadKey(), "Saving and creating feed instance in NiFi"); metadata.setIsNew(existingFeed == null ? true : false); metadata.setFeedId(existingFeed != null ? existingFeed.getFeedId() : null); metadata.setId(existingFeed != null ? existingFeed.getId() : null); //reassign the templateId to the newly registered template id metadata.setTemplateId(template.getTemplateId()); if (metadata.getRegisteredTemplate() != null) { metadata.getRegisteredTemplate().setNifiTemplateId(template.getNifiTemplateId()); metadata.getRegisteredTemplate().setId(template.getTemplateId()); } //get/create category FeedCategory category = metadataService.getCategoryBySystemName(metadata.getCategory().getSystemName()); if (category == null) { metadata.getCategory().setId(null); metadataService.saveCategory(metadata.getCategory()); } else { metadata.setCategory(category); } if (importOptions.isDisableUponImport()) { metadata.setActive(false); metadata.setState(FeedMetadata.STATE.DISABLED.name()); } //remap any preconditions to this new feed/category name. if (metadata.getSchedule().hasPreconditions()) { metadata.getSchedule().getPreconditions().stream() .flatMap(preconditionRule -> preconditionRule.getProperties().stream()) .filter(fieldRuleProperty -> PolicyPropertyTypes.PROPERTY_TYPE.currentFeed.name().equals(fieldRuleProperty.getType())) .forEach(fieldRuleProperty -> fieldRuleProperty.setValue(metadata.getCategoryAndFeedName())); } ////for all those properties where the template value is != userEditable and the template value has a metadata. property, remove that property from the feed properties so it can be imported and assigned correctly RegisteredTemplate template1 = registeredTemplateService.findRegisteredTemplateById(template.getTemplateId()); if (template1 != null) { //Find all the properties in the template that have ${metadata. and are not userEditable. //These are the properties we need to replace on the feed metadata List<NifiProperty> metadataProperties = template1.getProperties().stream().filter(nifiProperty -> { return nifiProperty != null && StringUtils.isNotBlank(nifiProperty.getValue()) && !nifiProperty.isUserEditable() && nifiProperty.getValue().contains("${" + MetadataFieldAnnotationFieldNameResolver.metadataPropertyPrefix); }).collect(Collectors.toList()); //Replace the Feed Metadata properties with those that match the template ones from above. List<NifiProperty> updatedProperties = metadata.getProperties().stream().map(nifiProperty -> { NifiProperty p = NifiPropertyUtil.findPropertyByProcessorName(metadataProperties, nifiProperty); return p != null ? p : nifiProperty; }).collect(Collectors.toList()); metadata.setProperties(updatedProperties); } NifiFeed nifiFeed = metadataService.createFeed(metadata); if (nifiFeed != null) { feed.setFeedName(nifiFeed.getFeedMetadata().getCategoryAndFeedName()); uploadProgressMessage.update("Successfully saved the feed " + feed.getFeedName(), true); } feed.setNifiFeed(nifiFeed); feed.setSuccess(nifiFeed != null && nifiFeed.isSuccess()); } else { feed.setSuccess(false); feed.setTemplate(template); feed.addErrorMessage(existingFeed, "The feed " + FeedNameUtil.fullName(feedCategory, metadata.getSystemFeedName()) + " needs additional properties to be supplied before importing."); } completeSection(importOptions, ImportSection.Section.IMPORT_FEED_DATA); } return feed; } //Utility private void completeSection(ImportOptions options, ImportSection.Section section) { UploadProgress progress = uploadProgressService.getUploadStatus(options.getUploadKey()); progress.completeSection(section.name()); } private ImportFeed readFeedJson(String fileName, byte[] content) throws IOException { byte[] buffer = new byte[1024]; InputStream inputStream = new ByteArrayInputStream(content); ZipInputStream zis = new ZipInputStream(inputStream); ZipEntry zipEntry; // while there are entries I process them ImportFeed importFeed = new ImportFeed(fileName); while ((zipEntry = zis.getNextEntry()) != null) { if (zipEntry.getName().startsWith(FEED_JSON_FILE)) { String zipEntryContents = ZipFileUtil.zipEntryToString(buffer, zis, zipEntry); importFeed.setFeedJson(zipEntryContents); } } return importFeed; } //Internal classes public class ExportFeed { private String fileName; private byte[] file; public ExportFeed(String fileName, byte[] file) { this.fileName = fileName; this.file = file; } public String getFileName() { return fileName; } public byte[] getFile() { return file; } } public static class ImportFeed { private boolean valid; private boolean success; private String fileName; private String feedName; private ExportImportTemplateService.ImportTemplate template; private NifiFeed nifiFeed; private String feedJson; private ImportFeedOptions importOptions; @JsonIgnore private FeedMetadata feedToImport; public ImportFeed() { } public ImportFeed(String fileName) { this.fileName = fileName; this.template = new ExportImportTemplateService.ImportTemplate(fileName); } public String getFeedJson() { return feedJson; } public void setFeedJson(String feedJson) { this.feedJson = feedJson; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public ExportImportTemplateService.ImportTemplate getTemplate() { return template; } public void setTemplate(ExportImportTemplateService.ImportTemplate template) { this.template = template; } public String getFeedName() { return feedName; } public void setFeedName(String feedName) { this.feedName = feedName; } public NifiFeed getNifiFeed() { return nifiFeed; } public void setNifiFeed(NifiFeed nifiFeed) { this.nifiFeed = nifiFeed; } public boolean isValid() { return valid; } public void setValid(boolean valid) { this.valid = valid; } public boolean isSuccess() { return success; } public void setSuccess(boolean success) { this.success = success; } public void addErrorMessage(FeedMetadata feedMetadata, String errorMessage) { if (nifiFeed == null) { nifiFeed = new NifiFeed(feedMetadata, null); } nifiFeed.addErrorMessage(errorMessage); } public ImportFeedOptions getImportOptions() { return importOptions; } public void setImportOptions(ImportFeedOptions importOptions) { this.importOptions = importOptions; } @JsonIgnore public FeedMetadata getFeedToImport() { if (feedToImport == null && StringUtils.isNotBlank(feedJson)) { feedToImport = ObjectMapperSerializer.deserialize(getFeedJson(), FeedMetadata.class); } return feedToImport; } @JsonIgnore public void setFeedToImport(FeedMetadata feedToImport) { this.feedToImport = feedToImport; } } }