DefaultNodeItemFactory.java
package gov.nist.secauto.metaschema.core.metapath.item.node;
import gov.nist.secauto.metaschema.core.metapath.item.node.IFeatureFlagContainerItem.FlagContainer;
import gov.nist.secauto.metaschema.core.metapath.item.node.IFeatureModelContainerItem.ModelContainer;
import gov.nist.secauto.metaschema.core.model.IAssemblyInstanceGrouped;
import gov.nist.secauto.metaschema.core.model.IChoiceGroupInstance;
import gov.nist.secauto.metaschema.core.model.IFlagInstance;
import gov.nist.secauto.metaschema.core.model.IModelInstance;
import gov.nist.secauto.metaschema.core.model.IModule;
import gov.nist.secauto.metaschema.core.model.INamedModelInstance;
import gov.nist.secauto.metaschema.core.model.INamedModelInstanceAbsolute;
import gov.nist.secauto.metaschema.core.model.INamedModelInstanceGrouped;
import gov.nist.secauto.metaschema.core.util.CollectionUtil;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.xml.namespace.QName;
import edu.umd.cs.findbugs.annotations.NonNull;
@SuppressWarnings("PMD.CouplingBetweenObjects")
final class DefaultNodeItemFactory
extends AbstractNodeItemFactory {
@NonNull
static final DefaultNodeItemFactory SINGLETON = new DefaultNodeItemFactory();
/**
* Get the singleton instance of this node factory.
*
* @return the node factory instance
*/
@NonNull
public static DefaultNodeItemFactory instance() {
return SINGLETON;
}
private DefaultNodeItemFactory() {
// prevent construction
}
@Override
@NonNull
public Supplier<FlagContainer> newDataModelSupplier(@NonNull IFieldNodeItem item) {
return () -> {
Map<QName, IFlagNodeItem> flags = generateFlags(item);
return new FlagContainer(flags);
};
}
@Override
@NonNull
public Supplier<ModelContainer> newDataModelSupplier(@NonNull IAssemblyNodeItem item) {
return () -> {
Map<QName, IFlagNodeItem> flags = generateFlags(item);
Map<QName, List<? extends IModelNodeItem<?, ?>>> modelItems = generateModelItems(item);
return new ModelContainer(flags, modelItems);
};
}
@Override
public Supplier<ModelContainer> newDataModelSupplier(IRootAssemblyNodeItem item) {
return () -> {
Map<QName, List<? extends IModelNodeItem<?, ?>>> modelItems = CollectionUtil.singletonMap(
item.getQName(),
CollectionUtil.singletonList(item));
return new ModelContainer(CollectionUtil.emptyMap(), modelItems);
};
}
/**
* Given the provided parent node item, generate a mapping of flag name to flag
* node item for each flag on the parent assembly.
*
* @param parent
* the parent assembly containing flags
* @return a mapping of flag name to flag item
*/
@SuppressWarnings("PMD.UseConcurrentHashMap") // need an ordered Map
@NonNull
protected Map<QName, IFlagNodeItem> generateFlags(@NonNull IModelNodeItem<?, ?> parent) {
Map<QName, IFlagNodeItem> retval = new LinkedHashMap<>();
Object parentValue = parent.getValue();
assert parentValue != null;
for (IFlagInstance instance : parent.getDefinition().getFlagInstances()) {
Object flagValue = instance.getValue(parentValue);
if (flagValue != null) {
IFlagNodeItem item = newFlagNodeItem(instance, parent, flagValue);
retval.put(instance.getXmlQName(), item);
}
}
return retval.isEmpty() ? CollectionUtil.emptyMap() : CollectionUtil.unmodifiableMap(retval);
}
/**
* Given the provided parent node item, generate a mapping of model instance
* name to model node item(s) for each model instance on the parent assembly.
*
* @param parent
* the parent assembly containing model instances
* @return a mapping of model instance name to model node item(s)
*/
@SuppressWarnings({ "PMD.UseConcurrentHashMap", "PMD.CognitiveComplexity" }) // need an ordered map
@NonNull
protected Map<QName, List<? extends IModelNodeItem<?, ?>>> generateModelItems(
@NonNull IAssemblyNodeItem parent) {
Map<QName, List<? extends IModelNodeItem<?, ?>>> retval = new LinkedHashMap<>();
Object parentValue = parent.getValue();
assert parentValue != null;
for (IModelInstance instance : CollectionUtil.toIterable(getValuedModelInstances(parent.getDefinition()))) {
if (instance instanceof INamedModelInstanceAbsolute) {
INamedModelInstanceAbsolute namedInstance = (INamedModelInstanceAbsolute) instance;
Object instanceValue = namedInstance.getValue(parentValue);
if (instanceValue != null) {
List<IModelNodeItem<?, ?>> items = generateModelInstanceItems(
parent,
namedInstance,
ObjectUtils.notNull(namedInstance.getItemValues(instanceValue).stream()));
retval.put(namedInstance.getXmlQName(), items);
}
} else if (instance instanceof IChoiceGroupInstance) {
IChoiceGroupInstance choiceInstance = (IChoiceGroupInstance) instance;
Object instanceValue = choiceInstance.getValue(parentValue);
if (instanceValue != null) {
Map<INamedModelInstanceGrouped, List<Object>> instanceMap
= choiceInstance.getItemValues(instanceValue).stream()
.map(item -> {
assert item != null;
INamedModelInstanceGrouped itemInstance = choiceInstance.getItemInstance(item);
return Map.entry(itemInstance, item);
})
.collect(Collectors.groupingBy(
entry -> entry.getKey(),
LinkedHashMap::new,
Collectors.mapping(entry -> entry.getValue(), Collectors.toUnmodifiableList())));
for (Map.Entry<INamedModelInstanceGrouped, List<Object>> entry : instanceMap.entrySet()) {
INamedModelInstanceGrouped namedInstance = entry.getKey();
assert namedInstance != null;
List<IModelNodeItem<?, ?>> items = generateModelInstanceItems(
parent,
namedInstance,
ObjectUtils.notNull(entry.getValue().stream()));
retval.put(namedInstance.getXmlQName(), items);
}
}
}
}
return retval.isEmpty() ? CollectionUtil.emptyMap() : CollectionUtil.unmodifiableMap(retval);
}
private List<IModelNodeItem<?, ?>> generateModelInstanceItems(
@NonNull IAssemblyNodeItem parent,
@NonNull INamedModelInstance namedInstance,
@NonNull Stream<?> itemValues) {
AtomicInteger index = new AtomicInteger(); // NOPMD - intentional
// the item values will be all non-null items
return itemValues.map(itemValue -> {
assert itemValue != null;
return newModelItem(namedInstance, parent, index.incrementAndGet(), itemValue);
}).collect(Collectors.toUnmodifiableList());
}
@Override
public Supplier<ModelContainer> newMetaschemaModelSupplier(@NonNull IModuleNodeItem item) {
return () -> {
IModule module = item.getModule();
// build flags from Metaschema definitions
Map<QName, IFlagNodeItem> flags = ObjectUtils.notNull(
Collections.unmodifiableMap(module.getExportedFlagDefinitions().stream()
.map(def -> newFlagNodeItem(ObjectUtils.notNull(def), item))
.collect(
Collectors.toMap(
IFlagNodeItem::getQName,
Function.identity(),
(v1, v2) -> v2,
LinkedHashMap::new))));
// build model items from Metaschema definitions
Stream<IFieldNodeItem> fieldStream = module.getExportedFieldDefinitions().stream()
.map(def -> newFieldNodeItem(ObjectUtils.notNull(def), item));
Stream<IAssemblyNodeItem> assemblyStream = module.getExportedAssemblyDefinitions().stream()
.map(def -> newAssemblyNodeItem(ObjectUtils.notNull(def), item));
Map<QName, List<? extends IModelNodeItem<?, ?>>> modelItems
= ObjectUtils.notNull(Stream.concat(fieldStream, assemblyStream)
.collect(
Collectors.collectingAndThen(
Collectors.groupingBy(IModelNodeItem::getQName),
Collections::unmodifiableMap)));
return new ModelContainer(flags, modelItems);
};
}
@Override
public Supplier<FlagContainer> newMetaschemaModelSupplier(@NonNull IFieldNodeItem item) {
return () -> {
Map<QName, IFlagNodeItem> flags = generateMetaschemaFlags(item);
return new FlagContainer(flags);
};
}
@Override
public Supplier<ModelContainer> newMetaschemaModelSupplier(
@NonNull IAssemblyNodeItem item) {
return () -> {
Map<QName, IFlagNodeItem> flags = generateMetaschemaFlags(item);
Map<QName, List<? extends IModelNodeItem<?, ?>>> modelItems = generateMetaschemaModelItems(item);
return new ModelContainer(flags, modelItems);
};
}
@NonNull
protected Map<QName, IFlagNodeItem> generateMetaschemaFlags(
@NonNull IModelNodeItem<?, ?> parent) {
Map<QName, IFlagNodeItem> retval = new LinkedHashMap<>(); // NOPMD - intentional
for (IFlagInstance instance : parent.getDefinition().getFlagInstances()) {
assert instance != null;
IFlagNodeItem item = newFlagNodeItem(instance, parent);
retval.put(instance.getXmlQName(), item);
}
return retval.isEmpty() ? CollectionUtil.emptyMap() : CollectionUtil.unmodifiableMap(retval);
}
@NonNull
protected Map<QName, List<? extends IModelNodeItem<?, ?>>> generateMetaschemaModelItems(
@NonNull IAssemblyNodeItem parent) {
Map<QName, List<? extends IModelNodeItem<?, ?>>> retval = new LinkedHashMap<>(); // NOPMD - intentional
for (INamedModelInstance instance : CollectionUtil.toIterable(getNamedModelInstances(parent.getDefinition()))) {
assert instance != null;
IModelNodeItem<?, ?> item = newModelItem(instance, parent);
retval.put(instance.getXmlQName(), Collections.singletonList(item));
}
return retval.isEmpty() ? CollectionUtil.emptyMap() : CollectionUtil.unmodifiableMap(retval);
}
@Override
public IAssemblyNodeItem newAssemblyNodeItem(IAssemblyInstanceGrouped instance, IAssemblyNodeItem parent,
int position, Object value) {
throw new UnsupportedOperationException("implement");
}
}