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.model.MetaschemaException;
12  import gov.nist.secauto.metaschema.core.util.CollectionUtil;
13  import gov.nist.secauto.metaschema.databind.IBindingContext.IBindingMatcher;
14  import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelComplex;
15  import gov.nist.secauto.metaschema.databind.model.IBoundModule;
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) throws MetaschemaException {
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    /**
84     * Perform post-processing on the provided module.
85     *
86     * @param module
87     *          the module to post process
88     */
89    protected void processModule(@NonNull IModule module) {
90      postProcessedModulesLock.lock();
91      try {
92        if (!postProcessedModules.contains(module)) {
93          for (IModuleLoader.IModulePostProcessor postProcessor : getModulePostProcessors()) {
94            postProcessor.processModule(module);
95          }
96          postProcessedModules.add(module);
97        }
98      } finally {
99        postProcessedModulesLock.unlock();
100     }
101   }
102 
103   @Override
104   public Collection<IBindingMatcher> getBindingMatchers() {
105     return delegate.getBindingMatchers();
106   }
107 
108   @Override
109   public IBoundDefinitionModelComplex getBoundDefinitionForClass(
110       Class<? extends IBoundObject> clazz,
111       IBindingContext bindingContext) {
112 
113     //
114     // resolvedModulesLock.lock();
115     // try {
116     // if (!resolvedModules.contains(module)) {
117     // // add first, to avoid loops
118     // resolvedModules.add(module);
119     // for (IModuleLoader.IModulePostProcessor postProcessor :
120     // getModulePostProcessors()) {
121     // postProcessor.processModule(module);
122     // }
123     // }
124     // } finally {
125     // resolvedModulesLock.unlock();
126     // }
127     return delegate.getBoundDefinitionForClass(clazz, bindingContext);
128   }
129 }