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.markup.MarkupLine;
9   import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
10  import gov.nist.secauto.metaschema.core.model.IBoundObject;
11  import gov.nist.secauto.metaschema.core.model.IModule;
12  import gov.nist.secauto.metaschema.core.model.constraint.AssemblyConstraintSet;
13  import gov.nist.secauto.metaschema.core.model.constraint.IModelConstrained;
14  import gov.nist.secauto.metaschema.core.model.constraint.ISource;
15  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
16  import gov.nist.secauto.metaschema.databind.IBindingContext;
17  import gov.nist.secauto.metaschema.databind.io.BindingException;
18  import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelAssembly;
19  import gov.nist.secauto.metaschema.databind.model.IBoundInstanceModel;
20  import gov.nist.secauto.metaschema.databind.model.IBoundInstanceModelAssembly;
21  import gov.nist.secauto.metaschema.databind.model.IBoundInstanceModelChoiceGroup;
22  import gov.nist.secauto.metaschema.databind.model.IBoundInstanceModelField;
23  import gov.nist.secauto.metaschema.databind.model.IBoundInstanceModelNamed;
24  import gov.nist.secauto.metaschema.databind.model.IBoundModule;
25  import gov.nist.secauto.metaschema.databind.model.IBoundProperty;
26  import gov.nist.secauto.metaschema.databind.model.annotations.AssemblyConstraints;
27  import gov.nist.secauto.metaschema.databind.model.annotations.MetaschemaAssembly;
28  import gov.nist.secauto.metaschema.databind.model.annotations.ModelUtil;
29  import gov.nist.secauto.metaschema.databind.model.annotations.ValueConstraints;
30  
31  import java.util.Map;
32  
33  import javax.xml.namespace.QName;
34  
35  import edu.umd.cs.findbugs.annotations.NonNull;
36  import edu.umd.cs.findbugs.annotations.Nullable;
37  import nl.talsmasoftware.lazy4j.Lazy;
38  
39  //TODO: implement getProperties()
40  public final class DefinitionAssembly
41      extends AbstractBoundDefinitionModelComplex<MetaschemaAssembly>
42      implements IBoundDefinitionModelAssembly,
43      IFeatureBoundContainerModelAssembly<
44          IBoundInstanceModel<?>,
45          IBoundInstanceModelNamed<?>,
46          IBoundInstanceModelField<?>,
47          IBoundInstanceModelAssembly,
48          IBoundInstanceModelChoiceGroup> {
49  
50    @NonNull
51    private final Lazy<FlagContainerSupport> flagContainer;
52    @NonNull
53    private final Lazy<AssemblyModelContainerSupport> modelContainer;
54    @NonNull
55    private final Lazy<IModelConstrained> constraints;
56    @NonNull
57    private final Lazy<QName> xmlRootQName;
58    @NonNull
59    private final Lazy<Map<String, IBoundProperty<?>>> jsonProperties;
60  
61    public static DefinitionAssembly newInstance(
62        @NonNull Class<? extends IBoundObject> clazz,
63        @NonNull IBindingContext bindingContext) {
64      MetaschemaAssembly annotation = ModelUtil.getAnnotation(clazz, MetaschemaAssembly.class);
65      Class<? extends IBoundModule> moduleClass = annotation.moduleClass();
66      return new DefinitionAssembly(clazz, annotation, moduleClass, bindingContext);
67    }
68  
69    private DefinitionAssembly(
70        @NonNull Class<? extends IBoundObject> clazz,
71        @NonNull MetaschemaAssembly annotation,
72        @NonNull Class<? extends IBoundModule> moduleClass,
73        @NonNull IBindingContext bindingContext) {
74      super(clazz, annotation, moduleClass, bindingContext);
75  
76      String rootLocalName = ModelUtil.resolveNoneOrDefault(getAnnotation().rootName(), null);
77      this.xmlRootQName = ObjectUtils.notNull(Lazy.lazy(() -> rootLocalName == null
78          ? null
79          : getContainingModule().toModelQName(rootLocalName)));
80      this.flagContainer = ObjectUtils.notNull(Lazy.lazy(() -> new FlagContainerSupport(this, null)));
81      this.modelContainer = ObjectUtils.notNull(Lazy.lazy(() -> new AssemblyModelContainerSupport(this)));
82  
83      IModule module = getContainingModule();
84  
85      this.constraints = ObjectUtils.notNull(Lazy.lazy(() -> {
86        IModelConstrained retval = new AssemblyConstraintSet();
87        ValueConstraints valueAnnotation = getAnnotation().valueConstraints();
88        ConstraintSupport.parse(valueAnnotation, ISource.modelSource(module), retval);
89  
90        AssemblyConstraints assemblyAnnotation = getAnnotation().modelConstraints();
91        ConstraintSupport.parse(assemblyAnnotation, ISource.modelSource(module), retval);
92        return retval;
93      }));
94      this.jsonProperties = ObjectUtils.notNull(Lazy.lazy(() -> getJsonProperties(null)));
95  
96      if (rootLocalName != null) {
97        bindingContext.registerBindingMatcher(this);
98      }
99    }
100 
101   @Override
102   protected void deepCopyItemInternal(IBoundObject fromObject, IBoundObject toObject) throws BindingException {
103     // copy the flags
104     super.deepCopyItemInternal(fromObject, toObject);
105 
106     for (IBoundInstanceModel<?> instance : getModelInstances()) {
107       instance.deepCopy(fromObject, toObject);
108     }
109   }
110 
111   @Override
112   public Map<String, IBoundProperty<?>> getJsonProperties() {
113     return ObjectUtils.notNull(jsonProperties.get());
114   }
115 
116   // ------------------------------------------
117   // - Start annotation driven code - CPD-OFF -
118   // ------------------------------------------
119 
120   @Override
121   @SuppressWarnings("null")
122   @NonNull
123   public FlagContainerSupport getFlagContainer() {
124     return flagContainer.get();
125   }
126 
127   @Override
128   @SuppressWarnings("null")
129   @NonNull
130   public AssemblyModelContainerSupport getModelContainer() {
131     return modelContainer.get();
132   }
133 
134   @Override
135   @NonNull
136   public IModelConstrained getConstraintSupport() {
137     return ObjectUtils.notNull(constraints.get());
138   }
139 
140   @Override
141   @Nullable
142   public String getFormalName() {
143     return ModelUtil.resolveNoneOrValue(getAnnotation().formalName());
144   }
145 
146   @Override
147   @Nullable
148   public MarkupLine getDescription() {
149     return ModelUtil.resolveToMarkupLine(getAnnotation().description());
150   }
151 
152   @Override
153   @NonNull
154   public String getName() {
155     return getAnnotation().name();
156   }
157 
158   @Override
159   @Nullable
160   public Integer getIndex() {
161     return ModelUtil.resolveDefaultInteger(getAnnotation().index());
162   }
163 
164   @Override
165   @Nullable
166   public MarkupMultiline getRemarks() {
167     return ModelUtil.resolveToMarkupMultiline(getAnnotation().description());
168   }
169 
170   @Override
171   @Nullable
172   public QName getRootXmlQName() {
173     // Overriding this is more efficient, since it is already built
174     return xmlRootQName.get();
175   }
176 
177   @Override
178   public boolean isRoot() {
179     // Overriding this is more efficient, since the root name is derived from the
180     // XML QName
181     return getRootXmlQName() != null;
182   }
183 
184   @Override
185   @Nullable
186   public String getRootName() {
187     // Overriding this is more efficient, since it is already built
188     QName qname = getRootXmlQName();
189     return qname == null ? null : qname.getLocalPart();
190   }
191 
192   @Override
193   @Nullable
194   public Integer getRootIndex() {
195     return ModelUtil.resolveDefaultInteger(getAnnotation().rootIndex());
196   }
197 
198   // ----------------------------------------
199   // - End annotation driven code - CPD-OFF -
200   // ----------------------------------------
201 }