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.AbstractModule;
30 import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition;
31 import gov.nist.secauto.metaschema.core.model.IFieldDefinition;
32 import gov.nist.secauto.metaschema.core.model.IFlagDefinition;
33 import gov.nist.secauto.metaschema.core.model.IModule;
34 import gov.nist.secauto.metaschema.core.util.CollectionUtil;
35 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
36 import gov.nist.secauto.metaschema.databind.IBindingContext;
37 import gov.nist.secauto.metaschema.databind.model.annotations.Module;
38
39 import java.lang.reflect.Constructor;
40 import java.lang.reflect.InvocationTargetException;
41 import java.net.URI;
42 import java.util.ArrayList;
43 import java.util.Arrays;
44 import java.util.Collection;
45 import java.util.Collections;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.function.Function;
49 import java.util.stream.Collectors;
50
51 import edu.umd.cs.findbugs.annotations.NonNull;
52
53 public abstract class AbstractBoundModule
54 extends AbstractModule {
55 @NonNull
56 private final IBindingContext bindingContext;
57 private Map<String, IAssemblyClassBinding> assemblyDefinitions;
58 private Map<String, IFieldClassBinding> fieldDefinitions;
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 @NonNull
74 public static IModule createInstance(
75 @NonNull Class<? extends IModule> clazz,
76 @NonNull IBindingContext bindingContext) {
77
78 if (!clazz.isAnnotationPresent(Module.class)) {
79 throw new IllegalStateException(String.format("The class '%s' is missing the '%s' annotation",
80 clazz.getCanonicalName(), Module.class.getCanonicalName()));
81 }
82
83 Module moduleAnnotation = clazz.getAnnotation(Module.class);
84
85 List<IModule> importedModules;
86 if (moduleAnnotation.imports().length > 0) {
87 importedModules = new ArrayList<>(moduleAnnotation.imports().length);
88 for (Class<? extends IModule> importClass : moduleAnnotation.imports()) {
89 assert importClass != null;
90 IModule moduleImport = bindingContext.getModuleByClass(importClass);
91 importedModules.add(moduleImport);
92 }
93 } else {
94 importedModules = CollectionUtil.emptyList();
95 }
96 return createInstance(clazz, bindingContext, importedModules);
97 }
98
99 @NonNull
100 private static IModule createInstance(
101 @NonNull Class<? extends IModule> clazz,
102 @NonNull IBindingContext bindingContext,
103 @NonNull List<? extends IModule> importedModules) {
104
105 Constructor<? extends IModule> constructor;
106 try {
107 constructor = clazz.getDeclaredConstructor(List.class, IBindingContext.class);
108 } catch (NoSuchMethodException ex) {
109 throw new IllegalArgumentException(ex);
110 }
111
112 try {
113 return ObjectUtils.notNull(constructor.newInstance(importedModules, bindingContext));
114 } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
115 throw new IllegalArgumentException(ex);
116 }
117 }
118
119
120
121
122
123
124
125
126
127 protected AbstractBoundModule(
128 @NonNull List<? extends IModule> importedModules,
129 @NonNull IBindingContext bindingContext) {
130 super(importedModules);
131 this.bindingContext = bindingContext;
132 }
133
134
135
136
137
138
139 @NonNull
140 protected IBindingContext getBindingContext() {
141 return bindingContext;
142 }
143
144 @Override
145 public URI getLocation() {
146
147 return null;
148 }
149
150 @NonNull
151 protected Class<?>[] getAssemblyClasses() {
152 Class<?>[] retval;
153 if (getClass().isAnnotationPresent(Module.class)) {
154 Module moduleAnnotation = getClass().getAnnotation(Module.class);
155 retval = moduleAnnotation.assemblies();
156 } else {
157 retval = new Class<?>[] {};
158 }
159 return retval;
160 }
161
162 @NonNull
163 protected Class<?>[] getFieldClasses() {
164 Class<?>[] retval;
165 if (getClass().isAnnotationPresent(Module.class)) {
166 Module moduleAnnotation = getClass().getAnnotation(Module.class);
167 retval = moduleAnnotation.fields();
168 } else {
169 retval = new Class<?>[] {};
170 }
171 return retval;
172 }
173
174 protected void initDefinitions() {
175 synchronized (this) {
176 if (assemblyDefinitions == null) {
177 IBindingContext bindingContext = getBindingContext();
178 this.assemblyDefinitions = Arrays.stream(getAssemblyClasses())
179 .map(clazz -> {
180 assert clazz != null;
181 return (IAssemblyClassBinding) ObjectUtils.requireNonNull(bindingContext.getClassBinding(clazz));
182 })
183 .collect(Collectors.toUnmodifiableMap(
184 IAssemblyClassBinding::getName,
185 Function.identity()));
186 this.fieldDefinitions = Arrays.stream(getFieldClasses())
187 .map(clazz -> {
188 assert clazz != null;
189 return (IFieldClassBinding) ObjectUtils.requireNonNull(bindingContext.getClassBinding(clazz));
190 })
191 .collect(Collectors.toUnmodifiableMap(
192 IFieldClassBinding::getName,
193 Function.identity()));
194 }
195 }
196
197 }
198
199 @SuppressWarnings("null")
200 protected @NonNull Map<String, ? extends IAssemblyDefinition> getAssemblyDefinitionMap() {
201 initDefinitions();
202 return assemblyDefinitions;
203 }
204
205 @SuppressWarnings("null")
206 @Override
207 public Collection<? extends IAssemblyDefinition> getAssemblyDefinitions() {
208 return getAssemblyDefinitionMap().values();
209 }
210
211 @Override
212 public IAssemblyDefinition getAssemblyDefinitionByName(@NonNull String name) {
213 return getAssemblyDefinitionMap().get(name);
214 }
215
216 protected Map<String, ? extends IFieldDefinition> getFieldDefinitionMap() {
217 initDefinitions();
218 return fieldDefinitions;
219 }
220
221 @SuppressWarnings("null")
222 @Override
223 public Collection<? extends IFieldDefinition> getFieldDefinitions() {
224 return getFieldDefinitionMap().values();
225 }
226
227 @Override
228 public IFieldDefinition getFieldDefinitionByName(@NonNull String name) {
229 return getFieldDefinitionMap().get(name);
230 }
231
232 @NonNull
233 public Map<String, ? extends IFlagDefinition> getFlagDefinitionMap() {
234
235 return CollectionUtil.emptyMap();
236 }
237
238 @SuppressWarnings("null")
239 @Override
240 public Collection<? extends IFlagDefinition> getFlagDefinitions() {
241
242 return Collections.emptyList();
243 }
244
245 @Override
246 public IFlagDefinition getFlagDefinitionByName(@NonNull String name) {
247
248 return null;
249 }
250 }