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.schemagen;
28
29 import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition;
30 import gov.nist.secauto.metaschema.core.model.IAssemblyInstance;
31 import gov.nist.secauto.metaschema.core.model.IChoiceInstance;
32 import gov.nist.secauto.metaschema.core.model.IDefinition;
33 import gov.nist.secauto.metaschema.core.model.IFieldInstance;
34 import gov.nist.secauto.metaschema.core.model.IFlagDefinition;
35 import gov.nist.secauto.metaschema.core.model.IFlagInstance;
36 import gov.nist.secauto.metaschema.core.model.IModule;
37 import gov.nist.secauto.metaschema.core.model.INamedInstance;
38 import gov.nist.secauto.metaschema.core.model.ModelWalker;
39 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
40
41 import java.util.Collection;
42 import java.util.Map;
43 import java.util.concurrent.ConcurrentHashMap;
44 import java.util.concurrent.atomic.AtomicBoolean;
45 import java.util.concurrent.atomic.AtomicInteger;
46
47 import edu.umd.cs.findbugs.annotations.NonNull;
48
49 public class ModuleIndex {
50 private final Map<IDefinition, DefinitionEntry> index = new ConcurrentHashMap<>();
51
52 @NonNull
53 public static ModuleIndex indexDefinitions(@NonNull IModule module) {
54 Collection<? extends IAssemblyDefinition> definitions = module.getExportedRootAssemblyDefinitions();
55 ModuleIndex index = new ModuleIndex();
56 if (!definitions.isEmpty()) {
57 IndexVisitor visitor = new IndexVisitor(index);
58 for (IAssemblyDefinition definition : definitions) {
59 assert definition != null;
60
61
62 index.getEntry(definition).incrementReferenceCount();
63
64
65 visitor.walk(ObjectUtils.requireNonNull(definition));
66 }
67 }
68 return index;
69 }
70
71 public boolean hasEntry(@NonNull IDefinition definition) {
72 return index.containsKey(definition);
73 }
74
75 @NonNull
76 public DefinitionEntry getEntry(@NonNull IDefinition definition) {
77 return ObjectUtils.notNull(index.computeIfAbsent(
78 definition,
79 k -> new ModuleIndex.DefinitionEntry(ObjectUtils.notNull(k))));
80 }
81
82 @NonNull
83 public Collection<DefinitionEntry> getDefinitions() {
84 return ObjectUtils.notNull(index.values());
85 }
86
87 private static class IndexVisitor
88 extends ModelWalker<ModuleIndex> {
89 private final ModuleIndex index;
90
91 public IndexVisitor(@NonNull ModuleIndex index) {
92 this.index = index;
93 }
94
95 @Override
96 protected ModuleIndex getDefaultData() {
97 return index;
98 }
99
100 @Override
101 protected boolean visit(IFlagInstance instance, ModuleIndex data) {
102 return handleInstance(instance);
103 }
104
105 @Override
106 protected boolean visit(IFieldInstance instance, ModuleIndex data) {
107 return handleInstance(instance);
108 }
109
110 @Override
111 protected boolean visit(IAssemblyInstance instance, ModuleIndex data) {
112 return handleInstance(instance);
113 }
114
115 @Override
116 protected void visit(IFlagDefinition def, ModuleIndex data) {
117
118 }
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134 private boolean handleInstance(INamedInstance instance) {
135 IDefinition definition = instance.getDefinition();
136
137
138 final boolean exists = getDefaultData().hasEntry(definition);
139 DefinitionEntry entry = getDefaultData().getEntry(definition);
140 entry.incrementReferenceCount();
141
142 if (isChoice(instance)) {
143 entry.markUsedAsChoice();
144 }
145
146 if (isChoiceSibling(instance)) {
147 entry.markAsChoiceSibling();
148 }
149 return !exists;
150 }
151
152 private static boolean isChoice(@NonNull INamedInstance instance) {
153 return instance.getParentContainer() instanceof IChoiceInstance;
154 }
155
156 private static boolean isChoiceSibling(@NonNull INamedInstance instance) {
157 IDefinition containingDefinition = instance.getContainingDefinition();
158 return containingDefinition instanceof IAssemblyDefinition
159 && !((IAssemblyDefinition) containingDefinition).getChoiceInstances().isEmpty();
160 }
161 }
162
163 public static class DefinitionEntry {
164 @NonNull
165 private final IDefinition definition;
166 private final AtomicInteger referenceCount = new AtomicInteger();
167 private final AtomicBoolean usedAsChoice = new AtomicBoolean();
168 private final AtomicBoolean choiceSibling = new AtomicBoolean();
169
170 public DefinitionEntry(@NonNull IDefinition definition) {
171 this.definition = definition;
172 }
173
174 public IDefinition getDefinition() {
175 return definition;
176 }
177
178 public boolean isReferenced() {
179 return getReferenceCount() > 0;
180 }
181
182 public int getReferenceCount() {
183 return referenceCount.get();
184 }
185
186 public int incrementReferenceCount() {
187 return referenceCount.incrementAndGet();
188 }
189
190 public int incrementReferenceCount(int increment) {
191 return referenceCount.addAndGet(increment);
192 }
193
194 public boolean isInline() {
195 return getDefinition().isInline();
196 }
197
198 public void markUsedAsChoice() {
199 usedAsChoice.compareAndSet(false, true);
200 }
201
202 public boolean isUsedAsChoice() {
203 return usedAsChoice.get();
204 }
205
206 public void markAsChoiceSibling() {
207 choiceSibling.compareAndSet(false, true);
208 }
209
210 public boolean isChoiceSibling() {
211 return choiceSibling.get();
212 }
213 }
214 }