1
2
3
4
5
6 package dev.metaschema.core.testsupport.builder;
7
8 import static org.mockito.ArgumentMatchers.eq;
9 import static org.mockito.Mockito.doReturn;
10
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.function.Function;
15 import java.util.stream.Collectors;
16
17 import dev.metaschema.core.model.IAssemblyDefinition;
18 import dev.metaschema.core.model.IAssemblyInstance;
19 import dev.metaschema.core.model.IAssemblyInstanceAbsolute;
20 import dev.metaschema.core.model.IFieldDefinition;
21 import dev.metaschema.core.model.IFieldInstance;
22 import dev.metaschema.core.model.IFlagInstance;
23 import dev.metaschema.core.model.IModule;
24 import dev.metaschema.core.model.INamedModelElement;
25 import dev.metaschema.core.model.INamedModelInstanceAbsolute;
26 import dev.metaschema.core.model.ISource;
27 import dev.metaschema.core.model.ModelType;
28 import dev.metaschema.core.model.constraint.AssemblyConstraintSet;
29 import dev.metaschema.core.qname.IEnhancedQName;
30 import dev.metaschema.core.util.CollectionUtil;
31 import dev.metaschema.core.util.ObjectUtils;
32 import edu.umd.cs.findbugs.annotations.NonNull;
33 import edu.umd.cs.findbugs.annotations.Nullable;
34
35 final class AssemblyBuilder
36 extends AbstractModelBuilder<IAssemblyBuilder>
37 implements IAssemblyBuilder {
38
39 private String rootNamespace = "";
40 private String rootName;
41
42 private List<? extends IModelBuilder<?>> modelInstances;
43
44 AssemblyBuilder() {
45
46 }
47
48 @Override
49 public AssemblyBuilder reset() {
50 super.reset();
51 this.modelInstances = CollectionUtil.emptyList();
52 return this;
53 }
54
55 @Override
56 @NonNull
57 public AssemblyBuilder rootNamespace(@NonNull String name) {
58 this.rootNamespace = name;
59 return this;
60 }
61
62 @Override
63 @NonNull
64 public AssemblyBuilder rootName(@NonNull String name) {
65 this.rootName = name;
66 return this;
67 }
68
69 @Override
70 @NonNull
71 public AssemblyBuilder rootQName(@NonNull IEnhancedQName qname) {
72 this.rootName = qname.getLocalName();
73 this.rootNamespace = qname.getNamespace();
74 return this;
75 }
76
77 @Override
78 public AssemblyBuilder modelInstances(@Nullable List<? extends IModelBuilder<?>> modelInstances) {
79 this.modelInstances = modelInstances == null ? CollectionUtil.emptyList() : modelInstances;
80 return this;
81 }
82
83
84
85
86
87
88 @NonNull
89 List<? extends IModelBuilder<?>> getModelInstanceBuilders() {
90 return this.modelInstances;
91 }
92
93
94
95
96
97
98 boolean hasModelReferences() {
99 return modelInstances.stream().anyMatch(IModelReference.class::isInstance);
100 }
101
102 @Override
103 @NonNull
104 public IAssemblyInstanceAbsolute toInstance(@NonNull IAssemblyDefinition parent) {
105 IAssemblyDefinition def = toDefinition();
106 return toInstance(parent, def);
107 }
108
109
110
111
112
113
114
115
116
117
118
119 @Override
120 @NonNull
121 public IAssemblyInstanceAbsolute toInstance(
122 @NonNull IAssemblyDefinition parent,
123 @NonNull IAssemblyDefinition definition) {
124 validate();
125
126 IAssemblyInstanceAbsolute retval = mock(IAssemblyInstanceAbsolute.class);
127 applyNamedInstance(retval, definition, parent);
128 return retval;
129 }
130
131
132
133
134
135
136 @Override
137 @NonNull
138 public IAssemblyDefinition toDefinition() {
139 return toDefinition(null);
140 }
141
142 @Override
143 @NonNull
144 public IAssemblyDefinition toDefinition(@Nullable IModule module) {
145 validate();
146
147
148 ISource source = ObjectUtils.notNull(getSource());
149
150 IAssemblyDefinition retval = mock(IAssemblyDefinition.class);
151 applyDefinition(retval, module);
152
153 Map<IEnhancedQName, IFlagInstance> flags = getFlags().stream()
154 .map(builder -> builder.source(source).toInstance(retval))
155 .collect(Collectors.toUnmodifiableMap(
156 IFlagInstance::getQName,
157 Function.identity()));
158
159 if (rootName != null) {
160 doReturn(ModelType.ASSEMBLY).when(retval).getModelType();
161
162 IEnhancedQName rootQName = IEnhancedQName.of(ObjectUtils.notNull(rootNamespace), ObjectUtils.notNull(rootName));
163 doReturn(rootQName).when(retval).getRootQName();
164 }
165
166 doReturn(new AssemblyConstraintSet(source)).when(retval).getConstraintSupport();
167
168 doReturn(flags.values()).when(retval).getFlagInstances();
169 flags.entrySet().forEach(entry -> {
170 assert entry != null;
171 doReturn(entry.getValue()).when(retval).getFlagInstanceByName(eq(entry.getKey().getIndexPosition()));
172 });
173
174 Map<IEnhancedQName, ? extends INamedModelInstanceAbsolute> modelInstances = this.modelInstances.stream()
175 .map(builder -> builder.source(source).toInstance(retval))
176 .collect(Collectors.toUnmodifiableMap(
177 INamedModelInstanceAbsolute::getQName,
178 Function.identity()));
179
180 doReturn(modelInstances.values()).when(retval).getModelInstances();
181 doReturn(CollectionUtil.emptyMap()).when(retval).getChoiceGroupInstances();
182 doReturn(CollectionUtil.emptyList()).when(retval).getChoiceInstances();
183 modelInstances.forEach((key, value) -> {
184 doReturn(value).when(retval).getNamedModelInstanceByName(eq(key.getIndexPosition()));
185
186 if (value instanceof IAssemblyInstance) {
187 doReturn(value).when(retval).getAssemblyInstanceByName(eq(key.getIndexPosition()));
188 } else if (value instanceof IFieldInstance) {
189 doReturn(value).when(retval).getFieldInstanceByName(eq(key.getIndexPosition()));
190 }
191 });
192 doReturn(
193 modelInstances.values().stream()
194 .filter(IAssemblyInstance.class::isInstance)
195 .collect(Collectors.toList()))
196 .when(retval).getAssemblyInstances();
197 doReturn(
198 modelInstances.values().stream()
199 .filter(IFieldInstance.class::isInstance)
200 .collect(Collectors.toList()))
201 .when(retval).getFieldInstances();
202 return retval;
203 }
204
205
206
207
208
209
210
211
212
213 @NonNull
214 IAssemblyDefinition toDefinitionShell(@Nullable IModule module) {
215 validate();
216
217
218 ISource source = ObjectUtils.notNull(getSource());
219
220 IAssemblyDefinition retval = mock(IAssemblyDefinition.class);
221 applyDefinition(retval, module);
222
223 Map<IEnhancedQName, IFlagInstance> flags = getFlags().stream()
224 .map(builder -> builder.source(source).toInstance(retval))
225 .collect(Collectors.toUnmodifiableMap(
226 IFlagInstance::getQName,
227 Function.identity()));
228
229 if (rootName != null) {
230 doReturn(ModelType.ASSEMBLY).when(retval).getModelType();
231
232 IEnhancedQName rootQName = IEnhancedQName.of(ObjectUtils.notNull(rootNamespace), ObjectUtils.notNull(rootName));
233 doReturn(rootQName).when(retval).getRootQName();
234 }
235
236 doReturn(new AssemblyConstraintSet(source)).when(retval).getConstraintSupport();
237
238 doReturn(flags.values()).when(retval).getFlagInstances();
239 flags.entrySet().forEach(entry -> {
240 assert entry != null;
241 doReturn(entry.getValue()).when(retval).getFlagInstanceByName(eq(entry.getKey().getIndexPosition()));
242 });
243
244
245 doReturn(CollectionUtil.emptyList()).when(retval).getModelInstances();
246 doReturn(CollectionUtil.emptyMap()).when(retval).getChoiceGroupInstances();
247 doReturn(CollectionUtil.emptyList()).when(retval).getChoiceInstances();
248 doReturn(CollectionUtil.emptyList()).when(retval).getAssemblyInstances();
249 doReturn(CollectionUtil.emptyList()).when(retval).getFieldInstances();
250
251 return retval;
252 }
253
254
255
256
257
258
259
260
261
262
263
264
265 void resolveModelInstances(
266 @NonNull IAssemblyDefinition definition,
267 @NonNull Map<String, IAssemblyDefinition> assemblyDefinitions,
268 @NonNull Map<String, IFieldDefinition> fieldDefinitions) {
269
270 ISource source = ObjectUtils.notNull(getSource());
271 List<INamedModelInstanceAbsolute> instances = new ArrayList<>();
272
273 for (IModelBuilder<?> builder : modelInstances) {
274 INamedModelInstanceAbsolute instance;
275 if (builder instanceof IModelReference) {
276 IModelReference ref = (IModelReference) builder;
277 String refName = ref.getReferencedName();
278
279 if (builder instanceof AssemblyReference) {
280 IAssemblyDefinition refDef = assemblyDefinitions.get(refName);
281 if (refDef == null) {
282 throw new IllegalStateException("Assembly reference '" + refName + "' not found in module");
283 }
284
285 IAssemblyBuilder instanceBuilder = IAssemblyBuilder.builder()
286 .name(refName)
287 .namespace(ObjectUtils.notNull(getNamespace()))
288 .source(source);
289 instance = instanceBuilder.toInstance(definition, refDef);
290 } else if (builder instanceof FieldReference) {
291 IFieldDefinition refDef = fieldDefinitions.get(refName);
292 if (refDef == null) {
293 throw new IllegalStateException("Field reference '" + refName + "' not found in module");
294 }
295
296 IFieldBuilder instanceBuilder = IFieldBuilder.builder()
297 .name(refName)
298 .namespace(ObjectUtils.notNull(getNamespace()))
299 .source(source);
300 instance = instanceBuilder.toInstance(definition, refDef);
301 } else {
302 throw new IllegalStateException("Unknown reference type: " + builder.getClass().getName());
303 }
304 } else {
305
306 instance = builder.source(source).toInstance(definition);
307 }
308 instances.add(instance);
309 }
310
311
312 Map<IEnhancedQName, INamedModelInstanceAbsolute> instanceMap = instances.stream()
313 .collect(Collectors.toUnmodifiableMap(
314 INamedModelInstanceAbsolute::getQName,
315 Function.identity()));
316
317 doReturn(new ArrayList<>(instanceMap.values())).when(definition).getModelInstances();
318 instanceMap.forEach((key, value) -> {
319 doReturn(value).when(definition).getNamedModelInstanceByName(eq(key.getIndexPosition()));
320
321 if (value instanceof IAssemblyInstance) {
322 doReturn(value).when(definition).getAssemblyInstanceByName(eq(key.getIndexPosition()));
323 } else if (value instanceof IFieldInstance) {
324 doReturn(value).when(definition).getFieldInstanceByName(eq(key.getIndexPosition()));
325 }
326 });
327
328 List<IAssemblyInstance> assemblyInstances = instanceMap.values().stream()
329 .filter(IAssemblyInstance.class::isInstance)
330 .map(IAssemblyInstance.class::cast)
331 .collect(Collectors.toList());
332 doReturn(assemblyInstances).when(definition).getAssemblyInstances();
333
334 List<IFieldInstance> fieldInstances = instanceMap.values().stream()
335 .filter(IFieldInstance.class::isInstance)
336 .map(IFieldInstance.class::cast)
337 .collect(Collectors.toList());
338 doReturn(fieldInstances).when(definition).getFieldInstances();
339 }
340
341 @Override
342 protected void applyNamed(INamedModelElement element) {
343 super.applyNamed(element);
344 doReturn(ModelType.ASSEMBLY).when(element).getModelType();
345 }
346 }