package com.thinkbiganalytics.feedmgr.service; /*- * #%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.base.MoreObjects; import com.google.common.collect.Maps; import com.thinkbiganalytics.feedmgr.rest.model.UserField; import com.thinkbiganalytics.feedmgr.rest.model.UserProperty; import com.thinkbiganalytics.metadata.api.extension.UserFieldDescriptor; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.Nonnull; import javax.annotation.Nullable; /** * Transforms user-defined properties between Feed Manager and Metadata formats. */ public final class UserPropertyTransform { /** * Instances of {@code UserPropertyTransform} should not be constructed. * * @throws UnsupportedOperationException always */ private UserPropertyTransform() { throw new UnsupportedOperationException(); } /** * Transforms the specified Metadata user-defined properties to Feed Manager user-defined properties. * * @param properties map of property names to values * @param userFields the user-defined field descriptors * @return the set of Feed Manager user-defined properties */ @Nonnull @SafeVarargs public static Set<UserProperty> toUserProperties(@Nonnull final Map<String, String> properties, @Nonnull final Set<UserFieldDescriptor>... userFields) { // Map field names and order int order = 0; int size = Arrays.stream(userFields).collect(Collectors.summingInt(Set::size)); final Map<String, UserFieldDescriptor> userFieldMap = Maps.newHashMapWithExpectedSize(size); final Map<String, Integer> userFieldOrder = Maps.newHashMapWithExpectedSize(size); for (final Set<UserFieldDescriptor> set : userFields) { final Iterator<UserFieldDescriptor> sorted = set.stream().sorted((f1, f2) -> Integer.compare(f1.getOrder(), f2.getOrder())).iterator(); while (sorted.hasNext()) { final UserFieldDescriptor field = sorted.next(); if (!userFieldMap.containsKey(field.getSystemName())) { userFieldMap.put(field.getSystemName(), field); userFieldOrder.put(field.getSystemName(), order++); } } } // Convert from Metadata to Feed Manager format final Stream<UserProperty> newProperties = userFieldMap.values().stream() .filter(field -> !properties.containsKey(field.getSystemName())) .map(field -> { final UserProperty property = new UserProperty(); property.setDescription(field.getDescription()); property.setDisplayName(field.getDisplayName()); property.setLocked(true); property.setOrder(userFieldOrder.get(field.getSystemName())); property.setRequired(field.isRequired()); property.setSystemName(field.getSystemName()); return property; }); final Stream<UserProperty> existingProperties = properties.entrySet().stream() .map(entry -> { // Create the Feed Manager property final UserProperty property = new UserProperty(); property.setLocked(false); property.setSystemName(entry.getKey()); property.setValue(entry.getValue()); // Set additional Metadata attributes final UserFieldDescriptor field = userFieldMap.get(entry.getKey()); if (field != null) { property.setDescription(field.getDescription()); property.setDisplayName(field.getDisplayName()); property.setLocked(true); property.setOrder(userFieldOrder.get(entry.getKey())); property.setRequired(field.isRequired()); } // Return the Feed Manager property return property; }); return Stream.concat(newProperties, existingProperties).collect(Collectors.toCollection(LinkedHashSet::new)); } /** * Transforms the specified Feed Manager user-defined properties to Metadata user-defined properties. * * @param userProperties the Feed Manager user-defined properties * @return a map of property names to values */ @Nonnull public static Map<String, String> toMetadataProperties(@Nonnull final Set<UserProperty> userProperties) { return userProperties.stream() .filter(property -> property.getValue() != null) .collect(Collectors.toMap(UserProperty::getSystemName, UserProperty::getValue)); } /** * Transforms the specified {@link UserField} objects into {@link UserFieldDescriptor} objects. * * @param userFields the user-defined fields * @return equivalent user-defined field descriptors */ @Nonnull public static Set<UserFieldDescriptor> toUserFieldDescriptors(@Nonnull final Set<UserField> userFields) { return userFields.stream().map(FeedManagerUserFieldDescriptor::new).collect(Collectors.toSet()); } /** * Transforms the specified {@link UserFieldDescriptor} objects into {@link UserField} objects. * * @param descriptors the user-defined field descriptors * @return equivalent user-defined fields */ @Nonnull public static Set<UserField> toUserFields(@Nonnull final Set<UserFieldDescriptor> descriptors) { return descriptors.stream().map(descriptor -> { final UserField field = new UserField(); field.setDescription(descriptor.getDescription()); field.setDisplayName(descriptor.getDisplayName()); field.setOrder(descriptor.getOrder()); field.setRequired(descriptor.isRequired()); field.setSystemName(descriptor.getSystemName()); return field; }).collect(Collectors.toSet()); } /** * A {@link UserFieldDescriptor} backed by a {@link UserField}. */ private static class FeedManagerUserFieldDescriptor implements UserFieldDescriptor { /** * Delegate user-defined field */ @Nonnull private final UserField userField; /** * Constructs a {@code FeedManagerUserFieldDescriptor} that delegates to the specified user-defined field. * * @param userField the user-defined field to delegate to */ FeedManagerUserFieldDescriptor(@Nonnull final UserField userField) { this.userField = userField; } @Nullable @Override public String getDescription() { return userField.getDescription(); } @Nullable @Override public String getDisplayName() { return userField.getDisplayName(); } @Override public int getOrder() { return (userField.getOrder() != null) ? userField.getOrder() : 0; } @Override public boolean isRequired() { return (userField.isRequired() != null) ? userField.isRequired() : false; } @Nonnull @Override public String getSystemName() { return userField.getSystemName(); } @Override public int hashCode() { return Objects.hashCode(getSystemName()); } @Override public String toString() { return MoreObjects.toStringHelper(UserFieldDescriptor.class) .add("name", getSystemName()) .toString(); } } }