001/*
002 * SPDX-FileCopyrightText: none
003 * SPDX-License-Identifier: CC0-1.0
004 */
005
006package gov.nist.secauto.metaschema.databind;
007
008import gov.nist.secauto.metaschema.core.model.IBoundObject;
009import gov.nist.secauto.metaschema.core.model.IModule;
010import gov.nist.secauto.metaschema.core.model.IModuleLoader;
011import gov.nist.secauto.metaschema.core.util.CollectionUtil;
012import gov.nist.secauto.metaschema.databind.IBindingContext.IBindingMatcher;
013import gov.nist.secauto.metaschema.databind.model.IBoundDefinitionModelComplex;
014import gov.nist.secauto.metaschema.databind.model.IBoundModule;
015
016import java.util.ArrayList;
017import java.util.Collection;
018import java.util.HashSet;
019import java.util.List;
020import java.util.Set;
021import java.util.concurrent.locks.Lock;
022import java.util.concurrent.locks.ReentrantLock;
023
024import edu.umd.cs.findbugs.annotations.NonNull;
025
026public class PostProcessingModuleLoaderStrategy
027    implements IBindingContext.IModuleLoaderStrategy {
028  @NonNull
029  private final List<IModuleLoader.IModulePostProcessor> modulePostProcessors;
030  // private final Set<IModule> resolvedModules = new HashSet<>();
031  // private final Lock resolvedModulesLock = new ReentrantLock();
032  private final IBindingContext.IModuleLoaderStrategy delegate;
033  private final Set<IModule> postProcessedModules = new HashSet<>();
034  private final Lock postProcessedModulesLock = new ReentrantLock();
035
036  public PostProcessingModuleLoaderStrategy(
037      @NonNull List<IModuleLoader.IModulePostProcessor> modulePostProcessors) {
038    this(modulePostProcessors, new SimpleModuleLoaderStrategy());
039  }
040
041  public PostProcessingModuleLoaderStrategy(
042      @NonNull List<IModuleLoader.IModulePostProcessor> modulePostProcessors,
043      @NonNull IBindingContext.IModuleLoaderStrategy delegate) {
044    this.modulePostProcessors = CollectionUtil.unmodifiableList(new ArrayList<>(modulePostProcessors));
045    this.delegate = delegate;
046  }
047
048  @NonNull
049  protected List<IModuleLoader.IModulePostProcessor> getModulePostProcessors() {
050    return modulePostProcessors;
051  }
052
053  @Override
054  public IBoundModule loadModule(Class<? extends IBoundModule> clazz, IBindingContext bindingContext) {
055    return delegate.loadModule(clazz, bindingContext);
056  }
057
058  @Override
059  public void postProcessModule(IModule module, IBindingContext bindingContext) {
060    processModule(module);
061    delegate.postProcessModule(module, bindingContext);
062  }
063
064  @Override
065  public IBoundModule registerModule(IModule module, IBindingContext bindingContext) {
066    IBoundModule boundModule;
067    postProcessedModulesLock.lock();
068    try {
069      // process before registering
070      processModule(module);
071
072      boundModule = delegate.registerModule(module, bindingContext);
073
074      // ensure the resulting bound module is not processed again
075      postProcessedModules.add(boundModule);
076    } finally {
077      postProcessedModulesLock.unlock();
078    }
079    return boundModule;
080  }
081
082  /**
083   * Perform post-processing on the provided module.
084   *
085   * @param module
086   *          the module to post process
087   */
088  protected void processModule(@NonNull IModule module) {
089    postProcessedModulesLock.lock();
090    try {
091      if (!postProcessedModules.contains(module)) {
092        for (IModuleLoader.IModulePostProcessor postProcessor : getModulePostProcessors()) {
093          postProcessor.processModule(module);
094        }
095        postProcessedModules.add(module);
096      }
097    } finally {
098      postProcessedModulesLock.unlock();
099    }
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}