1
2
3
4
5
6 package gov.nist.secauto.metaschema.databind.model.impl;
7
8 import gov.nist.secauto.metaschema.core.model.DefaultAssemblyModelBuilder;
9 import gov.nist.secauto.metaschema.core.model.IChoiceInstance;
10 import gov.nist.secauto.metaschema.core.model.IContainerModelAssemblySupport;
11 import gov.nist.secauto.metaschema.core.util.CollectionUtil;
12 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
13 import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelAssembly;
14 import gov.nist.secauto.metaschema.databind.model.IBoundInstanceModel;
15 import gov.nist.secauto.metaschema.databind.model.IBoundInstanceModelAssembly;
16 import gov.nist.secauto.metaschema.databind.model.IBoundInstanceModelChoiceGroup;
17 import gov.nist.secauto.metaschema.databind.model.IBoundInstanceModelField;
18 import gov.nist.secauto.metaschema.databind.model.IBoundInstanceModelNamed;
19 import gov.nist.secauto.metaschema.databind.model.annotations.BoundAssembly;
20 import gov.nist.secauto.metaschema.databind.model.annotations.BoundChoiceGroup;
21 import gov.nist.secauto.metaschema.databind.model.annotations.BoundField;
22 import gov.nist.secauto.metaschema.databind.model.annotations.Ignore;
23
24 import java.lang.reflect.Field;
25 import java.util.Arrays;
26 import java.util.List;
27 import java.util.Objects;
28 import java.util.stream.Collectors;
29 import java.util.stream.Stream;
30
31 import edu.umd.cs.findbugs.annotations.NonNull;
32
33 final class AssemblyModelGenerator {
34
35 @SuppressWarnings("PMD.ShortMethodName")
36 @NonNull
37 public static IContainerModelAssemblySupport<
38 IBoundInstanceModel<?>,
39 IBoundInstanceModelNamed<?>,
40 IBoundInstanceModelField<?>,
41 IBoundInstanceModelAssembly,
42 IChoiceInstance,
43 IBoundInstanceModelChoiceGroup> of(@NonNull DefinitionAssembly containingDefinition) {
44 DefaultAssemblyModelBuilder<IBoundInstanceModel<?>,
45 IBoundInstanceModelNamed<?>,
46 IBoundInstanceModelField<?>,
47 IBoundInstanceModelAssembly,
48 IChoiceInstance,
49 IBoundInstanceModelChoiceGroup> builder = new DefaultAssemblyModelBuilder<>();
50
51 List<IBoundInstanceModel<?>> modelInstances = CollectionUtil.unmodifiableList(ObjectUtils.notNull(
52 getModelInstanceStream(containingDefinition, containingDefinition.getBoundClass())
53 .collect(Collectors.toUnmodifiableList())));
54
55 for (IBoundInstanceModel<?> instance : modelInstances) {
56 if (instance instanceof IBoundInstanceModelNamed) {
57 IBoundInstanceModelNamed<?> named = (IBoundInstanceModelNamed<?>) instance;
58 if (instance instanceof IBoundInstanceModelField) {
59 builder.append((IBoundInstanceModelField<?>) named);
60 } else if (instance instanceof IBoundInstanceModelAssembly) {
61 builder.append((IBoundInstanceModelAssembly) named);
62 }
63 } else if (instance instanceof IBoundInstanceModelChoiceGroup) {
64 IBoundInstanceModelChoiceGroup choiceGroup = (IBoundInstanceModelChoiceGroup) instance;
65 builder.append(choiceGroup);
66 }
67 }
68 return builder.buildAssembly();
69 }
70
71 private static IBoundInstanceModel<?> newBoundModelInstance(
72 @NonNull Field field,
73 @NonNull IBoundDefinitionModelAssembly definition) {
74 IBoundInstanceModel<?> retval = null;
75 if (field.isAnnotationPresent(BoundAssembly.class)) {
76 retval = IBoundInstanceModelAssembly.newInstance(field, definition);
77 } else if (field.isAnnotationPresent(BoundField.class)) {
78 retval = IBoundInstanceModelField.newInstance(field, definition);
79 } else if (field.isAnnotationPresent(BoundChoiceGroup.class)) {
80 retval = IBoundInstanceModelChoiceGroup.newInstance(field, definition);
81 }
82 return retval;
83 }
84
85 @NonNull
86 private static Stream<IBoundInstanceModel<?>> getModelInstanceStream(
87 @NonNull IBoundDefinitionModelAssembly definition,
88 @NonNull Class<?> clazz) {
89
90 Stream<IBoundInstanceModel<?>> superInstances;
91 Class<?> superClass = clazz.getSuperclass();
92 if (superClass == null) {
93 superInstances = Stream.empty();
94 } else {
95
96 superInstances = getModelInstanceStream(definition, superClass);
97 }
98
99 return ObjectUtils.notNull(Stream.concat(superInstances, Arrays.stream(clazz.getDeclaredFields())
100
101 .filter(field -> !field.isAnnotationPresent(Ignore.class))
102
103 .filter(field -> field.isAnnotationPresent(BoundField.class)
104 || field.isAnnotationPresent(BoundAssembly.class)
105 || field.isAnnotationPresent(BoundChoiceGroup.class))
106 .map(field -> {
107 assert field != null;
108
109 IBoundInstanceModel<?> retval = newBoundModelInstance(field, definition);
110 if (retval == null) {
111 throw new IllegalStateException(
112 String.format("The field '%s' on class '%s' is not bound", field.getName(), clazz.getName()));
113 }
114 return retval;
115 })
116 .filter(Objects::nonNull)));
117 }
118
119 private AssemblyModelGenerator() {
120
121 }
122 }