1
2
3
4
5
6 package dev.metaschema.databind.model.impl;
7
8 import java.util.Arrays;
9 import java.util.LinkedHashMap;
10 import java.util.Map;
11 import java.util.Set;
12 import java.util.stream.Collectors;
13
14 import dev.metaschema.core.datatype.markup.MarkupLine;
15 import dev.metaschema.core.datatype.markup.MarkupMultiline;
16 import dev.metaschema.core.model.IAttributable;
17 import dev.metaschema.core.model.IBoundObject;
18 import dev.metaschema.core.model.IChoiceInstance;
19 import dev.metaschema.core.model.IContainerModelAssemblySupport;
20 import dev.metaschema.core.model.ISource;
21 import dev.metaschema.core.model.constraint.AssemblyConstraintSet;
22 import dev.metaschema.core.model.constraint.IModelConstrained;
23 import dev.metaschema.core.model.util.ModuleUtils;
24 import dev.metaschema.core.qname.IEnhancedQName;
25 import dev.metaschema.core.util.CollectionUtil;
26 import dev.metaschema.core.util.ObjectUtils;
27 import dev.metaschema.databind.IBindingContext;
28 import dev.metaschema.databind.io.BindingException;
29 import dev.metaschema.databind.model.IBoundDefinitionModelAssembly;
30 import dev.metaschema.databind.model.IBoundInstanceModel;
31 import dev.metaschema.databind.model.IBoundInstanceModelAssembly;
32 import dev.metaschema.databind.model.IBoundInstanceModelChoiceGroup;
33 import dev.metaschema.databind.model.IBoundInstanceModelField;
34 import dev.metaschema.databind.model.IBoundInstanceModelNamed;
35 import dev.metaschema.databind.model.IBoundModule;
36 import dev.metaschema.databind.model.IBoundProperty;
37 import dev.metaschema.databind.model.annotations.AssemblyConstraints;
38 import dev.metaschema.databind.model.annotations.MetaschemaAssembly;
39 import dev.metaschema.databind.model.annotations.ModelUtil;
40 import dev.metaschema.databind.model.annotations.ValueConstraints;
41 import edu.umd.cs.findbugs.annotations.NonNull;
42 import edu.umd.cs.findbugs.annotations.Nullable;
43 import nl.talsmasoftware.lazy4j.Lazy;
44
45
46
47
48
49 @SuppressWarnings("PMD.CouplingBetweenObjects")
50 public final class DefinitionAssembly
51 extends AbstractBoundDefinitionModelComplex<MetaschemaAssembly>
52 implements IBoundDefinitionModelAssembly {
53
54 @NonNull
55 private final Lazy<FlagContainerSupport> flagContainer;
56 @NonNull
57 private final Lazy<IContainerModelAssemblySupport<
58 IBoundInstanceModel<?>,
59 IBoundInstanceModelNamed<?>,
60 IBoundInstanceModelField<?>,
61 IBoundInstanceModelAssembly,
62 IChoiceInstance,
63 IBoundInstanceModelChoiceGroup>> modelContainer;
64 @NonNull
65 private final Lazy<IModelConstrained> constraints;
66 @NonNull
67 private final Lazy<IEnhancedQName> xmlRootQName;
68 @NonNull
69 private final Lazy<Map<String, IBoundProperty<?>>> jsonProperties;
70 @NonNull
71 private final Lazy<Map<IAttributable.Key, Set<String>>> properties;
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 @NonNull
88 public static DefinitionAssembly newInstance(
89 @NonNull Class<? extends IBoundObject> clazz,
90 @NonNull MetaschemaAssembly annotation,
91 @NonNull IBoundModule module,
92 @NonNull IBindingContext bindingContext) {
93 return new DefinitionAssembly(clazz, annotation, module, bindingContext);
94 }
95
96 private DefinitionAssembly(
97 @NonNull Class<? extends IBoundObject> clazz,
98 @NonNull MetaschemaAssembly annotation,
99 @NonNull IBoundModule module,
100 @NonNull IBindingContext bindingContext) {
101 super(clazz, annotation, module, bindingContext);
102
103 String rootLocalName = ModelUtil.resolveNoneOrDefault(getAnnotation().rootName(), null);
104 this.xmlRootQName = ObjectUtils.notNull(Lazy.of(() -> rootLocalName == null
105 ? null
106 : ModuleUtils.parseModelName(getContainingModule(), rootLocalName)));
107 this.flagContainer = ObjectUtils.notNull(Lazy.of(() -> new FlagContainerSupport(this, null)));
108 this.modelContainer = ObjectUtils.notNull(Lazy.of(() -> AssemblyModelGenerator.of(this)));
109
110 ISource source = module.getSource();
111 this.constraints = ObjectUtils.notNull(Lazy.of(() -> {
112 IModelConstrained retval = new AssemblyConstraintSet(source);
113 ValueConstraints valueAnnotation = getAnnotation().valueConstraints();
114 ConstraintSupport.parse(valueAnnotation, source, retval);
115
116 AssemblyConstraints assemblyAnnotation = getAnnotation().modelConstraints();
117 ConstraintSupport.parse(assemblyAnnotation, source, retval);
118 return retval;
119 }));
120 this.jsonProperties = ObjectUtils.notNull(Lazy.of(() -> getJsonProperties(null)));
121 this.properties = ObjectUtils.notNull(
122 Lazy.of(() -> CollectionUtil.unmodifiableMap(ObjectUtils.notNull(
123 Arrays.stream(annotation.properties())
124 .map(ModelUtil::toPropertyEntry)
125 .collect(
126 Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v2, LinkedHashMap::new))))));
127 }
128
129 @Override
130 protected void deepCopyItemInternal(IBoundObject fromObject, IBoundObject toObject) throws BindingException {
131
132 super.deepCopyItemInternal(fromObject, toObject);
133
134 for (IBoundInstanceModel<?> instance : getModelInstances()) {
135 assert instance != null;
136
137 instance.deepCopy(fromObject, toObject);
138 }
139 }
140
141 @Override
142 public Map<String, IBoundProperty<?>> getJsonProperties() {
143 return ObjectUtils.notNull(jsonProperties.get());
144 }
145
146
147
148
149
150 @Override
151 @SuppressWarnings("null")
152 @NonNull
153 public FlagContainerSupport getFlagContainer() {
154 return flagContainer.get();
155 }
156
157 @Override
158 @SuppressWarnings("null")
159 @NonNull
160 public IContainerModelAssemblySupport<
161 IBoundInstanceModel<?>,
162 IBoundInstanceModelNamed<?>,
163 IBoundInstanceModelField<?>,
164 IBoundInstanceModelAssembly,
165 IChoiceInstance,
166 IBoundInstanceModelChoiceGroup> getModelContainer() {
167 return modelContainer.get();
168 }
169
170 @Override
171 @NonNull
172 public IModelConstrained getConstraintSupport() {
173 return ObjectUtils.notNull(constraints.get());
174 }
175
176 @Override
177 @Nullable
178 public String getFormalName() {
179 return ModelUtil.resolveNoneOrValue(getAnnotation().formalName());
180 }
181
182 @Override
183 @Nullable
184 public MarkupLine getDescription() {
185 return ModelUtil.resolveToMarkupLine(getAnnotation().description());
186 }
187
188 @Override
189 @NonNull
190 public String getName() {
191 return getAnnotation().name();
192 }
193
194 @Override
195 @Nullable
196 public Integer getIndex() {
197 return ModelUtil.resolveDefaultInteger(getAnnotation().index());
198 }
199
200 @Override
201 public Map<Key, Set<String>> getProperties() {
202 return ObjectUtils.notNull(properties.get());
203 }
204
205 @Override
206 @Nullable
207 public MarkupMultiline getRemarks() {
208 return ModelUtil.resolveToMarkupMultiline(getAnnotation().description());
209 }
210
211 @Override
212 @Nullable
213 public IEnhancedQName getRootQName() {
214
215 return xmlRootQName.get();
216 }
217
218 @Override
219 public boolean isRoot() {
220
221
222 return getRootQName() != null;
223 }
224
225 @Override
226 @Nullable
227 public String getRootName() {
228
229 IEnhancedQName qname = getRootQName();
230 return qname == null ? null : qname.getLocalName();
231 }
232
233 @Override
234 @Nullable
235 public Integer getRootIndex() {
236 return ModelUtil.resolveDefaultInteger(getAnnotation().rootIndex());
237 }
238
239
240
241
242 }