/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package util;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import com.emc.vipr.model.catalog.ServiceDescriptorRestRep;
import com.emc.vipr.model.catalog.ServiceFieldGroupRestRep;
import com.emc.vipr.model.catalog.ServiceFieldModalRestRep;
import com.emc.vipr.model.catalog.ServiceFieldRestRep;
import com.emc.vipr.model.catalog.ServiceFieldTableRestRep;
import com.emc.vipr.model.catalog.ServiceItemRestRep;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import controllers.api.AssetOptionsApi;
public class ServiceFormUtils {
/**
* Creates a mapping of field name to {@link AssetFieldDescriptor} for all asset fields in the provided service.
*
* @param service
* the service descriptor.
* @return the map of field name->AssetFieldDescriptor.
*/
public static Map<String, AssetFieldDescriptor> createAssetFieldDescriptors(ServiceDescriptorRestRep service) {
Map<String, ServiceFieldRestRep> providedFields = Maps.newHashMap();
Map<String, AssetFieldDescriptor> assetFields = createAssetFieldsFromItems(service.getItems(), providedFields);
calculateReverseDependencies(assetFields);
return assetFields;
}
/**
* Reverses the dependencies of the asset fields, calculating {@link AssetFieldDescriptor#fieldsThatDependOnUs}.
*
* @param assetFields
* the map of all asset fields.
*/
private static void calculateReverseDependencies(Map<String, AssetFieldDescriptor> assetFields) {
for (Map.Entry<String, AssetFieldDescriptor> entry : assetFields.entrySet()) {
String name = entry.getKey();
for (String dependencyName : entry.getValue().fieldsWeDependOn) {
AssetFieldDescriptor dependency = assetFields.get(dependencyName);
if (dependency != null) {
dependency.fieldsThatDependOnUs.add(name);
}
}
}
}
/**
* Creates the asset fields for the container and all its children.
*
* @param container
* the service item container.
* @param providedFields
* the asset fields provided by the parent, mapped by asset type.
* @return the map of field name->AssetFieldDescriptor.
*/
private static Map<String, AssetFieldDescriptor> createAssetFieldsFromItems(Collection<? extends ServiceItemRestRep> items,
Map<String, ServiceFieldRestRep> providedFields) {
List<ServiceFieldRestRep> fields = ServiceFieldRestRep.getAssetFields(items);
Map<String, AssetFieldDescriptor> assetFields = createAssetFields(fields, providedFields);
// Add the container fields to the provided fields for the children
providedFields = addFieldsByType(fields, providedFields);
for (ServiceItemRestRep child : items) {
if (child instanceof ServiceFieldGroupRestRep) {
assetFields.putAll(createAssetFieldsFromItems(((ServiceFieldGroupRestRep) child).getItems(), providedFields));
}
else if (child instanceof ServiceFieldTableRestRep) {
assetFields.putAll(createAssetFieldsFromItems(((ServiceFieldTableRestRep) child).getItems(), providedFields));
}
else if (child instanceof ServiceFieldModalRestRep) {
assetFields.putAll(createAssetFieldsFromItems(((ServiceFieldModalRestRep) child).getItems(), providedFields));
}
}
return assetFields;
}
/**
* Creates asset field descriptors for the list of asset fields, with access to the additional fields provided by
* the parent.
*
* @param fields
* the asset fields for which to create descriptors.
* @param providedFields
* the asset fields provided by the parent, mapped by asset type.
* @return the map of field name->AssetFieldDescriptor.
*/
private static Map<String, AssetFieldDescriptor> createAssetFields(List<ServiceFieldRestRep> fields,
Map<String, ServiceFieldRestRep> providedFields) {
Map<String, AssetFieldDescriptor> assetFields = Maps.newHashMap();
Set<String> availableTypes = Sets.newHashSet(ServiceFieldRestRep.getAssetTypes(providedFields.values()));
availableTypes.addAll(ServiceFieldRestRep.getAssetTypes(fields));
for (ServiceFieldRestRep field : fields) {
String assetType = field.getAssetType();
List<String> dependencies = Lists.newArrayList();
for (String requiredType : AssetOptionsApi.calculateAssetDependencies(assetType, availableTypes)) {
ServiceFieldRestRep dep = findFieldByAssetType(requiredType, fields, providedFields);
dependencies.add(dep.getName());
}
AssetFieldDescriptor assetField = createAssetField(field, dependencies);
assetFields.put(field.getName(), assetField);
}
return assetFields;
}
/**
* Creates an asset field descriptor for the service field with the provided dependencies
*
* @param field
* the service field.
* @param dependencies
* the names of the fields that are dependencies.
* @return the asset field descriptor.
*/
private static AssetFieldDescriptor createAssetField(ServiceFieldRestRep field, List<String> dependencies) {
AssetFieldDescriptor assetField = new AssetFieldDescriptor();
assetField.assetType = field.getAssetType();
assetField.select = field.getSelect();
assetField.fieldsWeDependOn = dependencies;
// Will be calculated after all asset field descriptors are created
assetField.fieldsThatDependOnUs = Lists.newArrayList();
return assetField;
}
/**
* Adds service fields to the provided fields by type, returning a new map. Any provided fields will be overwritten
* if the service fields contain a matching asset type.
*
* @param fields
* the service fields to add.
* @param providedFields
* the current provided fields, mapped by asset type.
* @return the combined map containing the original provided fields and the service fields mapped by type.
*/
private static Map<String, ServiceFieldRestRep> addFieldsByType(List<ServiceFieldRestRep> fields,
Map<String, ServiceFieldRestRep> providedFields) {
Map<String, ServiceFieldRestRep> map = Maps.newHashMap(providedFields);
for (ServiceFieldRestRep field : fields) {
if (field.isAsset()) {
map.put(field.getAssetType(), field);
}
}
return map;
}
/**
* Finds a field by asset type, first searching the fields list and falling back to a lookup in the provided fields.
*
* @param assetType
* the asset type.
* @param fields
* the fields to search.
* @param providedFields
* the fields provided by the parent, mapped by asset type.
* @return the matching service field.
*
* @throws IllegalArgumentException
* if there is no matching field with the desired type.
*/
private static ServiceFieldRestRep findFieldByAssetType(String assetType, Collection<ServiceFieldRestRep> fields,
Map<String, ServiceFieldRestRep> providedFields) {
ServiceFieldRestRep field = findFieldByAssetType(assetType, fields);
if (field != null) {
return field;
}
field = providedFields.get(assetType);
if (field != null) {
return field;
}
throw new IllegalArgumentException("No Field of type " + assetType);
}
/**
* Finds a field by asset type in a collection of fields. The first matching field is returned.
*
* @param assetType
* the asset type.
* @param fields
* the fields to search.
* @return the matching service field.
*/
private static ServiceFieldRestRep findFieldByAssetType(String assetType, Collection<ServiceFieldRestRep> fields) {
for (ServiceFieldRestRep field : fields) {
if (StringUtils.equals(field.getAssetType(), assetType)) {
return field;
}
}
return null;
}
public static class AssetFieldDescriptor {
/** A list of form field names that require us to proceed */
public List<String> fieldsThatDependOnUs;
/** A list of form field names that this field requires */
public List<String> fieldsWeDependOn;
public String assetType;
public String select;
}
}