1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package gov.nist.secauto.metaschema.databind.model;
28
29 import gov.nist.secauto.metaschema.core.model.IChoiceInstance;
30 import gov.nist.secauto.metaschema.core.model.IModelContainerSupport;
31 import gov.nist.secauto.metaschema.core.util.CollectionUtil;
32 import gov.nist.secauto.metaschema.core.util.CustomCollectors;
33 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
34 import gov.nist.secauto.metaschema.databind.IBindingContext;
35 import gov.nist.secauto.metaschema.databind.model.annotations.BoundAssembly;
36 import gov.nist.secauto.metaschema.databind.model.annotations.BoundField;
37 import gov.nist.secauto.metaschema.databind.model.annotations.Ignore;
38
39 import java.util.Arrays;
40 import java.util.Collection;
41 import java.util.LinkedHashMap;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Objects;
45 import java.util.function.Function;
46 import java.util.stream.Collectors;
47 import java.util.stream.Stream;
48
49 import edu.umd.cs.findbugs.annotations.NonNull;
50
51 class ClassBindingModelContainerSupport
52 implements IModelContainerSupport<IBoundNamedModelInstance, IBoundNamedModelInstance, IBoundFieldInstance,
53 IBoundAssemblyInstance, IChoiceInstance> {
54 @NonNull
55 private final Map<String, IBoundNamedModelInstance> modelInstances;
56 @NonNull
57 private final Map<String, IBoundFieldInstance> fieldInstances;
58 @NonNull
59 private final Map<String, IBoundAssemblyInstance> assemblyInstances;
60
61 public ClassBindingModelContainerSupport(
62 @NonNull IAssemblyClassBinding classBinding) {
63 Class<?> clazz = classBinding.getBoundClass();
64 this.modelInstances = CollectionUtil.unmodifiableMap(ObjectUtils.notNull(
65 getModelInstanceFieldStream(classBinding, clazz)
66 .collect(Collectors.toMap(instance -> instance.getEffectiveName(), Function.identity(),
67 CustomCollectors.useLastMapper(),
68 LinkedHashMap::new))));
69
70 this.fieldInstances = CollectionUtil.unmodifiableMap(ObjectUtils.notNull(
71 getNamedModelInstanceMap().values().stream()
72 .filter(instance -> instance instanceof IBoundFieldInstance)
73 .map(instance -> (IBoundFieldInstance) instance)
74 .map(ObjectUtils::notNull)
75 .collect(Collectors.toMap(IBoundFieldInstance::getEffectiveName, Function.identity(),
76 CustomCollectors.useLastMapper(),
77 LinkedHashMap::new))));
78
79 this.assemblyInstances = CollectionUtil.unmodifiableMap(ObjectUtils.notNull(
80 getNamedModelInstanceMap().values().stream()
81 .filter(instance -> instance instanceof IBoundAssemblyInstance)
82 .map(instance -> (IBoundAssemblyInstance) instance)
83 .map(ObjectUtils::notNull)
84 .collect(Collectors.toMap(IBoundAssemblyInstance::getEffectiveName, Function.identity(),
85 CustomCollectors.useLastMapper(),
86 LinkedHashMap::new))));
87 }
88
89 protected Stream<IBoundNamedModelInstance> getModelInstanceFieldStream(
90 @NonNull IAssemblyClassBinding classBinding,
91 @NonNull Class<?> clazz) {
92
93 Stream<IBoundNamedModelInstance> superInstances;
94 Class<?> superClass = clazz.getSuperclass();
95 if (superClass == null) {
96 superInstances = Stream.empty();
97 } else {
98
99 superInstances = getModelInstanceFieldStream(classBinding, superClass);
100 }
101
102 IBindingContext bindingContext = classBinding.getBindingContext();
103 return Stream.concat(superInstances, Arrays.stream(clazz.getDeclaredFields())
104
105 .filter(field -> !field.isAnnotationPresent(Ignore.class))
106
107 .filter(field -> field.isAnnotationPresent(BoundField.class) || field.isAnnotationPresent(BoundAssembly.class))
108 .map(field -> {
109 assert field != null;
110
111 IBoundNamedModelInstance retval;
112 if (field.isAnnotationPresent(BoundAssembly.class)
113 && bindingContext.getClassBinding(IBoundNamedModelInstance.getItemType(field)) != null) {
114 retval = IBoundAssemblyInstance.newInstance(field, classBinding);
115 } else if (field.isAnnotationPresent(BoundField.class)) {
116 retval = IBoundFieldInstance.newInstance(field, classBinding);
117 } else {
118 throw new IllegalStateException(
119 String.format("The field '%s' on class '%s' is not bound", field.getName(), clazz.getName()));
120 }
121
122 return retval;
123 })
124 .filter(Objects::nonNull)
125 .map(ObjectUtils::notNull));
126 }
127
128 @Override
129 public Collection<IBoundNamedModelInstance> getModelInstances() {
130 return ObjectUtils.notNull(getNamedModelInstanceMap().values());
131 }
132
133 @Override
134 public Map<String, IBoundNamedModelInstance> getNamedModelInstanceMap() {
135 return modelInstances;
136 }
137
138 @Override
139 public Map<String, IBoundFieldInstance> getFieldInstanceMap() {
140 return fieldInstances;
141 }
142
143 @Override
144 public Map<String, IBoundAssemblyInstance> getAssemblyInstanceMap() {
145 return assemblyInstances;
146 }
147
148 @Override
149 public List<IChoiceInstance> getChoiceInstances() {
150
151 return CollectionUtil.emptyList();
152 }
153 }