ChoiceGroupModelContainerSupport.java
/*
* SPDX-FileCopyrightText: none
* SPDX-License-Identifier: CC0-1.0
*/
package gov.nist.secauto.metaschema.databind.model.metaschema.impl;
import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItemFactory;
import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition;
import gov.nist.secauto.metaschema.core.model.IAssemblyInstanceGrouped;
import gov.nist.secauto.metaschema.core.model.IChoiceGroupInstance;
import gov.nist.secauto.metaschema.core.model.IContainerModelSupport;
import gov.nist.secauto.metaschema.core.model.IFieldDefinition;
import gov.nist.secauto.metaschema.core.model.IFieldInstanceGrouped;
import gov.nist.secauto.metaschema.core.model.IModule;
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 gov.nist.secauto.metaschema.databind.model.IBoundInstanceModelChoiceGroup;
import gov.nist.secauto.metaschema.databind.model.IBoundInstanceModelGroupedAssembly;
import gov.nist.secauto.metaschema.databind.model.metaschema.binding.AssemblyModel;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
class ChoiceGroupModelContainerSupport
implements IContainerModelSupport<
INamedModelInstanceGrouped,
INamedModelInstanceGrouped,
IFieldInstanceGrouped,
IAssemblyInstanceGrouped> {
@NonNull
private final Map<QName, INamedModelInstanceGrouped> namedModelInstances;
@NonNull
private final Map<QName, IFieldInstanceGrouped> fieldInstances;
@NonNull
private final Map<QName, IAssemblyInstanceGrouped> assemblyInstances;
@SuppressWarnings("PMD.ShortMethodName")
public static IContainerModelSupport<
INamedModelInstanceGrouped,
INamedModelInstanceGrouped,
IFieldInstanceGrouped,
IAssemblyInstanceGrouped> of(
@Nullable AssemblyModel.ChoiceGroup binding,
@NonNull IBoundInstanceModelGroupedAssembly bindingInstance,
@NonNull IChoiceGroupInstance parent,
@NonNull INodeItemFactory nodeItemFactory) {
List<Object> instances;
return binding == null || (instances = binding.getChoices()) == null || instances.isEmpty()
? IContainerModelSupport.empty()
: new ChoiceGroupModelContainerSupport(
binding,
bindingInstance,
parent,
nodeItemFactory);
}
/**
* Construct a new assembly model container.
*
* @param binding
* the choice model object bound to a Java class
* @param bindingInstance
* the Metaschema module instance for the bound model object
* @param parent
* the assembly definition containing this container
* @param nodeItemFactory
* the node item factory used to generate child nodes
*/
@SuppressWarnings({ "PMD.AvoidInstantiatingObjectsInLoops", "PMD.UseConcurrentHashMap", "PMD.PrematureDeclaration" })
@SuppressFBWarnings(value = "CT_CONSTRUCTOR_THROW", justification = "Use of final fields")
public ChoiceGroupModelContainerSupport(
@NonNull AssemblyModel.ChoiceGroup binding,
@NonNull IBoundInstanceModelGroupedAssembly bindingInstance,
@NonNull IChoiceGroupInstance parent,
@NonNull INodeItemFactory nodeItemFactory) {
// create temporary collections to store the child binding objects
final Map<QName, INamedModelInstanceGrouped> namedModelInstances = new LinkedHashMap<>();
final Map<QName, IFieldInstanceGrouped> fieldInstances = new LinkedHashMap<>();
final Map<QName, IAssemblyInstanceGrouped> assemblyInstances = new LinkedHashMap<>();
// create counters to track child positions
int assemblyReferencePosition = 0;
int assemblyInlineDefinitionPosition = 0;
int fieldReferencePosition = 0;
int fieldInlineDefinitionPosition = 0;
// TODO: make "instances" a constant
IBoundInstanceModelChoiceGroup instance = ObjectUtils.requireNonNull(
bindingInstance.getDefinition().getChoiceGroupInstanceByName("choices"));
for (Object obj : ObjectUtils.notNull(binding.getChoices())) {
assert obj != null;
IBoundInstanceModelGroupedAssembly objInstance
= (IBoundInstanceModelGroupedAssembly) instance.getItemInstance(obj);
if (obj instanceof AssemblyModel.ChoiceGroup.Assembly) {
IAssemblyInstanceGrouped assembly = newInstance(
(AssemblyModel.ChoiceGroup.Assembly) obj,
objInstance,
assemblyReferencePosition++,
parent);
addInstance(assembly, namedModelInstances, assemblyInstances);
} else if (obj instanceof AssemblyModel.ChoiceGroup.DefineAssembly) {
IAssemblyInstanceGrouped assembly = new InstanceModelGroupedAssemblyInline(
(AssemblyModel.ChoiceGroup.DefineAssembly) obj,
objInstance,
assemblyInlineDefinitionPosition++,
parent,
nodeItemFactory);
addInstance(assembly, namedModelInstances, assemblyInstances);
} else if (obj instanceof AssemblyModel.ChoiceGroup.Field) {
IFieldInstanceGrouped field = newInstance(
(AssemblyModel.ChoiceGroup.Field) obj,
objInstance,
fieldReferencePosition++,
parent);
addInstance(field, namedModelInstances, fieldInstances);
} else if (obj instanceof AssemblyModel.ChoiceGroup.DefineField) {
IFieldInstanceGrouped field = new InstanceModelGroupedFieldInline(
(AssemblyModel.ChoiceGroup.DefineField) obj,
objInstance,
fieldInlineDefinitionPosition++,
parent);
addInstance(field, namedModelInstances, fieldInstances);
} else {
throw new UnsupportedOperationException(
String.format("Unknown choice group model instance class: %s", obj.getClass()));
}
}
this.namedModelInstances = namedModelInstances.isEmpty()
? CollectionUtil.emptyMap()
: CollectionUtil.unmodifiableMap(namedModelInstances);
this.fieldInstances = fieldInstances.isEmpty()
? CollectionUtil.emptyMap()
: CollectionUtil.unmodifiableMap(fieldInstances);
this.assemblyInstances = assemblyInstances.isEmpty()
? CollectionUtil.emptyMap()
: CollectionUtil.unmodifiableMap(assemblyInstances);
}
protected static void addInstance(
@NonNull IAssemblyInstanceGrouped assembly,
@NonNull Map<QName, INamedModelInstanceGrouped> namedModelInstances,
@NonNull Map<QName, IAssemblyInstanceGrouped> assemblyInstances) {
QName effectiveName = assembly.getXmlQName();
namedModelInstances.put(effectiveName, assembly);
assemblyInstances.put(effectiveName, assembly);
}
protected static void addInstance(
@NonNull IFieldInstanceGrouped field,
@NonNull Map<QName, INamedModelInstanceGrouped> namedModelInstances,
@NonNull Map<QName, IFieldInstanceGrouped> fieldInstances) {
QName effectiveName = field.getXmlQName();
namedModelInstances.put(effectiveName, field);
fieldInstances.put(effectiveName, field);
}
@NonNull
protected static IAssemblyInstanceGrouped newInstance(
@NonNull AssemblyModel.ChoiceGroup.Assembly obj,
@NonNull IBoundInstanceModelGroupedAssembly objInstance,
int position,
@NonNull IChoiceGroupInstance parent) {
IAssemblyDefinition owningDefinition = parent.getOwningDefinition();
IModule module = owningDefinition.getContainingModule();
QName name = parent.getContainingModule().toModelQName(ObjectUtils.requireNonNull(obj.getRef()));
IAssemblyDefinition definition = module.getScopedAssemblyDefinitionByName(name);
if (definition == null) {
throw new IllegalStateException(
String.format("Unable to resolve assembly reference '%s' in definition '%s' in module '%s'",
name,
owningDefinition.getName(),
module.getShortName()));
}
return new InstanceModelGroupedAssemblyReference(obj, objInstance, position, definition, parent);
}
@NonNull
protected static IFieldInstanceGrouped newInstance(
@NonNull AssemblyModel.ChoiceGroup.Field obj,
@NonNull IBoundInstanceModelGroupedAssembly objInstance,
int position,
@NonNull IChoiceGroupInstance parent) {
IAssemblyDefinition owningDefinition = parent.getOwningDefinition();
IModule module = owningDefinition.getContainingModule();
QName name = parent.getContainingModule().toModelQName(ObjectUtils.requireNonNull(obj.getRef()));
IFieldDefinition definition = module.getScopedFieldDefinitionByName(name);
if (definition == null) {
throw new IllegalStateException(
String.format("Unable to resolve field reference '%s' in definition '%s' in module '%s'",
name,
owningDefinition.getName(),
module.getShortName()));
}
return new InstanceModelGroupedFieldReference(obj, objInstance, position, definition, parent);
}
@SuppressWarnings("null")
@Override
public Collection<INamedModelInstanceGrouped> getModelInstances() {
return namedModelInstances.values();
}
@Override
public Map<QName, INamedModelInstanceGrouped> getNamedModelInstanceMap() {
return namedModelInstances;
}
@Override
public Map<QName, IFieldInstanceGrouped> getFieldInstanceMap() {
return fieldInstances;
}
@Override
public Map<QName, IAssemblyInstanceGrouped> getAssemblyInstanceMap() {
return assemblyInstances;
}
}