content: /*
   *  Licensed to the Apache Software Foundation (ASF) under one or more
   *  contributor license agreements.  See the NOTICE file distributed with
   *  this work for additional information regarding copyright ownership.
   *  The ASF licenses this file to You under the Apache License, Version 2.0
   *  (the "License"); you may not use this file except in compliance with
   *  the License.  You may obtain a copy of the License at
   *
   *      https://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   *
   */
  package org.apache.ivy.core.settings;
  
  import org.apache.ivy.Ivy;
  import org.apache.ivy.core.IvyPatternHelper;
  import org.apache.ivy.core.NormalRelativeUrlResolver;
  import org.apache.ivy.core.RelativeUrlResolver;
  import org.apache.ivy.core.cache.CacheUtil;
  import org.apache.ivy.core.cache.DefaultRepositoryCacheManager;
  import org.apache.ivy.core.cache.DefaultResolutionCacheManager;
  import org.apache.ivy.core.cache.RepositoryCacheManager;
  import org.apache.ivy.core.cache.ResolutionCacheManager;
  import org.apache.ivy.core.check.CheckEngineSettings;
  import org.apache.ivy.core.deliver.DeliverEngineSettings;
  import org.apache.ivy.core.install.InstallEngineSettings;
  import org.apache.ivy.core.module.id.ModuleId;
  import org.apache.ivy.core.module.id.ModuleRevisionId;
  import org.apache.ivy.core.module.id.ModuleRules;
  import org.apache.ivy.core.module.status.StatusManager;
  import org.apache.ivy.core.pack.PackingRegistry;
  import org.apache.ivy.core.publish.PublishEngineSettings;
  import org.apache.ivy.core.repository.RepositoryManagementEngineSettings;
  import org.apache.ivy.core.resolve.ResolveEngineSettings;
  import org.apache.ivy.core.resolve.ResolveOptions;
  import org.apache.ivy.core.retrieve.RetrieveEngineSettings;
  import org.apache.ivy.core.sort.SortEngineSettings;
  import org.apache.ivy.osgi.core.OsgiLatestStrategy;
  import org.apache.ivy.plugins.IvySettingsAware;
  import org.apache.ivy.plugins.circular.CircularDependencyStrategy;
  import org.apache.ivy.plugins.circular.ErrorCircularDependencyStrategy;
  import org.apache.ivy.plugins.circular.IgnoreCircularDependencyStrategy;
  import org.apache.ivy.plugins.circular.WarnCircularDependencyStrategy;
  import org.apache.ivy.plugins.conflict.ConflictManager;
  import org.apache.ivy.plugins.conflict.LatestCompatibleConflictManager;
  import org.apache.ivy.plugins.conflict.LatestConflictManager;
  import org.apache.ivy.plugins.conflict.NearestConflictManager;
  import org.apache.ivy.plugins.conflict.NoConflictManager;
  import org.apache.ivy.plugins.conflict.StrictConflictManager;
  import org.apache.ivy.plugins.latest.LatestLexicographicStrategy;
  import org.apache.ivy.plugins.latest.LatestRevisionStrategy;
  import org.apache.ivy.plugins.latest.LatestStrategy;
  import org.apache.ivy.plugins.latest.LatestTimeStrategy;
  import org.apache.ivy.plugins.latest.WorkspaceLatestStrategy;
  import org.apache.ivy.plugins.lock.CreateFileLockStrategy;
  import org.apache.ivy.plugins.lock.LockStrategy;
  import org.apache.ivy.plugins.lock.NIOFileLockStrategy;
  import org.apache.ivy.plugins.lock.NoLockStrategy;
  import org.apache.ivy.plugins.matcher.ExactOrRegexpPatternMatcher;
  import org.apache.ivy.plugins.matcher.ExactPatternMatcher;
  import org.apache.ivy.plugins.matcher.MapMatcher;
  import org.apache.ivy.plugins.matcher.PatternMatcher;
  import org.apache.ivy.plugins.matcher.RegexpPatternMatcher;
  import org.apache.ivy.plugins.namespace.Namespace;
  import org.apache.ivy.plugins.pack.ArchivePacking;
  import org.apache.ivy.plugins.pack.OsgiBundlePacking;
  import org.apache.ivy.plugins.pack.ZipPacking;
  import org.apache.ivy.plugins.parser.ModuleDescriptorParser;
  import org.apache.ivy.plugins.parser.ModuleDescriptorParserRegistry;
  import org.apache.ivy.plugins.parser.ParserSettings;
  import org.apache.ivy.plugins.report.LogReportOutputter;
  import org.apache.ivy.plugins.report.ReportOutputter;
  import org.apache.ivy.plugins.report.XmlReportOutputter;
  import org.apache.ivy.plugins.resolver.AbstractWorkspaceResolver;
  import org.apache.ivy.plugins.resolver.ChainResolver;
  import org.apache.ivy.plugins.resolver.DependencyResolver;
  import org.apache.ivy.plugins.resolver.DualResolver;
  import org.apache.ivy.plugins.resolver.ResolverSettings;
  import org.apache.ivy.plugins.resolver.WorkspaceChainResolver;
  import org.apache.ivy.plugins.signer.SignatureGenerator;
  import org.apache.ivy.plugins.trigger.Trigger;
  import org.apache.ivy.plugins.version.ChainVersionMatcher;
  import org.apache.ivy.plugins.version.ExactVersionMatcher;
  import org.apache.ivy.plugins.version.LatestVersionMatcher;
  import org.apache.ivy.plugins.version.SubVersionMatcher;
  import org.apache.ivy.plugins.version.VersionMatcher;
  import org.apache.ivy.plugins.version.VersionRangeMatcher;
  import org.apache.ivy.util.Checks;
  import org.apache.ivy.util.FileUtil;
  import org.apache.ivy.util.Message;
  import org.apache.ivy.util.StringUtils;
  import org.apache.ivy.util.filter.Filter;
  import org.apache.ivy.util.url.URLHandlerRegistry;
  
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileNotFoundException;
  import java.io.IOException;
  import java.io.InputStream;
  import java.lang.reflect.Field;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.net.URLClassLoader;
  import java.security.AccessControlException;
  import java.text.ParseException;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.LinkedHashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.Properties;
  
  import static org.apache.ivy.util.StringUtils.splitToArray;
  
  public class IvySettings implements SortEngineSettings, PublishEngineSettings, ParserSettings,
          DeliverEngineSettings, CheckEngineSettings, InstallEngineSettings, ResolverSettings,
          ResolveEngineSettings, RetrieveEngineSettings, RepositoryManagementEngineSettings {
      private static final long INTERRUPT_TIMEOUT = 2000;
  
      private Map<String, Class<?>> typeDefs = new HashMap<>();
  
      private Map<String, DependencyResolver> resolversMap = new HashMap<>();
  
      private DependencyResolver defaultResolver;
  
      private DependencyResolver dictatorResolver = null;
  
      private String defaultResolverName;
  
      private File defaultCache;
  
      private String defaultBranch = null;
  
      private boolean checkUpToDate = true;
  
      private ModuleRules<ModuleSettings> moduleSettings = new ModuleRules<>();
  
      private Map<String, ConflictManager> conflictsManager = new HashMap<>();
  
      private Map<String, LatestStrategy> latestStrategies = new HashMap<>();
  
      private Map<String, LockStrategy> lockStrategies = new HashMap<>();
  
      private Map<String, Namespace> namespaces = new HashMap<>();
  
      private Map<String, PatternMatcher> matchers = new HashMap<>();
  
      private Map<String, ReportOutputter> reportOutputters = new HashMap<>();
  
      private Map<String, VersionMatcher> versionMatchers = new HashMap<>();
  
      private Map<String, CircularDependencyStrategy> circularDependencyStrategies = new HashMap<>();
  
      private Map<String, RepositoryCacheManager> repositoryCacheManagers = new HashMap<>();
  
      private Map<String, SignatureGenerator> signatureGenerators = new HashMap<>();
  
      private List<Trigger> triggers = new ArrayList<>();
  
      private IvyVariableContainer variableContainer = new IvyVariableContainerImpl();
  
      private boolean validate = true;
  
      private LatestStrategy defaultLatestStrategy = null;
  
      private LockStrategy defaultLockStrategy = null;
  
      private ConflictManager defaultConflictManager = null;
  
      private CircularDependencyStrategy circularDependencyStrategy = null;
  
      private RepositoryCacheManager defaultRepositoryCacheManager = null;
  
      private ResolutionCacheManager resolutionCacheManager = null;
  
      private List<String> listingIgnore = new ArrayList<>();
  
      private boolean repositoriesConfigured;
  
      private boolean useRemoteConfig = false;
  
      private File defaultUserDir;
  
      private File baseDir = new File(".").getAbsoluteFile();
  
      private List<URL> classpathURLs = new ArrayList<>();
  
      private ClassLoader classloader;
  
      private Boolean debugConflictResolution;
  
      private boolean logNotConvertedExclusionRule;
  
      private VersionMatcher versionMatcher;
  
      private StatusManager statusManager;
  
      private Boolean debugLocking;
  
      private Boolean dumpMemoryUsage;
  
      private String defaultCacheIvyPattern;
  
      private String defaultCacheArtifactPattern;
  
      private boolean defaultUseOrigin;
  
      private String defaultResolveMode = ResolveOptions.RESOLVEMODE_DEFAULT;
  
      private PackingRegistry packingRegistry = new PackingRegistry();
  
      private AbstractWorkspaceResolver workspaceResolver;
  
      private final Map<String, TimeoutConstraint> timeoutConstraints = new HashMap<>();
  
      public IvySettings() {
          this(new IvyVariableContainerImpl());
      }
  
      public IvySettings(IvyVariableContainer variableContainer) {
          setVariableContainer(variableContainer);
          setVariable("ivy.default.settings.dir", getDefaultSettingsDir(), true);
          setVariable("ivy.basedir", getBaseDir().getAbsolutePath());
          setDeprecatedVariable("ivy.default.conf.dir", "ivy.default.settings.dir");
  
          String ivyTypeDefs = System.getProperty("ivy.typedef.files");
          if (ivyTypeDefs != null) {
              for (String file : splitToArray(ivyTypeDefs)) {
                  try {
                      typeDefs(new FileInputStream(Checks.checkAbsolute(file,
                              "ivy.typedef.files")), true);
                  } catch (FileNotFoundException e) {
                      Message.warn("typedefs file not found: " + file);
                  } catch (IOException e) {
                      Message.warn("problem with typedef file: " + file, e);
                  }
              }
          } else {
              try {
                  typeDefs(getSettingsURL("typedef.properties").openStream(), true);
              } catch (IOException e) {
                  Message.warn("impossible to load default type defs", e);
              }
          }
          LatestLexicographicStrategy latestLexicographicStrategy = new LatestLexicographicStrategy();
          LatestRevisionStrategy latestRevisionStrategy = new LatestRevisionStrategy();
          LatestTimeStrategy latestTimeStrategy = new LatestTimeStrategy();
          OsgiLatestStrategy osgiLatestStrategy = new OsgiLatestStrategy();
  
          addLatestStrategy("latest-revision", latestRevisionStrategy);
          addLatestStrategy("latest-lexico", latestLexicographicStrategy);
          addLatestStrategy("latest-time", latestTimeStrategy);
          addLatestStrategy("latest-osgi", osgiLatestStrategy);
  
          addLockStrategy("no-lock", new NoLockStrategy());
          addLockStrategy("artifact-lock", new CreateFileLockStrategy(debugLocking()));
          addLockStrategy("artifact-lock-nio", new NIOFileLockStrategy(debugLocking()));
  
          addConflictManager("latest-revision", new LatestConflictManager("latest-revision",
                  latestRevisionStrategy));
          addConflictManager("latest-compatible", new LatestCompatibleConflictManager(
                  "latest-compatible", latestRevisionStrategy));
          addConflictManager("latest-time", new LatestConflictManager("latest-time",
                  latestTimeStrategy));
          addConflictManager("all", new NoConflictManager());
          addConflictManager("strict", new StrictConflictManager());
          addConflictManager("nearest", new NearestConflictManager());
  
          addMatcher(ExactPatternMatcher.INSTANCE);
          addMatcher(RegexpPatternMatcher.INSTANCE);
          addMatcher(ExactOrRegexpPatternMatcher.INSTANCE);
  
          try {
              // GlobPatternMatcher is optional. Only add it when available.
              @SuppressWarnings("unchecked")
              Class<? extends PatternMatcher> globClazz = (Class<? extends PatternMatcher>) IvySettings.class
                      .getClassLoader()
                      .loadClass("org.apache.ivy.plugins.matcher.GlobPatternMatcher");
              Field instanceField = globClazz.getField("INSTANCE");
              addMatcher((PatternMatcher) instanceField.get(null));
          } catch (Exception e) {
              // ignore: the matcher isn't on the classpath
              Message.info("impossible to define glob matcher: "
                      + "org.apache.ivy.plugins.matcher.GlobPatternMatcher was not found", e);
          }
  
          addArchivePacking(new ZipPacking());
          addArchivePacking(new OsgiBundlePacking());
          try {
              // Pack200Packing is optional. Only add it when available.
              @SuppressWarnings("unchecked")
              Class<? extends ArchivePacking> pack200 = (Class<? extends ArchivePacking>) IvySettings.class
                  .getClassLoader()
                  .loadClass("org.apache.ivy.plugins.pack.Pack200Packing");
              addArchivePacking(pack200.newInstance());
          } catch (Exception t) {
              // ignore: the pack200 packing isn't on the classpath
              Message.info("impossible to define pack200 packaging: "
                           + "org.apache.ivy.plugins.pack.Pack200Packing was not found", t);
          }
  
          addReportOutputter(new LogReportOutputter());
          addReportOutputter(new XmlReportOutputter());
  
          configureDefaultCircularDependencyStrategies();
  
          listingIgnore.add(".cvsignore");
          listingIgnore.add("CVS");
          listingIgnore.add(".svn");
          listingIgnore.add("maven-metadata.xml");
          listingIgnore.add("maven-metadata.xml.md5");
          listingIgnore.add("maven-metadata.xml.sha1");
  
          addSystemProperties();
      }
  
      private synchronized void addSystemProperties() {
          try {
              addAllVariables((Map<?, ?>) System.getProperties().clone());
          } catch (AccessControlException ex) {
              Message.verbose("access denied to getting all system properties: they won't be available as Ivy variables."
                      + "\nset " + ex.getPermission() + " permission if you want to access them");
          }
      }
  
      /**
       * Call this method to ask ivy to configure some variables using either a remote or a local
       * properties file
       *
       * @param remote boolean
       */
      @SuppressWarnings("deprecation")
      public synchronized void configureRepositories(boolean remote) {
          if (!repositoriesConfigured) {
              Properties props = new Properties();
              boolean configured = false;
              if (useRemoteConfig && remote) {
                  try {
                      URL url = new URL("https://ant.apache.org/ivy/repository.properties");
                      Message.verbose("configuring repositories with " + url);
                      props.load(URLHandlerRegistry.getDefault().openStream(url));
                      configured = true;
                  } catch (Exception ex) {
                      Message.verbose("unable to use remote repository configuration", ex);
                      props = new Properties();
                  }
              }
              if (!configured) {
                  InputStream repositoryPropsStream = null;
                  try {
                      repositoryPropsStream = getSettingsURL("repository.properties").openStream();
                      props.load(repositoryPropsStream);
                  } catch (IOException e) {
                      Message.error("unable to use internal repository configuration", e);
                      if (repositoryPropsStream != null) {
                          try {
                              repositoryPropsStream.close();
                          } catch (Exception ex) {
                              // nothing to do
                          }
                      }
                  }
              }
              addAllVariables(props, false);
              repositoriesConfigured = true;
          }
      }
  
      public synchronized void typeDefs(InputStream stream) throws IOException {
          typeDefs(stream, false);
      }
  
      public synchronized void typeDefs(InputStream stream, boolean silentFail) throws IOException {
          try {
              Properties p = new Properties();
              p.load(stream);
              typeDefs(p, silentFail);
          } finally {
              stream.close();
          }
      }
  
      public synchronized void typeDefs(Properties p) {
          typeDefs(p, false);
      }
  
      public synchronized void typeDefs(Properties p, boolean silentFail) {
          for (Map.Entry<Object, Object> entry : p.entrySet()) {
              typeDef(entry.getKey().toString(), entry.getValue().toString(), silentFail);
          }
      }
  
      public synchronized void load(File settingsFile) throws ParseException, IOException {
          Message.info(":: loading settings :: file = " + settingsFile);
          long start = System.currentTimeMillis();
          setSettingsVariables(settingsFile);
          if (getVariable("ivy.default.ivy.user.dir") != null) {
              setDefaultIvyUserDir(Checks.checkAbsolute(getVariable("ivy.default.ivy.user.dir"),
                  "ivy.default.ivy.user.dir"));
          } else {
              getDefaultIvyUserDir();
          }
  
          loadDefaultProperties();
          try {
              new XmlSettingsParser(this).parse(settingsFile.toURI().toURL());
          } catch (MalformedURLException e) {
              throw new IllegalArgumentException(
                      "given file cannot be transformed to url: " + settingsFile, e);
          }
          setVariable("ivy.default.ivy.user.dir", getDefaultIvyUserDir().getAbsolutePath(), false);
          Message.verbose("settings loaded (" + (System.currentTimeMillis() - start) + "ms)");
          dumpSettings();
      }
  
      public synchronized void load(URL settingsURL) throws ParseException, IOException {
          Message.info(":: loading settings :: url = " + settingsURL);
          long start = System.currentTimeMillis();
          setSettingsVariables(settingsURL);
          if (getVariable("ivy.default.ivy.user.dir") != null) {
              setDefaultIvyUserDir(Checks.checkAbsolute(getVariable("ivy.default.ivy.user.dir"),
                  "ivy.default.ivy.user.dir"));
          } else {
              getDefaultIvyUserDir();
          }
  
          loadDefaultProperties();
          new XmlSettingsParser(this).parse(settingsURL);
          setVariable("ivy.default.ivy.user.dir", getDefaultIvyUserDir().getAbsolutePath(), false);
          Message.verbose("settings loaded (" + (System.currentTimeMillis() - start) + "ms)");
          dumpSettings();
      }
  
      /**
       * Default initialization of settings, useful when you don't want to load your settings from a
       * settings file or URL, but prefer to set them manually. By calling this method you will still
       * have the basic initialization done when loading settings.
       *
       * @throws IOException if something goes wrong
       */
      public synchronized void defaultInit() throws IOException {
          if (getVariable("ivy.default.ivy.user.dir") != null) {
              setDefaultIvyUserDir(Checks.checkAbsolute(getVariable("ivy.default.ivy.user.dir"),
                  "ivy.default.ivy.user.dir"));
          } else {
              getDefaultIvyUserDir();
          }
          getDefaultCache();
  
          loadDefaultProperties();
          setVariable("ivy.default.ivy.user.dir", getDefaultIvyUserDir().getAbsolutePath(), false);
          dumpSettings();
      }
  
      public synchronized void loadDefault() throws ParseException, IOException {
          load(getDefaultSettingsURL());
      }
  
      public synchronized void loadDefault14() throws ParseException, IOException {
          load(getDefault14SettingsURL());
      }
  
      private void loadDefaultProperties() throws IOException {
          loadProperties(getDefaultPropertiesURL(), false);
      }
  
      public static URL getDefaultPropertiesURL() {
          return getSettingsURL("ivy.properties");
      }
  
      public static URL getDefaultSettingsURL() {
          return getSettingsURL("ivysettings.xml");
      }
  
      public static URL getDefault14SettingsURL() {
          return getSettingsURL("ivysettings-1.4.xml");
      }
  
      private String getDefaultSettingsDir() {
          String ivysettingsLocation = getDefaultSettingsURL().toExternalForm();
          return ivysettingsLocation.substring(0,
              ivysettingsLocation.length() - "ivysettings.xml".length() - 1);
      }
  
      private static URL getSettingsURL(String file) {
          return XmlSettingsParser.class.getResource(file);
      }
  
      public synchronized void setSettingsVariables(File settingsFile) {
          try {
              setVariable("ivy.settings.dir", new File(settingsFile.getAbsolutePath()).getParent());
              setDeprecatedVariable("ivy.conf.dir", "ivy.settings.dir");
              setVariable("ivy.settings.file", settingsFile.getAbsolutePath());
              setDeprecatedVariable("ivy.conf.file", "ivy.settings.file");
              setVariable("ivy.settings.url", settingsFile.toURI().toURL().toExternalForm());
              setDeprecatedVariable("ivy.conf.url", "ivy.settings.url");
              setVariable("ivy.settings.dir.url", new File(settingsFile.getAbsolutePath())
                      .getParentFile().toURI().toURL().toExternalForm());
          } catch (MalformedURLException e) {
              throw new IllegalArgumentException(
                      "given file cannot be transformed to url: " + settingsFile, e);
          }
      }
  
      /**
       * Sets a deprecated variable with the value of the new variable
       *
       * @param deprecatedKey
       *            the deprecated variable name
       * @param newKey
       *            the new variable name
       */
      private void setDeprecatedVariable(String deprecatedKey, String newKey) {
          setVariable(deprecatedKey, getVariable(newKey));
      }
  
      public synchronized void setSettingsVariables(URL settingsURL) {
          String settingsURLStr = settingsURL.toExternalForm();
          setVariable("ivy.settings.url", settingsURLStr);
          setDeprecatedVariable("ivy.conf.url", "ivy.settings.url");
          int slashIndex = settingsURLStr.lastIndexOf('/');
          if (slashIndex != -1) {
              String dirUrl = settingsURLStr.substring(0, slashIndex);
              setVariable("ivy.settings.dir", dirUrl);
              setVariable("ivy.settings.dir.url", dirUrl);
              setDeprecatedVariable("ivy.conf.dir", "ivy.settings.dir");
          } else {
              Message.warn("settings url does not contain any slash (/): "
                      + "ivy.settings.dir variable not set");
          }
      }
  
      private void dumpSettings() {
          Message.verbose("\tdefault cache: " + getDefaultCache());
          Message.verbose("\tdefault resolver: " + getDefaultResolver());
          Message.debug("\tdefault latest strategy: " + getDefaultLatestStrategy());
          Message.debug("\tdefault conflict manager: " + getDefaultConflictManager());
          Message.debug("\tcircular dependency strategy: " + getCircularDependencyStrategy());
          Message.debug("\tvalidate: " + doValidate());
          Message.debug("\tcheck up2date: " + isCheckUpToDate());
  
          if (!classpathURLs.isEmpty()) {
              Message.verbose("\t-- " + classpathURLs.size() + " custom classpath urls:");
              for (URL url : classpathURLs) {
                  Message.debug("\t\t" + url);
              }
          }
          Message.verbose("\t-- " + resolversMap.size() + " resolvers:");
          for (DependencyResolver resolver : resolversMap.values()) {
              resolver.dumpSettings();
          }
          Message.debug("\tmodule settings:");
          moduleSettings.dump("\t\t");
      }
  
      public synchronized void loadProperties(URL url) throws IOException {
          loadProperties(url, true);
      }
  
      public synchronized void loadProperties(URL url, boolean overwrite) throws IOException {
          loadProperties(url.openStream(), overwrite);
      }
  
      public synchronized void loadProperties(File file) throws IOException {
          loadProperties(file, true);
      }
  
      public synchronized void loadProperties(File file, boolean overwrite) throws IOException {
          loadProperties(new FileInputStream(file), overwrite);
      }
  
      private void loadProperties(InputStream stream, boolean overwrite) throws IOException {
          try {
              Properties properties = new Properties();
              properties.load(stream);
              addAllVariables(properties, overwrite);
          } finally {
              if (stream != null) {
                  try {
                      stream.close();
                  } catch (IOException e) {
                      // nothing
                  }
              }
          }
      }
  
      public synchronized void setVariable(String varName, String value) {
          setVariable(varName, value, true);
      }
  
      public synchronized void setVariable(String varName, String value, boolean overwrite) {
          setVariable(varName, value, overwrite, null, null);
      }
  
      public synchronized void setVariable(String varName, String value, boolean overwrite,
              String ifSetVar, String unlessSetVar) {
          if (ifSetVar != null && variableContainer.getVariable(ifSetVar) == null) {
              Message.verbose("Not setting '" + varName + "' to '" + value + "' since '" + ifSetVar
                      + "' is not set.");
              return;
          }
          if (unlessSetVar != null && variableContainer.getVariable(unlessSetVar) != null) {
              Message.verbose("Not setting '" + varName + "' to '" + value + "' since '"
                      + unlessSetVar + "' is set.");
              return;
          }
          variableContainer.setVariable(varName, value, overwrite);
      }
  
      public synchronized void addAllVariables(Map<?, ?> variables) {
          addAllVariables(variables, true);
      }
  
      public synchronized void addAllVariables(Map<?, ?> variables, boolean overwrite) {
          for (Map.Entry<?, ?> entry : variables.entrySet()) {
              Object val = entry.getValue();
              if (val == null || val instanceof String) {
                  setVariable(entry.getKey().toString(), (String) val, overwrite);
              }
          }
      }
  
      /**
       * Substitute variables in the given string by their value found in the current set of variables
       *
       * @param str
       *            the string in which substitution should be made
       * @return the string where all current ivy variables have been substituted by their value If
       *         the input str doesn't use any variable, the same object is returned
       */
      public synchronized String substitute(String str) {
          return IvyPatternHelper.substituteVariables(str, variableContainer);
      }
  
      /**
       * Substitute variables in the given map values by their value found in the current set of
       * variables
       *
       * @param strings
       *            the map of strings in which substitution should be made
       * @return a new map of strings in which all current ivy variables in values have been
       *         substituted by their value
       */
      public synchronized Map<String, String> substitute(Map<String, String> strings) {
          Map<String, String> substituted = new LinkedHashMap<>();
          for (Map.Entry<String, String> entry : strings.entrySet()) {
              substituted.put(entry.getKey(), substitute(entry.getValue()));
          }
          return substituted;
      }
  
      /**
       * Returns the variables loaded in configuration file. Those variables may better be seen as ant
       * properties
       *
       * @return IvyVariableContainer
       */
      public synchronized IvyVariableContainer getVariables() {
          return variableContainer;
      }
  
      public synchronized Class<?> typeDef(String name, String className) {
          return typeDef(name, className, false);
      }
  
      public synchronized Class<?> typeDef(String name, String className, boolean silentFail) {
          Class<?> clazz = classForName(className, silentFail);
          if (clazz != null) {
              typeDefs.put(name, clazz);
          }
          return clazz;
      }
  
      private Class<?> classForName(String className, boolean silentFail) {
          try {
              return getClassLoader().loadClass(className);
          } catch (ClassNotFoundException e) {
              if (silentFail) {
                  Message.info("impossible to define new type: class not found: " + className
                          + " in " + classpathURLs + " nor Ivy classloader");
                  return null;
              } else {
                  throw new RuntimeException("impossible to define new type: class not found: "
                          + className + " in " + classpathURLs + " nor Ivy classloader");
              }
          }
      }
  
      private ClassLoader getClassLoader() {
          if (classloader == null) {
              if (classpathURLs.isEmpty()) {
                  classloader = Ivy.class.getClassLoader();
              } else {
                  classloader = new URLClassLoader(
                          classpathURLs.toArray(new URL[classpathURLs.size()]),
                          Ivy.class.getClassLoader());
              }
          }
          return classloader;
      }
  
      public synchronized void addClasspathURL(URL url) {
          classpathURLs.add(url);
          classloader = null;
      }
  
      public synchronized Map<String, Class<?>> getTypeDefs() {
          return typeDefs;
      }
  
      public synchronized Class<?> getTypeDef(String name) {
          return typeDefs.get(name);
      }
  
      // methods which match ivy conf method signature specs
      public synchronized void addConfigured(DependencyResolver resolver) {
          addResolver(resolver);
      }
  
      public synchronized void addConfigured(ModuleDescriptorParser parser) {
          ModuleDescriptorParserRegistry.getInstance().addParser(parser);
      }
  
      public synchronized void addConfigured(SignatureGenerator generator) {
          addSignatureGenerator(generator);
      }
  
      public synchronized void addSignatureGenerator(SignatureGenerator generator) {
          init(generator);
          signatureGenerators.put(generator.getName(), generator);
      }
  
      public synchronized SignatureGenerator getSignatureGenerator(String name) {
          return signatureGenerators.get(name);
      }
  
      public synchronized void addResolver(DependencyResolver resolver) {
          if (resolver == null) {
              throw new NullPointerException("null resolver");
          }
          init(resolver);
          resolversMap.put(resolver.getName(), resolver);
          if (resolver instanceof ChainResolver) {
              List<DependencyResolver> subresolvers = ((ChainResolver) resolver).getResolvers();
              for (DependencyResolver dr : subresolvers) {
                  addResolver(dr);
              }
          } else if (resolver instanceof DualResolver) {
              DependencyResolver ivyResolver = ((DualResolver) resolver).getIvyResolver();
              if (ivyResolver != null) {
                  addResolver(ivyResolver);
              }
              DependencyResolver artifactResolver = ((DualResolver) resolver).getArtifactResolver();
              if (artifactResolver != null) {
                  addResolver(artifactResolver);
              }
          }
      }
  
      public synchronized void setDefaultCache(File cacheDirectory) {
          setVariable("ivy.cache.dir", cacheDirectory.getAbsolutePath(), false);
          defaultCache = cacheDirectory;
          if (defaultRepositoryCacheManager != null) {
              if ("default-cache".equals(defaultRepositoryCacheManager.getName())
                      && defaultRepositoryCacheManager instanceof DefaultRepositoryCacheManager) {
                  ((DefaultRepositoryCacheManager) defaultRepositoryCacheManager)
                          .setBasedir(defaultCache);
              }
          }
      }
  
      public synchronized void setDefaultResolver(String resolverName) {
          checkResolverName(resolverName);
          if (resolverName != null && !resolverName.equals(defaultResolverName)) {
              defaultResolver = null;
          }
          defaultResolverName = resolverName;
      }
  
      private void checkResolverName(String resolverName) {
          if (resolverName != null && !resolversMap.containsKey(resolverName)) {
              throw new IllegalArgumentException("no resolver found called " + resolverName
                      + ": check your settings");
          }
      }
  
      /**
       * regular expressions as explained in Pattern class may be used in attributes
       *
       * @param attributes Map
       * @param matcher PatternMatcher
       * @param resolverName String
       * @param branch String
       * @param conflictManager String
       * @param resolveMode String
       */
      public synchronized void addModuleConfiguration(Map<String, String> attributes,
              PatternMatcher matcher, String resolverName, String branch, String conflictManager,
              String resolveMode) {
          checkResolverName(resolverName);
          moduleSettings.defineRule(new MapMatcher(attributes, matcher), new ModuleSettings(
                  resolverName, branch, conflictManager, resolveMode));
      }
  
      /**
       * Return the canonical form of a filename.
       * <p>
       * If the specified file name is relative it is resolved with respect to the settings's base
       * directory.
       *
       * @param fileName
       *            The name of the file to resolve. Must not be <code>null</code>.
       *
       * @return the resolved File.
       *
       */
      public synchronized File resolveFile(String fileName) {
          return FileUtil.resolveFile(baseDir, fileName);
      }
  
      public synchronized void setBaseDir(File baseDir) {
          this.baseDir = baseDir.getAbsoluteFile();
          setVariable("ivy.basedir", this.baseDir.getAbsolutePath());
          setVariable("basedir", this.baseDir.getAbsolutePath(), false);
      }
  
      public synchronized File getBaseDir() {
          return baseDir;
      }
  
      public synchronized File getDefaultIvyUserDir() {
          if (defaultUserDir == null) {
              if (getVariable("ivy.home") != null) {
                  setDefaultIvyUserDir(Checks.checkAbsolute(getVariable("ivy.home"), "ivy.home"));
                  Message.verbose("using ivy.default.ivy.user.dir variable for default ivy user dir: "
                          + defaultUserDir);
              } else {
                  setDefaultIvyUserDir(new File(System.getProperty("user.home"), ".ivy2"));
                  Message.verbose("no default ivy user dir defined: set to " + defaultUserDir);
              }
          }
          return defaultUserDir;
      }
  
      public synchronized void setDefaultIvyUserDir(File defaultUserDir) {
          this.defaultUserDir = defaultUserDir;
          setVariable("ivy.default.ivy.user.dir", this.defaultUserDir.getAbsolutePath());
          setVariable("ivy.home", this.defaultUserDir.getAbsolutePath());
      }
  
      public synchronized File getDefaultCache() {
          if (defaultCache == null) {
              String cache = getVariable("ivy.cache.dir");
              if (cache != null) {
                  defaultCache = Checks.checkAbsolute(cache, "ivy.cache.dir");
              } else {
                  setDefaultCache(new File(getDefaultIvyUserDir(), "cache"));
                  Message.verbose("no default cache defined: set to " + defaultCache);
              }
          }
          return defaultCache;
      }
  
      public synchronized void setDefaultRepositoryCacheBasedir(String repositoryCacheRoot) {
          setVariable("ivy.cache.repository", repositoryCacheRoot, true);
          if (defaultRepositoryCacheManager != null
                  && "default-cache".equals(defaultRepositoryCacheManager.getName())
                  && defaultRepositoryCacheManager instanceof DefaultRepositoryCacheManager) {
              ((DefaultRepositoryCacheManager) defaultRepositoryCacheManager)
                      .setBasedir(getDefaultRepositoryCacheBasedir());
          }
      }
  
      public synchronized void setDefaultResolutionCacheBasedir(String resolutionCacheRoot) {
          setVariable("ivy.cache.resolution", resolutionCacheRoot, true);
          if (resolutionCacheManager != null
                  && resolutionCacheManager instanceof DefaultResolutionCacheManager) {
              ((DefaultResolutionCacheManager) resolutionCacheManager)
                      .setBasedir(getDefaultResolutionCacheBasedir());
          }
      }
  
      public synchronized File getDefaultRepositoryCacheBasedir() {
          String repositoryCacheRoot = getVariable("ivy.cache.repository");
          if (repositoryCacheRoot != null) {
              return Checks.checkAbsolute(repositoryCacheRoot, "ivy.cache.repository");
          } else {
              return getDefaultCache();
          }
      }
  
      public synchronized File getDefaultResolutionCacheBasedir() {
          String resolutionCacheRoot = getVariable("ivy.cache.resolution");
          if (resolutionCacheRoot != null) {
              return Checks.checkAbsolute(resolutionCacheRoot, "ivy.cache.resolution");
          } else {
              return getDefaultCache();
          }
      }
  
      public synchronized void setDictatorResolver(DependencyResolver resolver) {
          dictatorResolver = resolver;
      }
  
      private DependencyResolver getDictatorResolver() {
          if (dictatorResolver == null) {
              return null;
          }
          if (workspaceResolver != null && !(dictatorResolver instanceof WorkspaceChainResolver)) {
              dictatorResolver = new WorkspaceChainResolver(this, dictatorResolver, workspaceResolver);
          }
          return dictatorResolver;
      }
  
      public synchronized DependencyResolver getResolver(ModuleRevisionId mrid) {
          DependencyResolver r = getDictatorResolver();
          if (r != null) {
              return r;
          }
          String resolverName = getResolverName(mrid);
          return getResolver(resolverName);
      }
  
      public synchronized boolean hasResolver(String resolverName) {
          return resolversMap.containsKey(resolverName);
      }
  
      public synchronized DependencyResolver getResolver(String resolverName) {
          DependencyResolver r = getDictatorResolver();
          if (r != null) {
              return r;
          }
          DependencyResolver resolver = resolversMap.get(resolverName);
          if (resolver == null) {
              Message.error("unknown resolver " + resolverName);
          } else if (workspaceResolver != null && !(resolver instanceof WorkspaceChainResolver)) {
              resolver = new WorkspaceChainResolver(this, resolver, workspaceResolver);
              resolversMap.put(resolver.getName(), resolver);
              resolversMap.put(resolverName, resolver);
          }
          return resolver;
      }
  
      public synchronized DependencyResolver getDefaultResolver() {
          DependencyResolver r = getDictatorResolver();
          if (r != null) {
              return r;
          }
          if (defaultResolver == null) {
              defaultResolver = resolversMap.get(defaultResolverName);
          }
          if (workspaceResolver != null && !(defaultResolver instanceof WorkspaceChainResolver)) {
              defaultResolver = new WorkspaceChainResolver(this, defaultResolver, workspaceResolver);
          }
          return defaultResolver;
      }
  
      public synchronized String getResolverName(ModuleRevisionId mrid) {
          ModuleSettings ms = moduleSettings.getRule(mrid, new Filter<ModuleSettings>() {
              public boolean accept(ModuleSettings o) {
                  return o.getResolverName() != null;
              }
          });
          return ms == null ? defaultResolverName : ms.getResolverName();
      }
  
      public synchronized String getDefaultBranch(ModuleId moduleId) {
          ModuleSettings ms = moduleSettings.getRule(moduleId, new Filter<ModuleSettings>() {
              public boolean accept(ModuleSettings o) {
                  return o.getBranch() != null;
              }
          });
          return ms == null ? getDefaultBranch() : ms.getBranch();
      }
  
      public synchronized String getDefaultBranch() {
          return defaultBranch;
      }
  
      public synchronized void setDefaultBranch(String defaultBranch) {
          this.defaultBranch = defaultBranch;
      }
  
      public synchronized ConflictManager getConflictManager(ModuleId moduleId) {
          ModuleSettings ms = moduleSettings.getRule(moduleId, new Filter<ModuleSettings>() {
              public boolean accept(ModuleSettings o) {
                  return o.getConflictManager() != null;
              }
          });
          if (ms == null) {
              return getDefaultConflictManager();
          } else {
              ConflictManager cm = getConflictManager(ms.getConflictManager());
              if (cm == null) {
                  throw new IllegalStateException("ivy badly configured: unknown conflict manager "
                          + ms.getConflictManager());
              }
              return cm;
          }
      }
  
      public synchronized String getResolveMode(ModuleId moduleId) {
          ModuleSettings ms = moduleSettings.getRule(moduleId, new Filter<ModuleSettings>() {
              public boolean accept(ModuleSettings o) {
                  return o.getResolveMode() != null;
              }
          });
          return ms == null ? getDefaultResolveMode() : ms.getResolveMode();
      }
  
      public synchronized String getDefaultResolveMode() {
          return defaultResolveMode;
      }
  
      public synchronized void setDefaultResolveMode(String defaultResolveMode) {
          this.defaultResolveMode = defaultResolveMode;
      }
  
      public synchronized void addConfigured(ConflictManager cm) {
          addConflictManager(cm.getName(), cm);
      }
  
      public synchronized ConflictManager getConflictManager(String name) {
          if ("default".equals(name)) {
              return getDefaultConflictManager();
          }
          return conflictsManager.get(name);
      }
  
      public synchronized void addConflictManager(String name, ConflictManager cm) {
          init(cm);
          conflictsManager.put(name, cm);
      }
  
      public synchronized void addConfigured(LatestStrategy latest) {
          addLatestStrategy(latest.getName(), latest);
      }
  
      public synchronized LatestStrategy getLatestStrategy(String name) {
          if ("default".equals(name)) {
              return getDefaultLatestStrategy();
          }
          LatestStrategy strategy = latestStrategies.get(name);
          if (workspaceResolver != null && !(strategy instanceof WorkspaceLatestStrategy)) {
              strategy = new WorkspaceLatestStrategy(strategy);
              latestStrategies.put(name, strategy);
          }
          return strategy;
      }
  
      public synchronized void addLatestStrategy(String name, LatestStrategy latest) {
          init(latest);
          latestStrategies.put(name, latest);
      }
  
      public synchronized void addConfigured(LockStrategy lockStrategy) {
          addLockStrategy(lockStrategy.getName(), lockStrategy);
      }
  
      public synchronized LockStrategy getLockStrategy(String name) {
          if ("default".equals(name)) {
              return getDefaultLockStrategy();
          }
          return lockStrategies.get(name);
      }
  
      public synchronized void addLockStrategy(String name, LockStrategy lockStrategy) {
          init(lockStrategy);
          lockStrategies.put(name, lockStrategy);
      }
  
      public synchronized void addConfigured(Namespace ns) {
          addNamespace(ns);
      }
  
      public synchronized Namespace getNamespace(String name) {
          if ("system".equals(name)) {
              return getSystemNamespace();
          }
          return namespaces.get(name);
      }
  
      public final Namespace getSystemNamespace() {
          return Namespace.SYSTEM_NAMESPACE;
      }
  
      public synchronized void addNamespace(Namespace ns) {
          init(ns);
          namespaces.put(ns.getName(), ns);
      }
  
      public void addConfigured(final NamedTimeoutConstraint timeoutConstraint) {
          if (timeoutConstraint == null) {
              return;
          }
          final String name = timeoutConstraint.getName();
          StringUtils.assertNotNullNorEmpty(name, "Name of a timeout constraint cannot be null or empty string");
          this.timeoutConstraints.put(name, timeoutConstraint);
      }
  
      @Override
      public TimeoutConstraint getTimeoutConstraint(final String name) {
          return this.timeoutConstraints.get(name);
      }
  
      public synchronized void addConfigured(PatternMatcher m) {
          addMatcher(m);
      }
  
      public synchronized PatternMatcher getMatcher(String name) {
          return matchers.get(name);
      }
  
      public synchronized void addMatcher(PatternMatcher m) {
          init(m);
          matchers.put(m.getName(), m);
      }
  
      public synchronized void addConfigured(RepositoryCacheManager c) {
          addRepositoryCacheManager(c);
      }
  
      public synchronized RepositoryCacheManager getRepositoryCacheManager(String name) {
          return repositoryCacheManagers.get(name);
      }
  
      public synchronized void addRepositoryCacheManager(RepositoryCacheManager c) {
          init(c);
          repositoryCacheManagers.put(c.getName(), c);
      }
  
      public synchronized RepositoryCacheManager[] getRepositoryCacheManagers() {
          return repositoryCacheManagers.values().toArray(
              new RepositoryCacheManager[repositoryCacheManagers.size()]);
      }
  
      public synchronized void addConfigured(ReportOutputter outputter) {
          addReportOutputter(outputter);
      }
  
      public synchronized ReportOutputter getReportOutputter(String name) {
          return reportOutputters.get(name);
      }
  
      public synchronized void addReportOutputter(ReportOutputter outputter) {
          init(outputter);
          reportOutputters.put(outputter.getName(), outputter);
      }
  
      public synchronized ReportOutputter[] getReportOutputters() {
          return reportOutputters.values().toArray(new ReportOutputter[reportOutputters.size()]);
      }
  
      public synchronized void addConfigured(VersionMatcher vmatcher) {
          addVersionMatcher(vmatcher);
      }
  
      public synchronized VersionMatcher getVersionMatcher(String name) {
          return versionMatchers.get(name);
      }
  
      public synchronized void addVersionMatcher(VersionMatcher vmatcher) {
          init(vmatcher);
          versionMatchers.put(vmatcher.getName(), vmatcher);
  
          if (versionMatcher == null) {
              versionMatcher = new ChainVersionMatcher();
              addVersionMatcher(new ExactVersionMatcher());
          }
          if (versionMatcher instanceof ChainVersionMatcher) {
              ChainVersionMatcher chain = (ChainVersionMatcher) versionMatcher;
              chain.add(vmatcher);
          }
      }
  
      public synchronized VersionMatcher[] getVersionMatchers() {
          return versionMatchers.values().toArray(new VersionMatcher[versionMatchers.size()]);
      }
  
      public synchronized VersionMatcher getVersionMatcher() {
          if (versionMatcher == null) {
              configureDefaultVersionMatcher();
          }
          return versionMatcher;
      }
  
      public synchronized void configureDefaultVersionMatcher() {
          addVersionMatcher(new LatestVersionMatcher());
          addVersionMatcher(new SubVersionMatcher());
          addVersionMatcher(new VersionRangeMatcher());
      }
  
      public synchronized CircularDependencyStrategy getCircularDependencyStrategy() {
          if (circularDependencyStrategy == null) {
              circularDependencyStrategy = getCircularDependencyStrategy("default");
          }
          return circularDependencyStrategy;
      }
  
      public synchronized CircularDependencyStrategy getCircularDependencyStrategy(String name) {
          if ("default".equals(name)) {
              name = "warn";
          }
          return circularDependencyStrategies.get(name);
      }
  
      public synchronized void setCircularDependencyStrategy(CircularDependencyStrategy strategy) {
          circularDependencyStrategy = strategy;
      }
  
      public synchronized void addConfigured(CircularDependencyStrategy strategy) {
          addCircularDependencyStrategy(strategy);
      }
  
      private void addCircularDependencyStrategy(CircularDependencyStrategy strategy) {
          circularDependencyStrategies.put(strategy.getName(), strategy);
      }
  
      private void configureDefaultCircularDependencyStrategies() {
          addCircularDependencyStrategy(WarnCircularDependencyStrategy.getInstance());
          addCircularDependencyStrategy(ErrorCircularDependencyStrategy.getInstance());
          addCircularDependencyStrategy(IgnoreCircularDependencyStrategy.getInstance());
      }
  
      public synchronized StatusManager getStatusManager() {
          if (statusManager == null) {
              statusManager = StatusManager.newDefaultInstance();
          }
          return statusManager;
      }
  
      public void setStatusManager(StatusManager statusManager) {
          this.statusManager = statusManager;
      }
  
      /**
       * Returns the file names of the files that should be ignored when creating a file listing.
       *
       * @return String[]
       */
      public synchronized String[] getIgnorableFilenames() {
          return listingIgnore.toArray(new String[listingIgnore.size()]);
      }
  
      /**
       * Filters the names list by removing all names that should be ignored as defined by the listing
       * ignore list
       *
       * @param names ditto
       */
      public synchronized void filterIgnore(Collection<String> names) {
          names.removeAll(listingIgnore);
      }
  
      public synchronized boolean isCheckUpToDate() {
          return checkUpToDate;
      }
  
      public synchronized void setCheckUpToDate(boolean checkUpToDate) {
          this.checkUpToDate = checkUpToDate;
      }
  
      public synchronized boolean doValidate() {
          return validate;
      }
  
      public synchronized void setValidate(boolean validate) {
          this.validate = validate;
      }
  
      public synchronized String getVariable(String name) {
          return variableContainer.getVariable(name);
      }
  
      /**
       * Returns a variable as boolean value.
       * @param name name of the variable
       * @param valueIfUnset value if the variable is unset
       * @return <tt>true</tt> if the variable is <tt>'true'</tt> (ignoring case)
       *     or the value of <i>valueIfUnset</i> if the variable is <tt>null</tt>
       */
      public synchronized boolean getVariableAsBoolean(String name, boolean valueIfUnset) {
          String var = getVariable(name);
          return var == null ? valueIfUnset : Boolean.valueOf(var);
      }
  
      public synchronized ConflictManager getDefaultConflictManager() {
          if (defaultConflictManager == null) {
              defaultConflictManager = new LatestConflictManager(getDefaultLatestStrategy());
              ((LatestConflictManager) defaultConflictManager).setSettings(this);
          }
          return defaultConflictManager;
      }
  
      public synchronized void setDefaultConflictManager(ConflictManager defaultConflictManager) {
          this.defaultConflictManager = defaultConflictManager;
      }
  
      public synchronized LatestStrategy getDefaultLatestStrategy() {
          if (defaultLatestStrategy == null) {
              defaultLatestStrategy = new LatestRevisionStrategy();
          }
          if (workspaceResolver != null
                  && !(defaultLatestStrategy instanceof WorkspaceLatestStrategy)) {
              defaultLatestStrategy = new WorkspaceLatestStrategy(defaultLatestStrategy);
          }
          return defaultLatestStrategy;
      }
  
      public synchronized void setDefaultLatestStrategy(LatestStrategy defaultLatestStrategy) {
          this.defaultLatestStrategy = defaultLatestStrategy;
      }
  
      public synchronized LockStrategy getDefaultLockStrategy() {
          if (defaultLockStrategy == null) {
              defaultLockStrategy = new NoLockStrategy();
          }
          return defaultLockStrategy;
      }
  
      public synchronized void setDefaultLockStrategy(LockStrategy defaultLockStrategy) {
          this.defaultLockStrategy = defaultLockStrategy;
      }
  
      public synchronized RepositoryCacheManager getDefaultRepositoryCacheManager() {
          if (defaultRepositoryCacheManager == null) {
              defaultRepositoryCacheManager = new DefaultRepositoryCacheManager("default-cache",
                      this, getDefaultRepositoryCacheBasedir());
              addRepositoryCacheManager(defaultRepositoryCacheManager);
          }
          return defaultRepositoryCacheManager;
      }
  
      public synchronized void setDefaultRepositoryCacheManager(RepositoryCacheManager cache) {
          this.defaultRepositoryCacheManager = cache;
      }
  
      public synchronized ResolutionCacheManager getResolutionCacheManager() {
          if (resolutionCacheManager == null) {
              resolutionCacheManager = new DefaultResolutionCacheManager(
                      getDefaultResolutionCacheBasedir());
              init(resolutionCacheManager);
          }
          return resolutionCacheManager;
      }
  
      public synchronized void setResolutionCacheManager(ResolutionCacheManager resolutionCacheManager) {
          this.resolutionCacheManager = resolutionCacheManager;
      }
  
      public synchronized void addTrigger(Trigger trigger) {
          init(trigger);
          triggers.add(trigger);
      }
  
      public synchronized List<Trigger> getTriggers() {
          return triggers;
      }
  
      public synchronized void addConfigured(Trigger trigger) {
          addTrigger(trigger);
      }
  
      public synchronized boolean isUseRemoteConfig() {
          return useRemoteConfig;
      }
  
      public synchronized void setUseRemoteConfig(boolean useRemoteConfig) {
          this.useRemoteConfig = useRemoteConfig;
      }
  
      public synchronized boolean logModulesInUse() {
          return getVariableAsBoolean("ivy.log.modules.in.use", true);
      }
  
      public synchronized boolean logModuleWhenFound() {
          return getVariableAsBoolean("ivy.log.module.when.found", true);
      }
  
      public synchronized boolean logResolvedRevision() {
          return getVariableAsBoolean("ivy.log.resolved.revision", true);
      }
  
      public synchronized boolean debugConflictResolution() {
          if (debugConflictResolution == null) {
              debugConflictResolution = getVariableAsBoolean("ivy.log.conflict.resolution", false);
          }
          return debugConflictResolution;
      }
  
      public synchronized boolean debugLocking() {
          if (debugLocking == null) {
              debugLocking = getVariableAsBoolean("ivy.log.locking", false);
          }
          return debugLocking;
      }
  
      public synchronized boolean dumpMemoryUsage() {
          if (dumpMemoryUsage == null) {
              dumpMemoryUsage = getVariableAsBoolean("ivy.log.memory", false);
          }
          return dumpMemoryUsage;
      }
  
      public synchronized boolean logNotConvertedExclusionRule() {
          return logNotConvertedExclusionRule;
      }
  
      public synchronized void setLogNotConvertedExclusionRule(boolean logNotConvertedExclusionRule) {
          this.logNotConvertedExclusionRule = logNotConvertedExclusionRule;
      }
  
      private void init(Object obj) {
          if (obj instanceof IvySettingsAware) {
              ((IvySettingsAware) obj).setSettings(this);
          } else if (obj instanceof DependencyResolver) {
              ((DependencyResolver) obj).setSettings(this);
          }
      }
  
      private static class ModuleSettings {
          private String resolverName;
  
          private String branch;
  
          private String conflictManager;
  
          private String resolveMode;
  
          public ModuleSettings(String resolver, String branchName, String conflictMgr,
                  String resolveMode) {
              this.resolverName = resolver;
              this.branch = branchName;
              this.conflictManager = conflictMgr;
              this.resolveMode = resolveMode;
          }
  
          @Override
          public String toString() {
              return (resolverName != null ? "resolver: " + resolverName : "")
                      + (branch != null ? "branch: " + branch : "")
                      + (conflictManager != null ? "conflictManager: " + conflictManager : "")
                      + (resolveMode != null ? "resolveMode: " + resolveMode : "");
          }
  
          public String getBranch() {
              return branch;
          }
  
          public String getResolverName() {
              return resolverName;
          }
  
          public String getConflictManager() {
              return conflictManager;
          }
  
          public String getResolveMode() {
              return resolveMode;
          }
      }
  
      public final long getInterruptTimeout() {
          return INTERRUPT_TIMEOUT;
      }
  
      public synchronized Collection<DependencyResolver> getResolvers() {
          return resolversMap.values();
      }
  
      public synchronized Collection<String> getResolverNames() {
          return resolversMap.keySet();
      }
  
      public synchronized Collection<String> getMatcherNames() {
          return matchers.keySet();
      }
  
      public synchronized IvyVariableContainer getVariableContainer() {
          return variableContainer;
      }
  
      /**
       * Use a different variable container.
       *
       * @param variables IvyVariableContainer
       */
      public synchronized void setVariableContainer(IvyVariableContainer variables) {
          variableContainer = variables;
      }
  
      public synchronized RelativeUrlResolver getRelativeUrlResolver() {
          return new NormalRelativeUrlResolver();
      }
  
      public synchronized void setDefaultCacheIvyPattern(String defaultCacheIvyPattern) {
          CacheUtil.checkCachePattern(defaultCacheIvyPattern);
          this.defaultCacheIvyPattern = defaultCacheIvyPattern;
      }
  
      public synchronized String getDefaultCacheIvyPattern() {
          return defaultCacheIvyPattern;
      }
  
      public synchronized void setDefaultCacheArtifactPattern(String defaultCacheArtifactPattern) {
          CacheUtil.checkCachePattern(defaultCacheArtifactPattern);
          this.defaultCacheArtifactPattern = defaultCacheArtifactPattern;
      }
  
      public synchronized String getDefaultCacheArtifactPattern() {
          return defaultCacheArtifactPattern;
      }
  
      public synchronized void setDefaultUseOrigin(boolean useOrigin) {
          defaultUseOrigin = useOrigin;
      }
  
      public synchronized boolean isDefaultUseOrigin() {
          return defaultUseOrigin;
      }
  
      public synchronized void useDeprecatedUseOrigin() {
          Message.deprecated("useOrigin option is deprecated when calling resolve, use useOrigin"
                  + " setting on the cache implementation instead");
          setDefaultUseOrigin(true);
  
      }
  
      /**
       * Validates the settings, throwing an {@link IllegalStateException} if the current state is not
       * valid.
       *
       * @throws IllegalStateException
       *             if the settings is not valid.
       */
      public synchronized void validate() {
          validateAll(resolversMap.values());
          validateAll(conflictsManager.values());
          validateAll(latestStrategies.values());
          validateAll(lockStrategies.values());
          validateAll(repositoryCacheManagers.values());
          validateAll(reportOutputters.values());
          validateAll(circularDependencyStrategies.values());
          validateAll(versionMatchers.values());
          validateAll(namespaces.values());
      }
  
      /**
       * Validates all {@link Validatable} objects in the collection.
       *
       * @param values
       *            the collection of objects to validate.
       * @throws IllegalStateException
       *             if any of the objects is not valid.
       */
      private void validateAll(Collection<?> values) {
          for (Object object : values) {
              if (object instanceof Validatable) {
                  ((Validatable) object).validate();
              }
          }
      }
  
      public Namespace getContextNamespace() {
          return Namespace.SYSTEM_NAMESPACE;
      }
  
      public synchronized void addConfigured(ArchivePacking packing) {
          addArchivePacking(packing);
      }
  
      public synchronized void addArchivePacking(ArchivePacking packing) {
          init(packing);
          packingRegistry.register(packing);
      }
  
      public PackingRegistry getPackingRegistry() {
          return packingRegistry;
      }
  
      public void addConfigured(AbstractWorkspaceResolver workspaceResolver) {
          this.workspaceResolver = workspaceResolver;
          if (workspaceResolver != null) {
              workspaceResolver.setSettings(this);
              DefaultRepositoryCacheManager cacheManager = new DefaultRepositoryCacheManager();
              String cacheName = "workspace-resolver-cache-" + workspaceResolver.getName();
              cacheManager.setBasedir(new File(getDefaultCache(), cacheName));
              cacheManager.setCheckmodified(true);
              cacheManager.setUseOrigin(true);
              cacheManager.setName(cacheName);
              addRepositoryCacheManager(cacheManager);
              workspaceResolver.setCache(cacheName);
          }
  
      }
  }
  