001/*
002 * SPDX-FileCopyrightText: none
003 * SPDX-License-Identifier: CC0-1.0
004 */
005
006package gov.nist.secauto.metaschema.databind.model;
007
008import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter;
009import gov.nist.secauto.metaschema.core.model.IBoundObject;
010import gov.nist.secauto.metaschema.core.model.IFieldInstanceAbsolute;
011import gov.nist.secauto.metaschema.core.util.ObjectUtils;
012import gov.nist.secauto.metaschema.databind.IBindingContext;
013import gov.nist.secauto.metaschema.databind.model.impl.DefinitionField;
014import gov.nist.secauto.metaschema.databind.model.impl.InstanceModelFieldComplex;
015import gov.nist.secauto.metaschema.databind.model.impl.InstanceModelFieldScalar;
016
017import java.lang.reflect.Field;
018
019import javax.xml.namespace.QName;
020
021import edu.umd.cs.findbugs.annotations.NonNull;
022
023public interface IBoundInstanceModelField<ITEM> extends IBoundInstanceModelNamed<ITEM>, IFieldInstanceAbsolute {
024
025  @Override
026  IBoundDefinitionModelField<ITEM> getDefinition();
027
028  /**
029   * Create a new bound field instance.
030   *
031   * @param field
032   *          the Java field the instance is bound to
033   * @param containingDefinition
034   *          the definition containing the instance
035   * @return the new instance
036   */
037  @NonNull
038  static IBoundInstanceModelField<?> newInstance(
039      @NonNull Field field,
040      @NonNull IBoundDefinitionModelAssembly containingDefinition) {
041    Class<?> itemType = IBoundInstanceModel.getItemType(field);
042
043    IBoundInstanceModelField<?> retval;
044    if (IBoundObject.class.isAssignableFrom(itemType)) {
045      IBindingContext bindingContext = containingDefinition.getBindingContext();
046      IBoundDefinitionModel<?> definition = bindingContext.getBoundDefinitionForClass(
047          ObjectUtils.notNull(itemType.asSubclass(IBoundObject.class)));
048      if (definition == null) {
049        throw new IllegalStateException(String.format(
050            "The field '%s' on class '%s' is not bound to a Metaschema field",
051            field.toString(),
052            field.getDeclaringClass().getName()));
053      }
054      retval = InstanceModelFieldComplex.newInstance(field, (DefinitionField) definition, containingDefinition);
055    } else {
056
057      retval = InstanceModelFieldScalar.newInstance(field, containingDefinition);
058    }
059    return retval;
060  }
061
062  @Override
063  default boolean canHandleXmlQName(QName qname) {
064    boolean retval;
065    if (isEffectiveValueWrappedInXml()) {
066      retval = qname.equals(getXmlQName());
067    } else {
068      IDataTypeAdapter<?> adapter = getDefinition().getJavaTypeAdapter();
069      // we are to parse the data type
070      retval = adapter.canHandleQName(qname);
071    }
072    return retval;
073  }
074}