1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package dev.metaschema.databind.model.metaschema.impl;
7   
8   import java.math.BigInteger;
9   import java.util.Map;
10  import java.util.Set;
11  
12  import dev.metaschema.core.datatype.markup.MarkupLine;
13  import dev.metaschema.core.datatype.markup.MarkupMultiline;
14  import dev.metaschema.core.metapath.item.node.IAssemblyNodeItem;
15  import dev.metaschema.core.metapath.item.node.INodeItemFactory;
16  import dev.metaschema.core.model.AbstractInlineAssemblyDefinition;
17  import dev.metaschema.core.model.IAssemblyDefinition;
18  import dev.metaschema.core.model.IAssemblyInstanceAbsolute;
19  import dev.metaschema.core.model.IAttributable;
20  import dev.metaschema.core.model.IChoiceGroupInstance;
21  import dev.metaschema.core.model.IChoiceInstance;
22  import dev.metaschema.core.model.IContainerFlagSupport;
23  import dev.metaschema.core.model.IContainerModelAbsolute;
24  import dev.metaschema.core.model.IContainerModelAssemblySupport;
25  import dev.metaschema.core.model.IFieldInstanceAbsolute;
26  import dev.metaschema.core.model.IFlagInstance;
27  import dev.metaschema.core.model.IModelElementVisitor;
28  import dev.metaschema.core.model.IModelInstanceAbsolute;
29  import dev.metaschema.core.model.INamedModelInstanceAbsolute;
30  import dev.metaschema.core.model.ISource;
31  import dev.metaschema.core.model.MetaschemaModelConstants;
32  import dev.metaschema.core.model.constraint.AssemblyConstraintSet;
33  import dev.metaschema.core.model.constraint.IModelConstrained;
34  import dev.metaschema.core.util.ObjectUtils;
35  import dev.metaschema.databind.model.IBoundInstanceModelGroupedAssembly;
36  import dev.metaschema.databind.model.IGroupAs;
37  import dev.metaschema.databind.model.impl.IFeatureInstanceModelGroupAs;
38  import dev.metaschema.databind.model.metaschema.IBindingDefinitionModelAssembly;
39  import dev.metaschema.databind.model.metaschema.IBindingInstance;
40  import dev.metaschema.databind.model.metaschema.IBindingMetaschemaModule;
41  import dev.metaschema.databind.model.metaschema.binding.AssemblyConstraints;
42  import dev.metaschema.databind.model.metaschema.binding.InlineDefineAssembly;
43  import dev.metaschema.databind.model.metaschema.binding.JsonKey;
44  import edu.umd.cs.findbugs.annotations.NonNull;
45  import nl.talsmasoftware.lazy4j.Lazy;
46  
47  /**
48   * Implementation of an inline assembly instance from binding data.
49   * <p>
50   * This class represents an assembly that is defined inline within its
51   * containing assembly rather than as a reference.
52   */
53  public class InstanceModelAssemblyInline
54      extends AbstractInlineAssemblyDefinition<
55          IContainerModelAbsolute,
56          IAssemblyDefinition,
57          IAssemblyInstanceAbsolute,
58          IBindingDefinitionModelAssembly,
59          IFlagInstance,
60          IModelInstanceAbsolute,
61          INamedModelInstanceAbsolute,
62          IFieldInstanceAbsolute,
63          IAssemblyInstanceAbsolute,
64          IChoiceInstance,
65          IChoiceGroupInstance>
66      implements IAssemblyInstanceAbsolute, IBindingInstance, IBindingDefinitionModelAssembly,
67      IFeatureInstanceModelGroupAs {
68    @NonNull
69    private final InlineDefineAssembly binding;
70    @NonNull
71    private final Map<IAttributable.Key, Set<String>> properties;
72    @NonNull
73    private final IGroupAs groupAs;
74    @NonNull
75    private final Lazy<IAssemblyNodeItem> boundNodeItem;
76    @NonNull
77    private final Lazy<IContainerFlagSupport<IFlagInstance>> flagContainer;
78    @NonNull
79    private final Lazy<IContainerModelAssemblySupport<
80        IModelInstanceAbsolute,
81        INamedModelInstanceAbsolute,
82        IFieldInstanceAbsolute,
83        IAssemblyInstanceAbsolute,
84        IChoiceInstance,
85        IChoiceGroupInstance>> modelContainer;
86    @NonNull
87    private final Lazy<IModelConstrained> modelConstraints;
88  
89    /**
90     * Construct a new assembly instance that defines the assembly inline.
91     *
92     * @param binding
93     *          the assembly reference instance object bound to a Java class
94     * @param bindingInstance
95     *          the Metaschema module instance for the bound object
96     * @param position
97     *          the zero-based position of this bound object relative to its bound
98     *          object siblings
99     * @param parent
100    *          the assembly definition containing this binding
101    * @param nodeItemFactory
102    *          the node item factory used to generate child nodes
103    */
104   public InstanceModelAssemblyInline(
105       @NonNull InlineDefineAssembly binding,
106       @NonNull IBoundInstanceModelGroupedAssembly bindingInstance,
107       int position,
108       @NonNull IContainerModelAbsolute parent,
109       @NonNull INodeItemFactory nodeItemFactory) {
110     super(parent);
111     this.binding = binding;
112     this.properties = ModelSupport.parseProperties(ObjectUtils.requireNonNull(binding.getProps()));
113     this.groupAs = ModelSupport.groupAs(binding.getGroupAs(), parent.getOwningDefinition().getContainingModule());
114     this.boundNodeItem = ObjectUtils.notNull(
115         Lazy.of(() -> (IAssemblyNodeItem) ObjectUtils.notNull(getContainingDefinition().getSourceNodeItem())
116             .getModelItemsByName(bindingInstance.getQName())
117             .get(position)));
118     this.flagContainer = ObjectUtils.notNull(Lazy.of(() -> {
119       JsonKey jsonKey = getBinding().getJsonKey();
120       return FlagContainerSupport.newFlagContainer(
121           binding.getFlags(),
122           bindingInstance,
123           this,
124           jsonKey == null ? null : jsonKey.getFlagRef());
125     }));
126     this.modelContainer = ObjectUtils.notNull(Lazy.of(() -> AssemblyModelGenerator.of(
127         binding.getModel(),
128         ObjectUtils.requireNonNull(bindingInstance.getDefinition()
129             .getAssemblyInstanceByName(MetaschemaModelConstants.MODEL_QNAME.getIndexPosition())),
130         this,
131         nodeItemFactory)));
132 
133     ISource source = parent.getOwningDefinition().getContainingModule().getSource();
134 
135     this.modelConstraints = ObjectUtils.notNull(Lazy.of(() -> {
136       IModelConstrained retval = new AssemblyConstraintSet(source);
137       AssemblyConstraints constraints = getBinding().getConstraint();
138       if (constraints != null) {
139         ConstraintBindingSupport.parse(
140             retval,
141             constraints,
142             source);
143       }
144       return retval;
145     }));
146   }
147 
148   /**
149    * Gets the underlying binding object for this inline assembly instance.
150    *
151    * @return the binding object
152    */
153   @NonNull
154   protected InlineDefineAssembly getBinding() {
155     getContainingDefinition();
156     return binding;
157   }
158 
159   @Override
160   public IBindingMetaschemaModule getContainingModule() {
161     return getContainingDefinition().getContainingModule();
162   }
163 
164   @Override
165   public Map<IAttributable.Key, Set<String>> getProperties() {
166     return properties;
167   }
168 
169   @Override
170   public IGroupAs getGroupAs() {
171     return groupAs;
172   }
173 
174   @Override
175   public IAssemblyNodeItem getSourceNodeItem() {
176     return ObjectUtils.notNull(boundNodeItem.get());
177   }
178 
179   @Override
180   public IContainerFlagSupport<IFlagInstance> getFlagContainer() {
181     return ObjectUtils.notNull(flagContainer.get());
182   }
183 
184   @Override
185   public IContainerModelAssemblySupport<
186       IModelInstanceAbsolute,
187       INamedModelInstanceAbsolute,
188       IFieldInstanceAbsolute,
189       IAssemblyInstanceAbsolute,
190       IChoiceInstance,
191       IChoiceGroupInstance> getModelContainer() {
192     return ObjectUtils.notNull(modelContainer.get());
193   }
194 
195   @Override
196   public IModelConstrained getConstraintSupport() {
197     return ObjectUtils.notNull(modelConstraints.get());
198   }
199 
200   @Override
201   public <CONTEXT, RESULT> RESULT accept(IModelElementVisitor<CONTEXT, RESULT> visitor, CONTEXT context) {
202     return IAssemblyInstanceAbsolute.super.accept(visitor, context);
203   }
204 
205   // ---------------------------------------
206   // - Start binding driven code - CPD-OFF -
207   // ---------------------------------------
208 
209   @Override
210   public String getName() {
211     return ObjectUtils.notNull(getBinding().getName());
212   }
213 
214   @Override
215   public Integer getIndex() {
216     return ModelSupport.index(getBinding().getIndex());
217   }
218 
219   @Override
220   public String getFormalName() {
221     return getBinding().getFormalName();
222   }
223 
224   @Override
225   public MarkupLine getDescription() {
226     return getBinding().getDescription();
227   }
228 
229   @Override
230   public MarkupMultiline getRemarks() {
231     return ModelSupport.remarks(getBinding().getRemarks());
232   }
233 
234   @Override
235   public int getMinOccurs() {
236     BigInteger min = getBinding().getMinOccurs();
237     return min == null ? DEFAULT_GROUP_AS_MIN_OCCURS : min.intValueExact();
238   }
239 
240   @Override
241   public int getMaxOccurs() {
242     String max = getBinding().getMaxOccurs();
243     return max == null ? DEFAULT_GROUP_AS_MAX_OCCURS : ModelSupport.maxOccurs(max);
244   }
245 }