1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.databind;
7   
8   import gov.nist.secauto.metaschema.core.model.IBoundObject;
9   import gov.nist.secauto.metaschema.core.model.IModule;
10  import gov.nist.secauto.metaschema.core.model.IModuleLoader;
11  import gov.nist.secauto.metaschema.core.util.CollectionUtil;
12  import gov.nist.secauto.metaschema.databind.IBindingContext.IBindingMatcher;
13  import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelComplex;
14  import gov.nist.secauto.metaschema.databind.model.IBoundModule;
15  import gov.nist.secauto.metaschema.databind.model.metaschema.binding.MetaschemaModelModule;
16  
17  import java.util.ArrayList;
18  import java.util.Collection;
19  import java.util.HashSet;
20  import java.util.List;
21  import java.util.Set;
22  import java.util.concurrent.locks.Lock;
23  import java.util.concurrent.locks.ReentrantLock;
24  
25  import edu.umd.cs.findbugs.annotations.NonNull;
26  
27  public class PostProcessingModuleLoaderStrategy
28      implements IBindingContext.IModuleLoaderStrategy {
29    @NonNull
30    private final List<IModuleLoader.IModulePostProcessor> modulePostProcessors;
31    // private final Set<IModule> resolvedModules = new HashSet<>();
32    // private final Lock resolvedModulesLock = new ReentrantLock();
33    private final IBindingContext.IModuleLoaderStrategy delegate;
34    private final Set<IModule> postProcessedModules = new HashSet<>();
35    private final Lock postProcessedModulesLock = new ReentrantLock();
36  
37    public PostProcessingModuleLoaderStrategy(
38        @NonNull List<IModuleLoader.IModulePostProcessor> modulePostProcessors) {
39      this(modulePostProcessors, new SimpleModuleLoaderStrategy());
40    }
41  
42    public PostProcessingModuleLoaderStrategy(
43        @NonNull List<IModuleLoader.IModulePostProcessor> modulePostProcessors,
44        @NonNull IBindingContext.IModuleLoaderStrategy delegate) {
45      this.modulePostProcessors = CollectionUtil.unmodifiableList(new ArrayList<>(modulePostProcessors));
46      this.delegate = delegate;
47    }
48  
49    @NonNull
50    protected List<IModuleLoader.IModulePostProcessor> getModulePostProcessors() {
51      return modulePostProcessors;
52    }
53  
54    @Override
55    public IBoundModule loadModule(Class<? extends IBoundModule> clazz, IBindingContext bindingContext) {
56      return delegate.loadModule(clazz, bindingContext);
57    }
58  
59    @Override
60    public void postProcessModule(IModule module, IBindingContext bindingContext) {
61      processModule(module);
62      delegate.postProcessModule(module, bindingContext);
63    }
64  
65    @Override
66    public IBoundModule registerModule(IModule module, IBindingContext bindingContext) {
67      IBoundModule boundModule;
68      postProcessedModulesLock.lock();
69      try {
70        // process before registering
71        processModule(module);
72  
73        boundModule = delegate.registerModule(module, bindingContext);
74  
75        // ensure the resulting bound module is not processed again
76        postProcessedModules.add(boundModule);
77      } finally {
78        postProcessedModulesLock.unlock();
79      }
80      return boundModule;
81    }
82  
83    private void processModule(@NonNull IModule module) {
84      postProcessedModulesLock.lock();
85      try {
86        if (!postProcessedModules.contains(module)) {
87          // do not post-process the built-in Metaschema module, since it has already been
88          // pre-processed
89          if (!(module instanceof MetaschemaModelModule)) {
90            for (IModuleLoader.IModulePostProcessor postProcessor : getModulePostProcessors()) {
91              postProcessor.processModule(module);
92            }
93          }
94          postProcessedModules.add(module);
95        }
96      } finally {
97        postProcessedModulesLock.unlock();
98      }
99    }
100 
101   @Override
102   public Collection<IBindingMatcher> getBindingMatchers() {
103     return delegate.getBindingMatchers();
104   }
105 
106   @Override
107   public IBoundDefinitionModelComplex getBoundDefinitionForClass(
108       Class<? extends IBoundObject> clazz,
109       IBindingContext bindingContext) {
110 
111     //
112     // resolvedModulesLock.lock();
113     // try {
114     // if (!resolvedModules.contains(module)) {
115     // // add first, to avoid loops
116     // resolvedModules.add(module);
117     // for (IModuleLoader.IModulePostProcessor postProcessor :
118     // getModulePostProcessors()) {
119     // postProcessor.processModule(module);
120     // }
121     // }
122     // } finally {
123     // resolvedModulesLock.unlock();
124     // }
125     return delegate.getBoundDefinitionForClass(clazz, bindingContext);
126   }
127 }