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