UIOptionCollection.java
/*
* 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.rat.ui;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.TreeMap;
import java.util.function.BiFunction;
import java.util.stream.Stream;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.rat.Defaults;
import org.apache.rat.commandline.Arg;
import org.apache.rat.utils.Log;
/**
* A collection of options supported by the UI. This includes RAT options and UI specific options.
* @param <T> the AbstractOption implementation.
*/
public class UIOptionCollection<T extends UIOption<T>> {
/** map of ARG to the associated UpdatableOptionGroup */
private final Map<Arg, UpdatableOptionGroup> argMap;
/** set of RAT OptionGroups with unsupported options for this UI removed */
private final UpdatableOptionGroupCollection supportedRatOptions;
/** set of UI specific options */
private final Map<Option, T> uiOptions;
/**
* Map of option to overridden default value. Generally applies to supported RAT options but may be
* UI-specific options as well.
*/
private final Map <Option, String> defaultValues;
/**
* The function to generate a concrete BaseOption instance.
*/
private final BiFunction<UIOptionCollection<T>, Option, T> mapper;
/**
* Construct the UIOptionCollection from the builder.
* @param builder the builder to build from.
*/
protected UIOptionCollection(final Builder<T, ?> builder) {
Objects.requireNonNull(builder.mapper, "Builder.mapper");
argMap = new TreeMap<>();
mapper = builder.mapper;
supportedRatOptions = new UpdatableOptionGroupCollection();
for (Arg arg : Arg.values()) {
argMap.put(arg, supportedRatOptions.add(arg.group()));
}
for (Option opt : builder.unsupportedRatOptions) {
supportedRatOptions.findGroups(opt).forEach(group -> group.disableOption(opt));
}
uiOptions = new HashMap<>();
supportedRatOptions.options().getOptions()
.forEach(option -> uiOptions.put(option, mapper.apply(this, option)));
builder.uiOptions.stream().filter(option -> !uiOptions.containsKey(option))
.forEach(option -> uiOptions.put(option, mapper.apply(this, option)));
defaultValues = new HashMap<>(builder.defaultValues);
}
/**
* Checks if an Arg is selected.
* @param arg the Arg to check.
* @return {@code true} if the arg is selected.
*/
public final boolean isSelected(final Arg arg) {
UpdatableOptionGroup group = argMap.get(arg);
return group != null && group.getSelected() != null;
}
/**
* Gets the selected Option for the arg.
* @param arg the arg to check.
* @return an Optional containing the selected option, or an empty Optional if none was selected.
*/
public final Optional<Option> getSelected(final Arg arg) {
UpdatableOptionGroup group = argMap.get(arg);
String s = group == null ? null : group.getSelected();
if (s != null) {
for (Option result : group.getOptions()) {
if (result.getKey().equals(s)) {
return Optional.of(result);
}
}
}
return Optional.empty();
}
/**
* Gets the collection of unsupported Options.
* @return the Options comprised for the unsupported options.
*/
public final Options getUnsupportedOptions() {
return supportedRatOptions.unsupportedOptions();
}
/**
* Gets the UiOption instance for the Option.
* @param option the option to find the instance of.
* @return a UIOption instance that wraps the option.
*/
public final Optional<T> getMappedOption(final Option option) {
return Optional.ofNullable(uiOptions.get(option));
}
/**
* Gets an Options that contains the RAT Arg defined Option instances that are understood by this collection.
* OptionGroups are registered in the resulting Options object.
* @return an Options that contains the RAT Arg defined Option instances that are understood by this collection.
*/
public final Options getOptions() {
return supportedRatOptions.options().addOptions(additionalOptions());
}
/**
* Gets the Stream of AbstractOption implementations understood by this collection.
* @return the Stream of AbstractOption implementations understood by this collection.
*/
public final Stream<T> getMappedOptions() {
return uiOptions.values().stream();
}
/**
* Gets a map client option name to specified AbstractOption implementation.
* @return a map client option name to specified AbstractOption implementation
*/
public final Map<String, T> getOptionMap() {
Map<String, T> result = new TreeMap<>();
getMappedOptions().forEach(mappedOption -> result.put(ArgumentTracker.extractKey(mappedOption.getOption()), mappedOption));
return result;
}
/**
* Gets the additional options understood by this collection.
* @return the additional options understood by this collection.
*/
public final Options additionalOptions() {
Options options = new Options();
uiOptions.keySet().stream()
.filter(option -> !supportedRatOptions.contains(option))
.forEach(options::addOption);
return options;
}
/**
* Gets the default value for the option.
* @param option the option to lookup.
* @return the default value or {@code null} if not set.
*/
public final String defaultValue(final Option option) {
return defaultValues.get(option);
}
/**
* Builder for a BaseOptionCollection.
* @param <T> the concreate type of the BaseOption.
* @param <S> the concrete type being built.
*/
protected static class Builder<T extends UIOption<T>, S extends Builder<T, S>> {
/** set of additional UI specific options */
private final List<Option> uiOptions;
/**
* Map of option to overridden default value. Generally applies to supported RAT options but may be
* UI-specific options as well.
*/
private final Map <Option, String> defaultValues;
/** The list of unsupported RAT options. */
protected final List<Option> unsupportedRatOptions;
/** The function to convert an option into a UIOption. */
private final BiFunction<UIOptionCollection<T>, Option, T> mapper;
/**
* Constructor for the builder.
*/
protected Builder(final BiFunction<UIOptionCollection<T>, Option, T> mapper) {
this.mapper = mapper;
uiOptions = new ArrayList<>();
defaultValues = new HashMap<>();
unsupportedRatOptions = new ArrayList<>();
defaultValue(Arg.LOG_LEVEL, Log.Level.WARN.name());
defaultValue(Arg.OUTPUT_ARCHIVE, Defaults.ARCHIVE_PROCESSING.name());
defaultValue(Arg.OUTPUT_STANDARD, Defaults.STANDARD_PROCESSING.name());
defaultValue(Arg.OUTPUT_LICENSES, Defaults.LIST_LICENSES.name());
defaultValue(Arg.OUTPUT_FAMILIES, Defaults.LIST_FAMILIES.name());
}
/**
* Build the UIOptionCollection.
* @return the UIOptionCollection.
*/
public UIOptionCollection<T> build() {
return new UIOptionCollection<>(this);
}
/**
* Returns this cast to {@code <S>} class.
* @return this as {@code <S>} class.
*/
protected final S self() {
return (S) this;
}
/**
* Add a UI option to the collection.
* @param uiOption the UI Option to add.
* @return this
*/
public S uiOption(final Option uiOption) {
uiOptions.add(uiOption);
return self();
}
/**
* Add a UI options to the collection.
* @param uiOption the UIOptions ({@code <T>} objects) to add.
* @return this
*/
public S uiOptions(final Option... uiOption) {
uiOptions.addAll(Arrays.asList(uiOption));
return self();
}
/**
* Register an option as unsupported.
* @param option the option that is not be supported. This should be an option in the
* {@link Arg} collection.
* @return this
*/
public S unsupported(final Option option) {
unsupportedRatOptions.add(option);
return self();
}
/**
* Register multiple options as unsupported.
* Will ignore all the options associated with the specified Arg.
* @param arg The Arg to ignore.
* @return this
*/
public S unsupported(final Arg arg) {
unsupportedRatOptions.addAll(arg.group().getOptions());
return self();
}
/**
* Specify the default values for an option.
* @param option the option to specify the default value for.
* @param value the value for the option.
* @return this
*/
public S defaultValue(final Option option, final String value) {
defaultValues.put(option, value);
return self();
}
/**
* Specify the default values for an Arg.
* @param arg the Arg to specify the default value for.
* @param value the value for the option.
* @return this
*/
public S defaultValue(final Arg arg, final String value) {
return defaultValue(arg.option(), value);
}
}
}