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