package org.jboss.windup.exec.configuration;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jboss.forge.furnace.Furnace;
import org.jboss.forge.furnace.addons.Addon;
import org.jboss.forge.furnace.services.Imported;
import org.jboss.forge.furnace.util.Predicate;
import org.jboss.windup.config.ConfigurationOption;
import org.jboss.windup.config.RuleProvider;
import org.jboss.windup.config.furnace.FurnaceHolder;
import org.jboss.windup.exec.WindupProcessor;
import org.jboss.windup.exec.WindupProgressMonitor;
import org.jboss.windup.exec.configuration.options.ExportCSVOption;
import org.jboss.windup.exec.configuration.options.InputPathOption;
import org.jboss.windup.exec.configuration.options.OnlineModeOption;
import org.jboss.windup.exec.configuration.options.OutputPathOption;
import org.jboss.windup.exec.configuration.options.UserIgnorePathOption;
import org.jboss.windup.exec.configuration.options.UserRulesDirectoryOption;
import org.jboss.windup.graph.GraphContext;
import org.jboss.windup.util.PathUtil;
import org.ocpsoft.rewrite.config.Rule;
/**
* Configuration of WindupProcessor.
*
* @author <a href="mailto:ozizka@redhat.com">Ondrej Zizka</a>
* @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
*/
public class WindupConfiguration
{
private static final String DEFAULT_USER_RULES_DIRECTORIES_OPTION = "defaultUserRulesDirectories";
private static final String DEFAULT_USER_IGNORE_DIRECTORIES_OPTION = "defaultUserIgnorePaths";
public static final boolean DEFAULT_ONLINE = false;
private Predicate<RuleProvider> ruleProviderFilter;
private WindupProgressMonitor progressMonitor = new NullWindupProgressMonitor();
private final Map<String, Object> configurationOptions = new HashMap<>();
private boolean alwaysHaltOnException;
private GraphContext context;
public WindupConfiguration()
{
}
public void useDefaultDirectories() throws IOException
{
Path userRulesDir = PathUtil.getUserRulesDir();
if (userRulesDir != null && !Files.isDirectory(userRulesDir))
{
Files.createDirectories(userRulesDir);
}
if (userRulesDir != null)
{
addDefaultUserRulesDirectory(userRulesDir);
}
Path userIgnoreDir = PathUtil.getUserIgnoreDir();
if (userIgnoreDir != null && !Files.isDirectory(userIgnoreDir))
{
Files.createDirectories(userIgnoreDir);
}
if (userIgnoreDir != null)
{
addDefaultUserIgnorePath(userIgnoreDir);
}
Path windupHomeRulesDir = PathUtil.getWindupRulesDir();
if (windupHomeRulesDir != null && !Files.isDirectory(windupHomeRulesDir))
{
Files.createDirectories(windupHomeRulesDir);
}
if (windupHomeRulesDir != null)
{
addDefaultUserRulesDirectory(windupHomeRulesDir);
}
Path windupHomeIgnoreDir = PathUtil.getWindupIgnoreDir();
if (windupHomeIgnoreDir != null && !Files.isDirectory(windupHomeIgnoreDir))
{
Files.createDirectories(windupHomeIgnoreDir);
}
if (windupHomeIgnoreDir != null)
{
addDefaultUserIgnorePath(windupHomeIgnoreDir);
}
}
/**
* Sets a configuration option to the specified value.
*/
public WindupConfiguration setOptionValue(String name, Object value)
{
configurationOptions.put(name, value);
return this;
}
/**
* Indicates that we should always halt on a {@link Rule} failure, regardless of whether or not we would normally bypass the failure.
*
* This can be useful in test scenarios where we don't want errors to be ignored at all.
*/
public boolean isAlwaysHaltOnException()
{
return alwaysHaltOnException;
}
/**
* Indicates that we should always halt on a {@link Rule} failure, regardless of whether or not we would normally bypass the failure.
*
* This can be useful in test scenarios where we don't want errors to be ignored at all.
*/
public void setAlwaysHaltOnException(boolean alwaysHaltOnException)
{
this.alwaysHaltOnException = alwaysHaltOnException;
}
/**
* Returns the configuration value with the specified name.
*/
@SuppressWarnings("unchecked")
public <T> T getOptionValue(String name)
{
return (T) configurationOptions.get(name);
}
/**
* Returns all configuration options as an immutable {@link Map}.
*/
public Map<String, Object> getOptionMap()
{
return Collections.unmodifiableMap(configurationOptions);
}
/**
* Returns all of the {@link ConfigurationOption} in all currently available {@link Addon}s.
*/
public static Iterable<ConfigurationOption> getWindupConfigurationOptions()
{
return getWindupConfigurationOptions(FurnaceHolder.getFurnace());
}
/**
* Returns all of the {@link ConfigurationOption} in all currently available {@link Addon}s.
*/
public static Iterable<ConfigurationOption> getWindupConfigurationOptions(Furnace furnace)
{
List<ConfigurationOption> results = new ArrayList<>();
for (ConfigurationOption option : furnace.getAddonRegistry().getServices(ConfigurationOption.class))
{
results.add(option);
}
Collections.sort(results, new Comparator<ConfigurationOption>()
{
@Override
public int compare(ConfigurationOption o1, ConfigurationOption o2)
{
return o2.getPriority() - o1.getPriority();
}
});
return results;
}
/**
* Returns all of the {@link ConfigurationOption} in the specified {@link Addon}.
*/
public static Iterable<ConfigurationOption> getWindupConfigurationOptions(Addon addon)
{
IdentityHashMap<ClassLoader, Addon> classLoaderToAddon = new IdentityHashMap<>();
for (Addon loadedAddon : FurnaceHolder.getAddonRegistry().getAddons())
{
classLoaderToAddon.put(loadedAddon.getClassLoader(), loadedAddon);
}
List<ConfigurationOption> results = new ArrayList<>();
Imported<ConfigurationOption> options = FurnaceHolder.getAddonRegistry()
.getServices(ConfigurationOption.class);
for (ConfigurationOption option : options)
{
ClassLoader optionClassLoader = option.getClass().getClassLoader();
Addon optionAddon = classLoaderToAddon.get(optionClassLoader);
if (optionAddon.equals(addon))
{
results.add(option);
}
}
return results;
}
/**
* Contains the path to the input file (or directory) to be processed
*/
public WindupConfiguration addInputPath(Path inputPath)
{
Set<Path> inputPaths = getOptionValue(InputPathOption.NAME);
if (inputPaths == null)
{
inputPaths = new LinkedHashSet<>();
setOptionValue(InputPathOption.NAME, inputPaths);
}
inputPaths.add(inputPath);
return this;
}
/**
* Contains the path to the input file (or directory) to be processed
*/
public Collection<Path> getInputPaths()
{
Collection<Path> inputPaths = getOptionValue(InputPathOption.NAME);
return inputPaths;
}
/**
* Contains the directory to put the output to (migration report, temporary files, exported graph data...).
*/
public Path getOutputDirectory()
{
File file = getOptionValue(OutputPathOption.NAME);
return file == null ? null : file.toPath();
}
/**
* Contains the directory to put the output to (migration report, temporary files, exported graph data...).
*/
public WindupConfiguration setOutputDirectory(Path outputDirectory)
{
setOptionValue(OutputPathOption.NAME, outputDirectory.toFile());
return this;
}
/**
* Gets all user rule directories. This includes both the ones that they specify (eg, /path/to/rules) as well as ones that Windup provides by
* default (eg, WINDUP_HOME/rules and ~/.windup/rules).
*/
public Iterable<Path> getAllUserRulesDirectories()
{
Set<Path> results = new HashSet<>();
results.addAll(getDefaultUserRulesDirectories());
File userSpecifiedFile = getOptionValue(UserRulesDirectoryOption.NAME);
if (userSpecifiedFile != null)
{
results.add(userSpecifiedFile.toPath());
}
return results;
}
/**
* Gets all the directories/files in which the regexes for ignoring the files is placed. This includes the file/directory specified by the user
* and the default paths that are WINDUP_HOME/ignore and ~/.windup/ignore.
*
* @return
*/
public Iterable<Path> getAllIgnoreDirectories()
{
Set<Path> results = new HashSet<>();
results.addAll(getDefaultUserIgnoreDirectories());
File userSpecifiedFile = getOptionValue(UserIgnorePathOption.NAME);
if (userSpecifiedFile != null)
{
results.add(userSpecifiedFile.toPath());
}
return results;
}
/**
* Contains a list of {@link Path}s with directories that contains user provided rules.
*/
public List<Path> getDefaultUserRulesDirectories()
{
List<Path> paths = getOptionValue(DEFAULT_USER_RULES_DIRECTORIES_OPTION);
if (paths == null)
{
return Collections.emptyList();
}
return Collections.unmodifiableList(paths);
}
/**
* Contains a default list of {@link Path}s with directories/files that contains files having regexes of file names to be ignored.
*/
public List<Path> getDefaultUserIgnoreDirectories()
{
List<Path> paths = getOptionValue(DEFAULT_USER_IGNORE_DIRECTORIES_OPTION);
if (paths == null)
{
return Collections.emptyList();
}
return Collections.unmodifiableList(paths);
}
/**
* Contains a list of {@link Path}s with the directory that contains user provided rules.
*
* This method does guard against duplicate directories.
*/
public WindupConfiguration addDefaultUserRulesDirectory(Path path)
{
List<Path> paths = getOptionValue(DEFAULT_USER_RULES_DIRECTORIES_OPTION);
if (paths == null)
{
paths = new ArrayList<>();
setOptionValue(DEFAULT_USER_RULES_DIRECTORIES_OPTION, paths);
}
File userSpecifiedRulePath = getOptionValue(UserRulesDirectoryOption.NAME);
if (userSpecifiedRulePath != null && userSpecifiedRulePath.toPath().equals(path))
{
return this;
}
for (Path existingPath : paths)
{
if (existingPath.equals(path))
{
return this;
}
}
paths.add(path);
return this;
}
/**
* Adds a path to the list of default {@link Path}s with directories/files that contain files with regexes of file names to be ignored.
*
* This method does guard against duplicate directories.
*/
public WindupConfiguration addDefaultUserIgnorePath(Path path)
{
List<Path> paths = getOptionValue(DEFAULT_USER_IGNORE_DIRECTORIES_OPTION);
if (paths == null)
{
paths = new ArrayList<>();
setOptionValue(DEFAULT_USER_IGNORE_DIRECTORIES_OPTION, paths);
}
File userSpecifiedIgnorePath = getOptionValue(UserIgnorePathOption.NAME);
if (userSpecifiedIgnorePath != null && userSpecifiedIgnorePath.toPath().equals(path))
{
return this;
}
for (Path existingPath : paths)
{
if (existingPath.equals(path))
{
return this;
}
}
paths.add(path);
return this;
}
public Predicate<RuleProvider> getRuleProviderFilter()
{
return ruleProviderFilter;
}
/**
* A filter to limit which rule providers' rules will be executed.
*/
public WindupConfiguration setRuleProviderFilter(Predicate<RuleProvider> ruleProviderFilter)
{
this.ruleProviderFilter = ruleProviderFilter;
return this;
}
public WindupProgressMonitor getProgressMonitor()
{
return progressMonitor;
}
/**
* A progress monitor which will get notification of the rule execution progress.
*/
public WindupConfiguration setProgressMonitor(WindupProgressMonitor progressMonitor)
{
this.progressMonitor = progressMonitor;
return this;
}
/**
* Sets the {@link GraphContext} instance on which the {@link WindupProcessor} should execute.
*/
public WindupConfiguration setGraphContext(GraphContext context)
{
this.context = context;
return this;
}
/**
* Gets the {@link GraphContext} instance on which the {@link WindupProcessor} should execute.
*/
public GraphContext getGraphContext()
{
return context;
}
/**
* Set Windup to run online or offline (with respect to an internet connection).
*/
public WindupConfiguration setOnline(boolean online)
{
setOptionValue(OnlineModeOption.NAME, online);
return this;
}
/**
* Returns true if Windup is operating in {@link OnlineModeOption} == true. (with respect to an internet connection)
*/
public boolean isOnline()
{
Boolean online = getOptionValue(OnlineModeOption.NAME);
return online == null ? DEFAULT_ONLINE : online;
}
/**
* Set Windup to export CSV file containing the migration information (classifications, hints).
*/
public WindupConfiguration setExportingCSV(boolean export)
{
setOptionValue(ExportCSVOption.NAME, export);
return this;
}
/**
* Returns true if Windup is operating in {@link ExportCSVOption} == true.
*/
public boolean isExportingCSV()
{
Boolean export = getOptionValue(ExportCSVOption.NAME);
return export == null ? false : export;
}
}