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