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.core.model;
28
29 import gov.nist.secauto.metaschema.core.util.CollectionUtil;
30 import gov.nist.secauto.metaschema.core.util.CustomCollectors;
31 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
32
33 import org.apache.logging.log4j.LogManager;
34 import org.apache.logging.log4j.Logger;
35
36 import java.util.Collection;
37 import java.util.List;
38 import java.util.Locale;
39 import java.util.Map;
40 import java.util.function.Function;
41 import java.util.function.Predicate;
42 import java.util.stream.Collectors;
43 import java.util.stream.Stream;
44
45 import edu.umd.cs.findbugs.annotations.NonNull;
46 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
47
48
49
50
51 @SuppressWarnings("PMD.CouplingBetweenObjects")
52 public abstract class AbstractModule
53 implements IModule {
54 private static final Logger LOGGER = LogManager.getLogger(AbstractModule.class);
55
56 @NonNull
57 private final List<? extends IModule> importedModules;
58 private Map<String, IFlagDefinition> exportedFlagDefinitions;
59 private Map<String, IFieldDefinition> exportedFieldDefinitions;
60 private Map<String, IAssemblyDefinition> exportedAssemblyDefinitions;
61
62
63
64
65
66
67
68
69 public AbstractModule(@NonNull List<? extends IModule> importedModules) {
70 this.importedModules
71 = CollectionUtil.unmodifiableList(ObjectUtils.requireNonNull(importedModules, "importedModules"));
72 }
73
74 @Override
75 @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "interface doesn't allow modification")
76 public List<? extends IModule> getImportedModules() {
77 return importedModules;
78 }
79
80 private Map<String, ? extends IModule> getImportedModulesByShortName() {
81 return importedModules.stream().collect(Collectors.toMap(IModule::getShortName, Function.identity()));
82 }
83
84 @Override
85 public IModule getImportedModuleByShortName(String name) {
86 return getImportedModulesByShortName().get(name);
87 }
88
89 @SuppressWarnings("null")
90 @Override
91 public Collection<? extends IFlagDefinition> getExportedFlagDefinitions() {
92 return getExportedFlagDefinitionMap().values();
93 }
94
95 @Override
96 public IFlagDefinition getExportedFlagDefinitionByName(String name) {
97 return getExportedFlagDefinitionMap().get(name);
98 }
99
100 private Map<String, ? extends IFlagDefinition> getExportedFlagDefinitionMap() {
101 initExports();
102 return exportedFlagDefinitions;
103 }
104
105 @SuppressWarnings("null")
106 @Override
107 public Collection<? extends IFieldDefinition> getExportedFieldDefinitions() {
108 return getExportedFieldDefinitionMap().values();
109 }
110
111 @Override
112 public IFieldDefinition getExportedFieldDefinitionByName(String name) {
113 return getExportedFieldDefinitionMap().get(name);
114 }
115
116 private Map<String, ? extends IFieldDefinition> getExportedFieldDefinitionMap() {
117 initExports();
118 return exportedFieldDefinitions;
119 }
120
121 @SuppressWarnings("null")
122 @Override
123 public Collection<? extends IAssemblyDefinition> getExportedAssemblyDefinitions() {
124 return getExportedAssemblyDefinitionMap().values();
125 }
126
127 @Override
128 public IAssemblyDefinition getExportedAssemblyDefinitionByName(String name) {
129 return getExportedAssemblyDefinitionMap().get(name);
130 }
131
132 private Map<String, ? extends IAssemblyDefinition> getExportedAssemblyDefinitionMap() {
133 initExports();
134 return exportedAssemblyDefinitions;
135 }
136
137
138
139
140
141 protected void initExports() {
142 synchronized (this) {
143 if (exportedFlagDefinitions == null) {
144
145 Predicate<IDefinition> filter = IModule.allNonLocalDefinitions();
146 Stream<? extends IFlagDefinition> flags = getFlagDefinitions().stream()
147 .filter(filter);
148 Stream<? extends IFieldDefinition> fields = getFieldDefinitions().stream()
149 .filter(filter);
150 Stream<? extends IAssemblyDefinition> assemblies = getAssemblyDefinitions().stream()
151 .filter(filter);
152
153
154 if (!getImportedModules().isEmpty()) {
155 Stream<? extends IFlagDefinition> importedFlags = Stream.empty();
156 Stream<? extends IFieldDefinition> importedFields = Stream.empty();
157 Stream<? extends IAssemblyDefinition> importedAssemblies = Stream.empty();
158
159 for (IModule module : getImportedModules()) {
160 importedFlags = Stream.concat(importedFlags, module.getExportedFlagDefinitions().stream());
161 importedFields = Stream.concat(importedFields, module.getExportedFieldDefinitions().stream());
162 importedAssemblies
163 = Stream.concat(importedAssemblies, module.getExportedAssemblyDefinitions().stream());
164 }
165
166 flags = Stream.concat(importedFlags, flags);
167 fields = Stream.concat(importedFields, fields);
168 assemblies = Stream.concat(importedAssemblies, assemblies);
169 }
170
171
172
173
174 Map<String, IFlagDefinition> exportedFlagDefinitions = flags.collect(
175 CustomCollectors.toMap(
176 IFlagDefinition::getName,
177 CustomCollectors.identity(),
178 AbstractModule::handleShadowedDefinitions));
179 Map<String, IFieldDefinition> exportedFieldDefinitions = fields.collect(
180 CustomCollectors.toMap(
181 IFieldDefinition::getName,
182 CustomCollectors.identity(),
183 AbstractModule::handleShadowedDefinitions));
184 Map<String, IAssemblyDefinition> exportedAssemblyDefinitions = assemblies.collect(
185 CustomCollectors.toMap(
186 IAssemblyDefinition::getName,
187 CustomCollectors.identity(),
188 AbstractModule::handleShadowedDefinitions));
189
190 this.exportedFlagDefinitions = exportedFlagDefinitions.isEmpty()
191 ? CollectionUtil.emptyMap()
192 : CollectionUtil.unmodifiableMap(exportedFlagDefinitions);
193 this.exportedFieldDefinitions = exportedFieldDefinitions.isEmpty()
194 ? CollectionUtil.emptyMap()
195 : CollectionUtil.unmodifiableMap(exportedFieldDefinitions);
196 this.exportedAssemblyDefinitions = exportedAssemblyDefinitions.isEmpty()
197 ? CollectionUtil.emptyMap()
198 : CollectionUtil.unmodifiableMap(exportedAssemblyDefinitions);
199 }
200 }
201 }
202
203 @SuppressWarnings({ "unused", "PMD.UnusedPrivateMethod" })
204 private static <DEF extends IDefinition> DEF handleShadowedDefinitions(
205 @SuppressWarnings("unused") @NonNull String key, @NonNull DEF oldDef, @NonNull DEF newDef) {
206 if (!oldDef.equals(newDef) && LOGGER.isWarnEnabled()) {
207 LOGGER.warn("The {} '{}' from metaschema '{}' is shadowing '{}' from metaschema '{}'",
208 newDef.getModelType().name().toLowerCase(Locale.ROOT),
209 newDef.getName(),
210 newDef.getContainingModule().getShortName(),
211 oldDef.getName(),
212 oldDef.getContainingModule().getShortName());
213 }
214 return newDef;
215 }
216 }