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.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.thinkbiganalytics.feedmgr.rest.model.FeedCategory;
import com.thinkbiganalytics.feedmgr.rest.model.FeedMetadata;
import com.thinkbiganalytics.feedmgr.rest.model.FeedSummary;
import com.thinkbiganalytics.feedmgr.rest.model.RegisteredTemplate;
import com.thinkbiganalytics.feedmgr.rest.model.Tag;
import com.thinkbiganalytics.feedmgr.rest.model.UserProperty;
import com.thinkbiganalytics.feedmgr.service.AccessControlledEntityTransform;
import com.thinkbiganalytics.feedmgr.service.EncryptionService;
import com.thinkbiganalytics.feedmgr.service.UserPropertyTransform;
import com.thinkbiganalytics.feedmgr.service.category.CategoryModelTransform;
import com.thinkbiganalytics.feedmgr.service.template.TemplateModelTransform;
import com.thinkbiganalytics.hive.service.HiveService;
import com.thinkbiganalytics.json.ObjectMapperSerializer;
import com.thinkbiganalytics.metadata.api.category.Category;
import com.thinkbiganalytics.metadata.api.category.CategoryProvider;
import com.thinkbiganalytics.metadata.api.extension.UserFieldDescriptor;
import com.thinkbiganalytics.metadata.api.feed.Feed;
import com.thinkbiganalytics.metadata.api.feed.FeedProvider;
import com.thinkbiganalytics.metadata.api.security.HadoopSecurityGroup;
import com.thinkbiganalytics.metadata.api.security.HadoopSecurityGroupProvider;
import com.thinkbiganalytics.metadata.api.template.FeedManagerTemplate;
import com.thinkbiganalytics.metadata.api.template.FeedManagerTemplateProvider;
import com.thinkbiganalytics.metadata.modeshape.security.JcrHadoopSecurityGroup;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Inject;
/**
* Transforms feeds between Feed Manager and Metadata formats.
*/
public class FeedModelTransform {
@Inject
CategoryProvider categoryProvider;
@Inject
FeedManagerTemplateProvider templateProvider;
@Inject
private FeedProvider feedProvider;
@Inject
private AccessControlledEntityTransform accessControlledEntityTransform;
@Inject
private TemplateModelTransform templateModelTransform;
@Inject
private CategoryModelTransform categoryModelTransform;
@Inject
private HiveService hiveService;
@Inject
private HadoopSecurityGroupProvider hadoopSecurityGroupProvider;
@Inject
private EncryptionService encryptionService;
/**
*
* @param feedMetadata
*/
private void prepareForSave(FeedMetadata feedMetadata) {
if (feedMetadata.getTable() != null) {
feedMetadata.getTable().simplifyFieldPoliciesForSerialization();
}
feedMetadata.setRegisteredTemplate(null);
//reset all those properties that contain config variables back to the string with the config options
feedMetadata.getProperties().stream().filter(property -> property.isContainsConfigurationVariables()).forEach(property -> property.setValue(property.getTemplateValue()));
//reset all sensitive properties
//ensure its encrypted
encryptSensitivePropertyValues(feedMetadata);
}
private void clearSensitivePropertyValues(FeedMetadata feedMetadata) {
feedMetadata.getProperties().stream().filter(property -> property.isSensitive()).forEach(nifiProperty -> nifiProperty.setValue(""));
}
public void encryptSensitivePropertyValues(FeedMetadata feedMetadata) {
List<String> encrypted = new ArrayList<>();
feedMetadata.getSensitiveProperties().stream().forEach(nifiProperty -> {
nifiProperty.setValue(encryptionService.encrypt(nifiProperty.getValue()));
encrypted.add(nifiProperty.getValue());
});
int i = 0;
}
public void decryptSensitivePropertyValues(FeedMetadata feedMetadata) {
List<String> decrypted = new ArrayList<>();
feedMetadata.getProperties().stream().filter(property -> property.isSensitive()).forEach(nifiProperty -> {
try {
String decryptedValue = encryptionService.decrypt(nifiProperty.getValue());
nifiProperty.setValue(decryptedValue);
decrypted.add(decryptedValue);
} catch (Exception e) {
}
});
int i = 0;
}
/**
* Transforms the specified Feed Manager feed to a Metadata feed.
*
* @param feedMetadata the Feed Manager feed
* @return the Metadata feed
*/
@Nonnull
public Feed feedToDomain(@Nonnull final FeedMetadata feedMetadata) {
//resolve the id
Feed.ID domainId = feedMetadata.getId() != null ? feedProvider.resolveId(feedMetadata.getId()) : null;
Feed domain = domainId != null ? feedProvider.findById(domainId) : null;
FeedCategory restCategoryModel = feedMetadata.getCategory();
Category category = null;
if (restCategoryModel != null && (domain == null || domain.getCategory() == null)) {
category = categoryProvider.findById(categoryProvider.resolveId(restCategoryModel.getId()));
}
if (domain == null) {
//ensure the Category exists
if (category == null) {
final String categoryId = (restCategoryModel != null) ? restCategoryModel.getId() : "(null)";
throw new RuntimeException("Category cannot be found while creating feed " + feedMetadata.getSystemFeedName() + ". Category Id is " + categoryId);
}
domain = feedProvider.ensureFeed(category.getId(), feedMetadata.getSystemFeedName());
domainId = domain.getId();
Feed.State state = Feed.State.valueOf(feedMetadata.getState());
domain.setState(state);
//reassign the domain data back to the ui model....
feedMetadata.setFeedId(domainId.toString());
feedMetadata.setState(state.name());
}
domain.setDisplayName(feedMetadata.getFeedName());
domain.setDescription(feedMetadata.getDescription());
feedMetadata.setId(domain.getId().toString());
if (StringUtils.isNotBlank(feedMetadata.getState())) {
Feed.State state = Feed.State.valueOf(feedMetadata.getState().toUpperCase());
domain.setState(state);
}
domain.setNifiProcessGroupId(feedMetadata.getNifiProcessGroupId());
//clear out the state as that
prepareForSave(feedMetadata);
domain.setJson(ObjectMapperSerializer.serialize(feedMetadata));
if (domain.getTemplate() == null) {
FeedManagerTemplate.ID templateId = templateProvider.resolveId(feedMetadata.getTemplateId());
FeedManagerTemplate domainTemplate = templateProvider.findById(templateId);
domain.setTemplate(domainTemplate);
}
// Set user-defined properties
if (feedMetadata.getUserProperties() != null) {
final Set<UserFieldDescriptor> userFields = getUserFields(category);
domain.setUserProperties(UserPropertyTransform.toMetadataProperties(feedMetadata.getUserProperties()), userFields);
}
// Set the hadoop security groups
final List<HadoopSecurityGroup> securityGroups = new ArrayList<>();
if (feedMetadata.getSecurityGroups() != null) {
for (com.thinkbiganalytics.feedmgr.rest.model.HadoopSecurityGroup securityGroup : feedMetadata.getSecurityGroups()) {
JcrHadoopSecurityGroup hadoopSecurityGroup = (JcrHadoopSecurityGroup) hadoopSecurityGroupProvider.ensureSecurityGroup(securityGroup.getName());
hadoopSecurityGroup.setGroupId(securityGroup.getId());
hadoopSecurityGroup.setDescription(securityGroup.getDescription());
securityGroups.add(hadoopSecurityGroup);
}
}
domain.setSecurityGroups(securityGroups);
domain.setVersionName(feedMetadata.getVersionName());
domain.setTags(feedMetadata.getTags().stream().map(Tag::getName).collect(Collectors.toSet()));
return domain;
}
/**
* Transforms the specified Metadata feed to a Feed Manager feed.
*
* @param domain the Metadata feed
* @return the Feed Manager feed
*/
@Nonnull
public FeedMetadata domainToFeedMetadata(@Nonnull final Feed domain) {
return domainToFeedMetadata(domain, null);
}
/**
* Transforms the specified Metadata feeds to Feed Manager feeds.
*
* @param domain the Metadata feeds
* @return the Feed Manager feeds
*/
@Nonnull
public List<FeedMetadata> domainToFeedMetadata(@Nonnull final Collection<? extends Feed> domain) {
final Map<Category, Set<UserFieldDescriptor>> userFieldMap = Maps.newHashMap();
return domain.stream().map(f -> domainToFeedMetadata(f, userFieldMap)).collect(Collectors.toList());
}
public FeedMetadata deserializeFeedMetadata(Feed domain, boolean clearSensitiveProperties) {
String json = domain.getJson();
FeedMetadata feedMetadata = ObjectMapperSerializer.deserialize(json, FeedMetadata.class);
if (clearSensitiveProperties) {
clearSensitivePropertyValues(feedMetadata);
}
return feedMetadata;
}
public FeedMetadata deserializeFeedMetadata(Feed domain) {
return deserializeFeedMetadata(domain, true);
}
/**
* Transforms the specified Metadata feed to a Feed Manager feed.
*
* @param domain the Metadata feed
* @param userFieldMap cache map from category to user-defined fields, or {@code null}
* @return the Feed Manager feed
*/
@Nonnull
private FeedMetadata domainToFeedMetadata(@Nonnull final Feed domain, @Nullable final Map<Category, Set<UserFieldDescriptor>> userFieldMap) {
FeedMetadata feed = deserializeFeedMetadata(domain, false);
feed.setId(domain.getId().toString());
feed.setFeedId(domain.getId().toString());
feed.setTemplateId(domain.getTemplate().getId().toString());
if (domain.getCreatedTime() != null) {
feed.setCreateDate(domain.getCreatedTime().toDate());
}
if (domain.getModifiedTime() != null) {
feed.setUpdateDate(domain.getModifiedTime().toDate());
}
FeedManagerTemplate template = domain.getTemplate();
if (template != null) {
RegisteredTemplate registeredTemplate = templateModelTransform.DOMAIN_TO_REGISTERED_TEMPLATE.apply(template);
feed.setRegisteredTemplate(registeredTemplate);
feed.setTemplateId(registeredTemplate.getId());
}
Category category = domain.getCategory();
if (category != null) {
feed.setCategory(categoryModelTransform.domainToFeedCategorySimple(category));
}
feed.setState(domain.getState() != null ? domain.getState().name() : null);
feed.setVersionName(domain.getVersionName() != null ? domain.getVersionName() : null);
// Set user-defined properties
final Set<UserFieldDescriptor> userFields;
if (userFieldMap == null) {
userFields = getUserFields(category);
} else if (userFieldMap.containsKey(category)) {
userFields = userFieldMap.get(category);
} else {
userFields = getUserFields(category);
userFieldMap.put(category, userFields);
}
@SuppressWarnings("unchecked")
final Set<UserProperty> userProperties = UserPropertyTransform.toUserProperties(domain.getUserProperties(), userFields);
feed.setUserProperties(userProperties);
// Convert JCR securitygroup to DTO
List<com.thinkbiganalytics.feedmgr.rest.model.HadoopSecurityGroup> restSecurityGroups = new ArrayList<>();
if (domain.getSecurityGroups() != null && domain.getSecurityGroups().size() > 0) {
for (Object group : domain.getSecurityGroups()) {
HadoopSecurityGroup hadoopSecurityGroup = (HadoopSecurityGroup) group;
com.thinkbiganalytics.feedmgr.rest.model.HadoopSecurityGroup restSecurityGroup = new com.thinkbiganalytics.feedmgr.rest.model.HadoopSecurityGroup();
restSecurityGroup.setDescription(hadoopSecurityGroup.getDescription());
restSecurityGroup.setId(hadoopSecurityGroup.getGroupId());
restSecurityGroup.setName(hadoopSecurityGroup.getName());
restSecurityGroups.add(restSecurityGroup);
}
}
feed.setSecurityGroups(restSecurityGroups);
if (domain.getUsedByFeeds() != null) {
final List<FeedSummary> usedByFeeds = domain.getUsedByFeeds().stream()
.map(this::domainToFeedSummary)
.collect(Collectors.toList());
feed.setUsedByFeeds(usedByFeeds);
}
//add in access control items
accessControlledEntityTransform.applyAccessControlToRestModel(domain,feed);
return feed;
}
/**
* Transforms the specified Metadata feed to a Feed Manager feed summary.
*
* @param feedManagerFeed the Metadata feed
* @return the Feed Manager feed summary
*/
public FeedSummary domainToFeedSummary(@Nonnull final Feed feedManagerFeed) {
Category category = feedManagerFeed.getCategory();
if (category == null) {
return null;
}
FeedSummary feedSummary = new FeedSummary();
feedSummary.setId(feedManagerFeed.getId().toString());
feedSummary.setFeedId(feedManagerFeed.getId().toString());
feedSummary.setCategoryId(feedManagerFeed.getCategory().getId().toString());
if (feedManagerFeed.getCategory() instanceof Category) {
feedSummary.setCategoryIcon(((Category) feedManagerFeed.getCategory()).getIcon());
feedSummary.setCategoryIconColor(((Category) feedManagerFeed.getCategory()).getIconColor());
}
feedSummary.setCategoryName(feedManagerFeed.getCategory().getDisplayName());
feedSummary.setSystemCategoryName(feedManagerFeed.getCategory().getName());
feedSummary.setUpdateDate(feedManagerFeed.getModifiedTime() != null ? feedManagerFeed.getModifiedTime().toDate() : null);
feedSummary.setFeedName(feedManagerFeed.getDisplayName());
feedSummary.setSystemFeedName(feedManagerFeed.getName());
feedSummary.setActive(feedManagerFeed.getState() != null && feedManagerFeed.getState().equals(Feed.State.ENABLED));
feedSummary.setState(feedManagerFeed.getState() != null ? feedManagerFeed.getState().name() : null);
if (feedManagerFeed instanceof Feed) {
Feed fmf = (Feed) feedManagerFeed;
if (fmf.getTemplate() != null) {
feedSummary.setTemplateId(fmf.getTemplate().getId().toString());
feedSummary.setTemplateName(fmf.getTemplate().getName());
}
}
//add in access control items
accessControlledEntityTransform.applyAccessControlToRestModel(feedManagerFeed, feedSummary);
return feedSummary;
}
/**
* Transforms the specified Metadata feeds to Feed Manager feed summaries.
*
* @param domain the Metadata feed
* @return the Feed Manager feed summaries
*/
@Nonnull
public List<FeedSummary> domainToFeedSummary(@Nonnull final Collection<? extends Feed> domain) {
return domain.stream().map(this::domainToFeedSummary).filter(feedSummary -> feedSummary != null).collect(Collectors.toList());
}
/**
* Gets the user-defined fields including those for the specified category.
*
* @param category the domain category
* @return the user-defined fields
*/
@Nonnull
private Set<UserFieldDescriptor> getUserFields(@Nullable final Category category) {
final Set<UserFieldDescriptor> userFields = feedProvider.getUserFields();
return (category != null) ? Sets.union(userFields, categoryProvider.getFeedUserFields(category.getId()).orElse(Collections.emptySet())) : userFields;
}
}