1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.databind.model.impl;
7   
8   import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter;
9   import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine;
10  import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
11  import gov.nist.secauto.metaschema.core.model.AbstractInlineFlagDefinition;
12  import gov.nist.secauto.metaschema.core.model.IBoundObject;
13  import gov.nist.secauto.metaschema.core.model.IModule;
14  import gov.nist.secauto.metaschema.core.model.constraint.ISource;
15  import gov.nist.secauto.metaschema.core.model.constraint.IValueConstrained;
16  import gov.nist.secauto.metaschema.core.model.constraint.ValueConstraintSet;
17  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
18  import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionFlag;
19  import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModel;
20  import gov.nist.secauto.metaschema.databind.model.IBoundInstanceFlag;
21  import gov.nist.secauto.metaschema.databind.model.IBoundModule;
22  import gov.nist.secauto.metaschema.databind.model.annotations.BoundFlag;
23  import gov.nist.secauto.metaschema.databind.model.annotations.JsonFieldValueKeyFlag;
24  import gov.nist.secauto.metaschema.databind.model.annotations.JsonKey;
25  import gov.nist.secauto.metaschema.databind.model.annotations.ModelUtil;
26  import gov.nist.secauto.metaschema.databind.model.annotations.ValueConstraints;
27  
28  import java.lang.reflect.Field;
29  import java.util.Optional;
30  
31  import edu.umd.cs.findbugs.annotations.NonNull;
32  import edu.umd.cs.findbugs.annotations.Nullable;
33  import nl.talsmasoftware.lazy4j.Lazy;
34  
35  /**
36   * Implements a Metaschema module inline flag instance/definition bound to a
37   * Java field.
38   */
39  // TODO: implement getProperties()
40  public class InstanceFlagInline
41      extends AbstractInlineFlagDefinition<IBoundDefinitionModel<IBoundObject>, IBoundDefinitionFlag, IBoundInstanceFlag>
42      // extends AbstractBoundInstanceJavaField<BoundFlag, IBoundDefinitionModel>
43      implements IBoundInstanceFlag {
44    @NonNull
45    private final Field javaField;
46    @NonNull
47    private final BoundFlag annotation;
48    @NonNull
49    private final IDataTypeAdapter<?> javaTypeAdapter;
50    @Nullable
51    private final Object defaultValue;
52    @NonNull
53    private final Lazy<IValueConstrained> constraints;
54  
55    /**
56     * Construct a new inline field instance/definition.
57     *
58     * @param javaField
59     *          the Java field bound to this instance
60     * @param containingDefinition
61     *          the definition containing this instance
62     */
63    public InstanceFlagInline(
64        @NonNull Field javaField,
65        @NonNull IBoundDefinitionModel<IBoundObject> containingDefinition) {
66      super(containingDefinition);
67      this.javaField = javaField;
68      this.annotation = ModelUtil.getAnnotation(javaField, BoundFlag.class);
69      Class<? extends IDataTypeAdapter<?>> adapterClass = ObjectUtils.notNull(getAnnotation().typeAdapter());
70      this.javaTypeAdapter = ModelUtil.getDataTypeAdapter(
71          adapterClass,
72          containingDefinition.getBindingContext());
73      this.defaultValue = ModelUtil.resolveDefaultValue(getAnnotation().defaultValue(), this.javaTypeAdapter);
74  
75      IModule module = containingDefinition.getContainingModule();
76  
77      this.constraints = ObjectUtils.notNull(Lazy.lazy(() -> {
78        IValueConstrained retval = new ValueConstraintSet();
79        ValueConstraints valueAnnotation = getAnnotation().valueConstraints();
80        ConstraintSupport.parse(valueAnnotation, ISource.modelSource(module), retval);
81        return retval;
82      }));
83    }
84  
85    /**
86     * Get the bound Java field.
87     *
88     * @return the bound Java field
89     */
90    @Override
91    @NonNull
92    public Field getField() {
93      return javaField;
94    }
95  
96    /**
97     * Get the binding Java annotation.
98     *
99     * @return the binding Java annotation
100    */
101   @NonNull
102   private BoundFlag getAnnotation() {
103     return annotation;
104   }
105 
106   @Override
107   public IBoundModule getContainingModule() {
108     return getContainingDefinition().getContainingModule();
109   }
110 
111   // ------------------------------------------
112   // - Start annotation driven code - CPD-OFF -
113   // ------------------------------------------
114 
115   @SuppressWarnings("null")
116   @Override
117   @NonNull
118   public IValueConstrained getConstraintSupport() {
119     return constraints.get();
120   }
121 
122   @Override
123   public boolean isRequired() {
124     return getAnnotation().required();
125   }
126 
127   @Override
128   public Object getDefaultValue() {
129     return defaultValue;
130   }
131 
132   @Override
133   public boolean isJsonKey() {
134     return getField().isAnnotationPresent(JsonKey.class);
135   }
136 
137   @Override
138   public boolean isJsonValueKey() {
139     return getField().isAnnotationPresent(JsonFieldValueKeyFlag.class);
140   }
141 
142   @Override
143   public IDataTypeAdapter<?> getJavaTypeAdapter() {
144     return javaTypeAdapter;
145   }
146 
147   @Override
148   @Nullable
149   public String getFormalName() {
150     return ModelUtil.resolveNoneOrValue(getAnnotation().formalName());
151   }
152 
153   @Override
154   @Nullable
155   public MarkupLine getDescription() {
156     return ModelUtil.resolveToMarkupLine(getAnnotation().description());
157   }
158 
159   @Override
160   public String getName() {
161     return ObjectUtils.notNull(
162         Optional.ofNullable(ModelUtil.resolveNoneOrValue(getAnnotation().name())).orElse(getField().getName()));
163   }
164 
165   @Override
166   public Integer getUseIndex() {
167     return getAnnotation().useIndex();
168   }
169 
170   @Override
171   @Nullable
172   public MarkupMultiline getRemarks() {
173     return ModelUtil.resolveToMarkupMultiline(getAnnotation().remarks());
174   }
175 
176   // ----------------------------------------
177   // - End annotation driven code - CPD-OFF -
178   // ----------------------------------------
179 }